我也曾遇到这个问题。关键是matplotlib直到绘制文本后才能确定文本的大小。因此,您需要显式调用plt.draw()
,然后调整边界,再次绘制。
根据文档,get_window_extent
方法应该以显示坐标而非数据坐标来给出答案。但如果画布尚未绘制,则它似乎会响应您在annotate
的textcoords
关键字参数中指定的任何坐标系统。这就是为什么您上面的代码使用textcoords='data'
可以工作,但不使用'offset points'
的原因。
以下是一个例子:
x = np.linspace(0,360,101)
y = np.sin(np.radians(x))
line, = plt.plot(x, y)
label = plt.annotate('finish', (360,0),
xytext=(12, 0), textcoords='offset points',
ha='left', va='center')
bbox = label.get_window_extent(plt.gcf().canvas.get_renderer())
print(bbox.extents)
![plot with annotation clipped](https://istack.dev59.com/h8HCU.webp)
array([ 12. , -5. , 42.84375, 5. ])
我们希望更改限制,使文本标签在坐标轴内。给定的bbox
值并没有太多帮助:因为它是相对于标记点的点数:在x轴上偏移12个点,一个显然会略长于30个点的字符串,在10号字体中(y轴为-5到5)。从这里到新的轴边界有些难以确定。
然而,如果我们现在再次调用该方法,我们将获得完全不同的bbox:
bbox = label.get_window_extent(plt.gcf().canvas.get_renderer())
print(bbox.extents)
现在我们得到
array([ 578.36666667, 216.66666667, 609.21041667, 226.66666667])
这是显示坐标系,我们可以像平常一样使用ax.transData
进行转换。因此,为了使我们的标签处于限制范围内,我们可以执行以下操作:
x = np.linspace(0,360,101)
y = np.sin(np.radians(x))
line, = plt.plot(x, y)
label = plt.annotate('finish', (360,0),
xytext=(8, 0), textcoords='offset points',
ha='left', va='center')
plt.draw()
bbox = label.get_window_extent()
ax = plt.gca()
bbox_data = bbox.transformed(ax.transData.inverted())
ax.update_datalim(bbox_data.corners())
ax.autoscale_view()
![修改后的图表](https://istack.dev59.com/yC93h.webp)
注意:在绘制图表后,不再需要显式传递plt.gcf().canvas.get_renderer()
给get_window_extent
。此外,我使用update_datalim
而不是直接使用xlim
和ylim
,以便自动将自动缩放调整为一个圆整数。
我在notebook格式中发布了这个答案这里 。
subplots_adjust
调整图形、数据点(和注释)的比例。它不会改变重叠在绘图边缘的文本。 - drevicko