我也为此苦苦挣扎。关键是 matplotlib 在实际绘制文本之前不会确定文本的大小。因此,您需要显式调用plt.draw()
,然后调整边界,然后再次绘制。
根据文档,该get_window_extent
方法应该以显示坐标而不是数据坐标给出答案。但是,如果尚未绘制画布,它似乎会响应您在关键字参数中指定的任何坐标系。这就是为什么上面的代码可以使用,但不能使用的原因。textcoords
annotate
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)
array([ 12. , -5. , 42.84375, 5. ])
我们想要更改限制,使文本标签位于轴内。given的值bbox
没有多大帮助:因为它是相对于标记点的点数:在 x 中偏移 12 个点,一个字符串显然将超过 30 点长,采用 10 点字体(-5 到 5 英寸) y)。弄清楚如何从那里到达一组新的轴边界并非易事。
然而,如果我们在绘制之后再次调用该方法,我们会得到一个完全不同的 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()
请注意,在绘图绘制一次后不再需要显式传递plt.gcf().canvas.get_renderer()
给。get_window_extent
另外,我直接使用update_datalim
而不是直接使用xlim
,ylim
以便自动缩放可以自动将自身调整为整数。
我在这里以笔记本格式发布了这个答案。