matplotlib自动缩放轴包含注释

Tan*_*ngo 5 python axes matplotlib

有没有人知道扩大绘图区域以包含注释的简单方法?我有一个图形,其中一些标签是长和/或多线字符串,而不是将它们剪切到轴,我想扩展轴以包括注释.

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)
Run Code Online (Sandbox Code Playgroud)

小智 9

我也为此苦苦挣扎。关键是 matplotlib 在实际绘制之前不会确定文本的大小。所以你需要显式调用plt.draw(),然后调整你的边界,然后再次绘制它。

根据文档get_window_extent,该方法应该在显示坐标中给出答案,而不是数据坐标。但是如果画布还没有被绘制,它似乎会响应你在关键字参数中指定的任何坐标系。这就是为什么您上面的代码可以使用,而不是.textcoordsannotatetextcoords='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)
Run Code Online (Sandbox Code Playgroud)

注释被剪掉的图

array([ 12.     ,  -5.     ,  42.84375,   5.     ])
Run Code Online (Sandbox Code Playgroud)

我们想要更改限制,以便文本标签位于轴内。bbox给定的值没有太大帮助:因为它是相对于标记点的点数:在 x 中偏移 12 点,一个字符串显然会长 30 点多一点,10 点字体(-5 到 5 英寸) y)。弄清楚如何从那里到达一组新的轴边界是很重要的。

但是,如果我们在绘制它之后再次调用该方法,我们会得到一个完全不同的 bbox:

bbox = label.get_window_extent(plt.gcf().canvas.get_renderer())
print(bbox.extents)
Run Code Online (Sandbox Code Playgroud)

现在我们得到

array([ 578.36666667,  216.66666667,  609.21041667,  226.66666667])
Run Code Online (Sandbox Code Playgroud)

这是在显示坐标中,我们可以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()
Run Code Online (Sandbox Code Playgroud)

固定情节

请注意,在绘制一次绘图后不再需要显式传递plt.gcf().canvas.get_renderer()get_window_extent。此外,我使用的是update_datalim代替xlimylim直接,以便自动缩放可以自动将自身调整为整数。

我贴在笔记本格式这个答案在这里


ims*_*msc 1

matplotlib1.1介绍tight_layout了解决一些布局问题的方法。这里有一个很好的教程。

  • 不幸的是,据我所知,tight_layout 也没有获取注释。 (3认同)