如果我向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()

当前回答

另一种简单的解决方案是在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()

其他回答

从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()

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

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

下面是一张证明它对我有效的图片:

在代码中可以很容易地更改标题的字体大小。然而,我假设你并不想这么做!

使用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()

结果:

也许GridSpec对你来说有点过头了,或者你的真正问题将涉及更大画布上的更多子情节,或其他复杂情况。一个简单的破解方法是使用annotation()并将坐标锁定为“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()

结果:

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

你可以使用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()

我有一个类似的问题,当使用tight_layout一个非常大的网格的情节(超过200个子情节),并在一个jupyter笔记本渲染。我做了一个快速的解决方案,总是把你的副标题放在你的顶部副标题上方的一定距离:

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。