10

有谁知道扩展绘图区域以包含注释的简单方法?我有一个图,其中一些标签是长字符串和/或多行字符串,而不是将这些标签剪裁到轴上,我想扩展轴以包含注释。

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)
4

3 回答 3

10

我也为此苦苦挣扎。关键是 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)

带有注释的绘图

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而不是直接使用xlimylim以便自动缩放可以自动将自身调整为整数。

我在这里以笔记本格式发布了这个答案。

于 2015-09-17T18:29:29.107 回答
2

对我来说tight_layout通常可以解决问题,但在某些情况下,我不得不使用subplots_adjust的“手动”调整,如下所示:

fig = plt.figure()
fig.subplots_adjust(bottom=0.2, top=0.12, left=0.12, right=0.1)

这些数字通常不会发生显着变化,因此您可以修复它们,而不是尝试根据实际绘图进行计算。

顺便说一句,像您在示例中所做的那样设置 xlim 只会更改您绘制的数据范围,而不是所有标签周围的白色区域。

于 2012-07-24T14:26:17.287 回答
1

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

于 2012-07-19T09:01:06.970 回答