なぜだか知らないがmatplotlibバージョン3.2.1時点ではfig.tight_layout()したときにfig.suptitle()で付与した上部のタイトルテキストが考慮されずに残念なことになってしまう。

suptitle+tight_layout

matplotlibのtight_layout()でfig.suptitleが考慮されない例

こんな感じ。こういう風になってしまったら

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

のようにしてrectで範囲を指定する。順番が左下原点で(left,bottom,right,top)なので面食らってしまわないように。topを96%に縮小したければ最後に0.96を入れる。デフォルトは(0,0,1,1)とのこと。

matplotlibのtight_layout()でrectを指定してsuptitleを考慮

このように上側を96%のとこ辺りにすると丁度よくなる。ただしあくまで全体に対するサイズの比率なのでこれより縦長だともっと隙間が空く。

matplotlibのtight_layout()でrectを指定してsuptitleを考慮の説明

内訳はこのこのような感じになっている。少しsuptitleにも被っているがデフォルトでpad=1.08とパディングが指定されているので結果かさならない。padの単位はテキストサイズに対する比率とのこと。

小ワザ

figsize=(6.4, 4.8/0.96)

で描画領域の高さを0.96で割っておくとプロットエリアのサイズを一切変えないままsuptitleが入るスペースを確保できる。

おまけ

図を作ったPythonコードを置いておく。

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1,2,figsize=(8,4.8))

x = np.linspace(-2*np.pi, 2*np.pi, 100)

ax[0].set_title('expansion of $\sin x$')
ax[1].set_title('expansion of $\cos x$')
ax[0].plot(x, np.sin(x), lw=2)
ax[1].plot(x, np.cos(x), lw=2)

s, c = np.zeros(100), np.zeros(100)
for n in range(5):
    s += x**(2*n+1)*(-1)**n/np.math.factorial(2*n+1)
    c += x**(2*n)*(-1)**n/np.math.factorial(2*n)
    ax[0].plot(x, np.array(s), lw=1, ls='--', label='$n=%d$'%(n+1))
    ax[1].plot(x, np.array(c), lw=1, ls='--', label='$n=%d$'%(n+1))

for a in ax:
    a.set_ylim([-2, +2])
    a.set_xlim([-5, +5])
    a.set_xlabel('$x$')
    a.set_ylabel('$f(x)$')
    a.legend()

t = fig.suptitle('Polynominal expansion of trigonometric function')
#fig.tight_layout()
fig.tight_layout(rect=[0,0,1,0.96])

desc = fig.add_axes([0,0,1,0.96])
desc.xaxis.set_visible(False)
desc.yaxis.set_visible(False)
desc.patch.set_alpha(0.3)
desc.patch.set_color('red')
desc.set_xlim([0,1])
desc.set_ylim([0,1])
desc.text(0.5, 0.03, 'tight_layout(rect=[0,0,1,0.96])', fontsize=16, color='black')

plt.show()
plt.close(fig)