Tight_layout()不会考虑figure suptitle

如果我向matplotlib图添加一个副标题,它会被副图的标题覆盖。有人知道怎么简单地处理吗?我尝试了tight_layout()函数,但它只会让事情变得更糟。

例子:

import numpy as np
import matplotlib.pyplot as plt


f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.tight_layout()
plt.show()
179401 次浏览

你可以使用plt.subplots_adjust(top=0.85)手动调整间距:

import numpy as np
import matplotlib.pyplot as plt


f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.subplots_adjust(top=0.85)
plt.show()

你可以在你的代码中很容易地改变的一件事是你用于标题的fontsize。然而,我假设你并不想这么做!

一些使用fig.subplots_adjust(top=0.85)的替代方法:

通常tight_layout()在将所有内容定位在合适的位置上做得很好,这样它们就不会重叠。在这种情况下,tight_layout()没有帮助的原因是因为tight_layout()不考虑fig.suptitle()。在GitHub上有一个公开的问题:https://github.com/matplotlib/matplotlib/issues/829[由于需要一个完整的几何管理器而在2014年关闭-转移到https://github.com/matplotlib/matplotlib/issues/1109]。

如果你读了这个线程,你的问题就有一个涉及GridSpec的解决方案。关键是在使用rect kwarg调用tight_layout时,在图的顶部留下一些空间。对于您的问题,代码变成:

使用GridSpec

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec


f = np.random.random(100)
g = np.random.random(100)


fig = plt.figure(1)
gs1 = gridspec.GridSpec(1, 2)
ax_list = [fig.add_subplot(ss) for ss in gs1]


ax_list[0].plot(f)
ax_list[0].set_title('Very Long Title 1', fontsize=20)


ax_list[1].plot(g)
ax_list[1].set_title('Very Long Title 2', fontsize=20)


fig.suptitle('Long Suptitle', fontsize=24)


gs1.tight_layout(fig, rect=[0, 0.03, 1, 0.95])


plt.show()

结果:

using gridspec

也许GridSpec对你来说有点过度,或者你的真正问题将涉及更多的子情节在一个更大的画布上,或其他复杂的情况。一个简单的破解方法是使用annotate()并将坐标锁定到'figure fraction'来模拟suptitle。但是,在查看输出之后,您可能需要进行一些更精细的调整。注意,第二个解决方案使用tight_layout()

简单的解决方案(虽然可能需要微调)

fig = plt.figure(2)


ax1 = plt.subplot(121)
ax1.plot(f)
ax1.set_title('Very Long Title 1', fontsize=20)


ax2 = plt.subplot(122)
ax2.plot(g)
ax2.set_title('Very Long Title 2', fontsize=20)


# fig.suptitle('Long Suptitle', fontsize=24)
# Instead, do a hack by annotating the first axes with the desired
# string and set the positioning to 'figure fraction'.
fig.get_axes()[0].annotate('Long Suptitle', (0.5, 0.95),
xycoords='figure fraction', ha='center',
fontsize=24
)
plt.show()

结果:

simple

[使用Python 2.7.3(64位)和matplotlib 1.2.0]

我一直在努力使用matplotlib修剪方法,所以我现在只做了一个函数,通过bash调用ImageMagickmogrify命令来做到这一点,这工作得很好,并从图形的边缘获得所有额外的空白。这要求你正在使用UNIX/Linux,正在使用bash shell,并且已经安装了ImageMagick

只需在savefig()调用之后对this抛出一个调用。

def autocrop_img(filename):
'''Call ImageMagick mogrify from bash to autocrop image'''
import subprocess
import os


cwd, img_name = os.path.split(filename)


bashcmd = 'mogrify -trim %s' % img_name
process = subprocess.Popen(bashcmd.split(), stdout=subprocess.PIPE, cwd=cwd)

另一种简单的解决方案是使用suptitle调用中的y参数来调整图中suptitle文本的坐标(参见文档):

import numpy as np
import matplotlib.pyplot as plt


f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', y=1.05, fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.show()

你可以在tight_layout调用中调整subplot几何形状,如下所示:

fig.tight_layout(rect=[0, 0.03, 1, 0.95])

正如文档(https://matplotlib.org/users/tight_layout_guide.html)中所述:

tight_layout()只考虑tick标签、轴标签和标题。因此,其他艺术家可能会被删减,也可能会重叠。

当我在jupyter笔记本上使用tight_layout来处理一个非常大的网格图(超过200个子图)并渲染时,我遇到了类似的问题。我做了一个快速的解决方案,总是把你的suptitle放在你的顶部subplot上方的一定距离:

import matplotlib.pyplot as plt


n_rows = 50
n_col = 4
fig, axs = plt.subplots(n_rows, n_cols)


#make plots ...


# define y position of suptitle to be ~20% of a row above the top row
y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2
fig.suptitle('My Sup Title', y=y_title_pos)

对于可变大小的子图,您仍然可以使用此方法获得最上面的子图的顶部,然后手动定义一个额外的量添加到suptitle。

正如其他人提到的,默认情况下紧凑的布局不考虑suptitle。然而,我发现可以使用bbox_extra_artists参数来传递suptitle作为应该考虑的边界框:

st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')

这迫使紧凑的布局计算将suptitle考虑在内,它看起来就像你期望的那样。

紧凑的布局不适用于suptitle,但constrained_layout可以。请看这个问题在matplotlib中使用许多子图来改进子图的大小/间距

我发现立即添加子情节看起来更好。

fig, axs = plt.subplots(rows, cols, constrained_layout=True)


# then iterating over the axes to fill in the plots

但也可以在图形创建时添加:

fig = plt.figure(constrained_layout=True)


ax1 = fig.add_subplot(cols, rows, 1)
# etc

注意:为了使我的次要情节更接近,我还使用了

fig.subplots_adjust(wspace=0.05)

和constrained_layout不工作:(

唯一对我有用的是修改对suptitle的调用:

fig.suptitle("title", y=.995)

这个网站有一个简单的解决方案,用一个例子,为我工作。为标题实际留出空间的代码行如下:

plt.tight_layout(rect=[0, 0, 1, 0.95])
下面是一张证明它对我有效的图片: 图片链接 < / p >

v3.3开始,tight_layout现在支持suptitle:

import matplotlib.pyplot as plt


fig, axs = plt.subplots(1, 3)
for i, ax in enumerate(axs):
ax.plot([1, 2, 3])
ax.set_title(f'Axes {i}')


fig.suptitle('suptitle')
fig.tight_layout()

enter image description here