Matplotlib tight_layout()没有考虑数字suptitle

kat*_*ikj 160 python matplotlib

如果我在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()
Run Code Online (Sandbox Code Playgroud)

sou*_*ult 138

您可以在tight_layout调用中调整子图几何体,如下所示:

fig.tight_layout(rect=[0, 0.03, 1, 0.95])
Run Code Online (Sandbox Code Playgroud)

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

tight_layout()仅考虑ticklabels,轴标签和标题.因此,其他艺术家可能被剪裁并且也可能重叠.

PS社区建议我发表我的评论作为答案.

  • 你能解释一下rect中每个数字的含义吗?我没有在文档中看到它们。 (5认同)
  • @steven参见`tight_layout`文档:`[左,下,右,上]在标准化(0,1)图形坐标中` (5认同)
  • 您可以通过降低最右边的值来增加副标题和轴之间的间距:`tight_layout(rect=[0, 0.03, 1, 0.9])`而不是答案中的`0.95`。 (4认同)
  • 在 jupyter 内部不起作用。尝试了不同的数字值,没有效果 (4认同)
  • 它的工作原理就像魅力一样,但是指定边界框时如何发生变化?我读了文档,但我不太清楚。如果您能向我解释一下,那就太好了!谢谢。 (2认同)

unu*_*tbu 108

您可以使用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()
Run Code Online (Sandbox Code Playgroud)

  • 我无法相信我们的主人2017年这仍然是matplotlib的一个错误. (60认同)
  • 请注意,在调用`tight_layout`之后*必须调用`subplots_adjust`,否则调用`subplots_adjust`将不起作用. (21认同)
  • 2020 年了,这仍然是一个问题 (9认同)
  • 2021年依然强劲 (7认同)
  • @wordsforthewise现在制作2018年 (6认同)
  • 请注意,当您调用`subplots_adjust`时,top的默认值为0.9 (4认同)
  • 不管有没有 bug,放置标题应该更简单。 (3认同)
  • @vlsd你好从2019 (2认同)

ase*_*ram 50

您可以非常轻松地更改代码中的一件事是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.关键是在tight_layout使用rectkwarg 调用时在图的顶部留出一些空间.对于您的问题,代码变为:

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

结果:

使用gridspec

GridSpec对你来说可能有点矫枉过正,或者你真正的问题会在更大的画布或其他并发症上涉及更多的子图.一个简单的黑客就是使用annotate()并锁定坐标'figure fraction'以模仿a 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()
Run Code Online (Sandbox Code Playgroud)

结果:

简单

[使用Python2.7.3(64位)和matplotlib1.2.0]

  • 铸造`fig.tight_layout(rect = [0,0.03,1,0.95])`也有效. (10认同)

Pug*_*gie 18

另一种易于使用的解决方案是使用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()
Run Code Online (Sandbox Code Playgroud)

  • 这是笔记本中的一种很好的方法,但是plt.savefig()命令不服从.此解决方案仍然在savefig命令中切断标题. (7认同)

小智 17

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

我发现立即添加子图看起来更好,即

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

# then iterating over the axes to fill in the plots
Run Code Online (Sandbox Code Playgroud)

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

fig = plt.figure(constrained_layout=True)

ax1 = fig.add_subplot(cols, rows, 1)
# etc
Run Code Online (Sandbox Code Playgroud)

注意:为了使我的子图更接近,我还使用了

fig.subplots_adjust(wspace=0.05)
Run Code Online (Sandbox Code Playgroud)

并且受约束的布局不适用于此:(


Her*_*aaf 6

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

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

这迫使紧凑的布局计算将 考虑suptitle在内,它看起来如您所愿。


woo*_*uwu 6

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

plt.tight_layout(rect=[0, 0, 1, 0.95]) 
Run Code Online (Sandbox Code Playgroud)

这是它对我有用的证明图片: 图片链接


uke*_*emi 6

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

在此输入图像描述