有谁知道扩展绘图区域以包含注释的简单方法?我有一个图形,其中一些标签是长字符串和/或多行字符串,我想扩展轴以包含注释,而不是将它们剪切到轴上。
Autoscale_view 不这样做,并且 ax.relim 不拾取注释的位置,因此这似乎不是一个选项。
我尝试执行类似下面的代码的操作,该代码循环遍历所有注释(假设它们位于数据坐标中)以获取其范围,然后相应地更新轴,但理想情况下我不希望我的注释位于数据坐标中(它们与实际数据点有偏移)。
xmin, xmax = plt.xlim()
ymin, ymax = plt.ylim()
# expand figure to include labels
for l in my_labels:
# get box surrounding text, in data coordinates
bbox = l.get_window_extent(renderer=plt.gcf().canvas.get_renderer())
l_xmin, l_ymin, l_xmax, l_ymax = bbox.extents
xmin = min(xmin, l_xmin); xmax = max(xmax, l_xmax); ymin = min(ymin, l_ymin); ymax = max(ymax, l_ymax)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
我也为此苦苦挣扎。关键是 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. ])
我们想要更改限制,使文本标签位于轴内。给出的
bbox
值没有多大帮助:因为它是相对于标记点的点:在 x 中偏移 12 点,一个字符串显然会超过 30 点长,采用 10 点字体(-5到 y 中的 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()
请注意,在绘制一次绘图后,不再需要显式地将
plt.gcf().canvas.get_renderer()
传递给 get_window_extent
。另外,我直接使用 update_datalim
而不是 xlim
和 ylim
,这样自动缩放就可以自动将其自身调整为整数。
我以笔记本格式发布了这个答案这里。
对我来说
tight_layout
通常可以解决问题,但在某些情况下我必须使用subplots_adjust进行“手动”调整,如下所示:
fig = plt.figure()
fig.subplots_adjust(bottom=0.2, top=0.12, left=0.12, right=0.1)
这些数字通常不会发生巨大变化,因此您可以修复它们,而不是尝试根据实际绘图进行计算。
顺便说一句,像在示例中那样设置 xlim 仅更改您绘制的数据范围,而不更改所有标签周围的白色区域。
matplotlib 不将注释/文本视为数据。所以默认的
autoscale
无法正常工作。我的快速解决方案可以手动设置边距。
ax.margin(0.2)
可以增加注释的边距空间。