You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib中线条与文本无法对齐问题求助

Matplotlib旋转文本与线条错位问题

问题描述

尝试通过两点绘制线条,计算线条角度后旋转文本使其与线条匹配,但二者出现错位。代码如下:

import math
import numpy as np
import matplotlib.pyplot as plt

def angle_line(A, B):
    x = B[0] - A[0]
    y = B[1] - A[1]
    angle = math.atan2(y, x )
    return angle*180/np.pi

fig, ax = plt.subplots()
xy_init = (0,0)
xy_end = (1, 0.5)

# 绘制线条
ax.plot((xy_init[0], xy_end[0]), (xy_init[1], xy_end[1]), color='black', linewidth=0.5, linestyle='--')

center = (xy_init[0]+xy_end[0])/2, (xy_init[1]+xy_end[1])/2
angle = angle_line(xy_init, xy_end)

# 绘制文本
ax.text(*center, 'TEST', horizontalalignment='center', rotation = angle,
        verticalalignment='center',fontdict={'fontsize': 20}, color='red')

原因分析

问题出在Matplotlib的rotation参数默认行为:它是基于屏幕坐标系计算旋转角度,而非数据坐标系。当x轴和y轴的像素缩放比例不一致时(比如本例中x轴范围0-1,y轴0-0.5,像素长度不同),你计算的是数据空间里的线条角度,直接传给rotation会导致文本旋转角度与视觉上的线条角度不匹配,从而错位。

解决方法

方法1:启用坐标系旋转适配

修改文本绘制代码,添加rotation_mode='anchor'和transform_rotates_text=True参数,让旋转基于数据坐标系的锚点:

ax.text(*center, 'TEST', horizontalalignment='center', verticalalignment='center',
        fontdict={'fontsize': 20}, color='red',
        rotation=angle, rotation_mode='anchor', transform_rotates_text=True)

方法2:计算屏幕空间真实角度

直接将数据坐标转换为屏幕坐标,计算屏幕空间里的线条角度,确保旋转角度完全匹配视觉线条:

# 转换坐标到屏幕空间
display_center = ax.transData.transform(np.array(center))
display_A = ax.transData.transform(np.array(xy_init))
display_B = ax.transData.transform(np.array(xy_end))
dx = display_B[0] - display_A[0]
dy = display_B[1] - display_A[1]
# 计算屏幕空间角度
screen_angle = np.arctan2(dy, dx) * 180 / np.pi

# 绘制文本
ax.text(*center, 'TEST', horizontalalignment='center', verticalalignment='center',
        fontdict={'fontsize': 20}, color='red',
        rotation=screen_angle, rotation_mode='anchor')

两种方法都能让文本与线条完美对齐,方法1更简洁,方法2适用于坐标轴缩放变化频繁的场景。

内容的提问来源于stack exchange,提问作者Bruno Mello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 09:35:35