はじめに
matplotlibのグラフや画像サイズをいろいろ決めたくなったが、サブプロットした時の状態とかよくわかってなかった。ので調べた。
デフォルトパラメータは
import matplotlib as mpl
print(mpl.rcParams["figure.figsize"])
print(mpl.rcParams["figure.dpi"])
print([mpl.rcParams["figure.subplot." + name]
for name in ["left", "right", "top", "bottom", "wspace", "hspace"]])
[6.0, 4.0]
72.0
[0.125, 0.9, 0.88, 0.125, 0.2, 0.2]
このとき、
AxesSubplotがひとつ
その1
import matplotlib.pyplot as plt
fig = plt.figure(facecolor="skyblue")
ax = fig.add_subplot(111)
print(fig)
print(ax)
fig.savefig("1.png", facecolor="skyblue")
fig.savefig("1_tight.png", facecolor="skyblue", bbox_inches="tight")
jupyterのOut
Figure(432x288)
AxesSubplot(0.125,0.125;0.775x0.755)
(379x252)
1.png
1_tight.png
その2
fig = plt.figure(facecolor="skyblue", linewidth=100, edgecolor="green")
ax = fig.add_subplot(111, ylabel="ylabel")
fig.subplots_adjust(left=0, right=1, bottom=0.2, top=0.8)
print(fig)
print(ax)
fig.savefig("2.png", facecolor="skyblue", edgecolor="orange")
fig.savefig("2_tight.png", facecolor="skyblue", edgecolor="blue", bbox_inches="tight")
JupyterのOut
2.png
2_tight.png
わかったこと
-
Figure.figsize
は「キャンバス」のサイズで、画像出力時は基本的にそのキャンバスが出力範囲となる、しかしキャンバスの外にもオブジェクト配置・描画は可能。と考えたい。 -
figsize
×dpi
のピクセルサイズの画像が出力される。 -
SubplotParams
(Figure.subplots_adjust()
)は、キャンバス左下を(0,0)・右上を(1,1)として、Axes
の位置を決める。上には載せていないが0未満や1以上も指定可能だった。 -
Axes
のエリアはプロットする部分が基準。(デフォルトでは)何もしなくても軸ラベルや目盛りが描画されているがこいつらはAxes
のエリアからはみ出ている。 -
Figure.savefig()
で、bbox_inches="tight"
するとオブジェクトが描画されている場所に合わせて(キャンバスの範囲は無視して)、画像を出力してくれる。 -
Figure
の枠(edgecolor
,linewidth
)は、キャンバスではなく出力画像に対して適用される。 - jupyterのインライン表示では
bbox_inches="tight"
が指定された画像が表示される。
AxesSubplotが複数
その1
fig = plt.figure(facecolor="skyblue")
ax1 = fig.add_subplot(211, xlabel="xlabel")
ax2 = fig.add_subplot(212, xlabel="xlabel")
fig.subplots_adjust(bottom=0, left=0, top=1, right=1)
print(ax1)
print(ax2)
fig.savefig("3.png", facecolor="skyblue")
AxesSubplot(0,0.545455;1x0.454545)
AxesSubplot(0,0;1x0.454545)
3.png
サイズが変な少数になった。計算すると縦は(ax1:余白:ax2)=(5:1:5)の割合で配置されたようだ。
その2
fig = plt.figure(facecolor="skyblue")
ax1 = fig.add_subplot(311, xlabel="xlabel")
ax2 = fig.add_subplot(312, xlabel="xlabel")
ax3 = fig.add_subplot(313, xlabel="xlabel")
fig.subplots_adjust(bottom=0, left=0, top=1, right=1)
print(ax1)
print(ax2)
print(ax3)
fig.savefig("4.png", facecolor="skyblue")
AxesSubplot(0,0.705882;1x0.294118)
AxesSubplot(0,0.352941;1x0.294118)
AxesSubplot(0,0;1x0.294118)
4.png
サイズが変な少数になった。その1から予想して(ax1:余白:ax2:余白:ax3)=(5:1:5:1:5)の割合で配置されたとみる。
$5÷(5+1+5+1+5)=0.2941176...$なので予想通りっぽい。
その3
fig = plt.figure(facecolor="skyblue")
ax1 = fig.add_subplot(211, xlabel="xlabel")
ax2 = fig.add_subplot(212, xlabel="xlabel")
fig.subplots_adjust(bottom=0.25, left=0.25, top=0.75, right=0.75, hspace=2)
print(ax1)
print(ax2)
fig.savefig("5.png", facecolor="skyblue")
AxesSubplot(0.25,0.625;0.5x0.125)
AxesSubplot(0.25,0.25;0.5x0.125)
5.png
わかったこと
-
Axes
が1つの時の範囲(SubplotParams
の上下左右)を基準に分割される。キャンバスのサイズ基準ではない。 - 各縦横は、(1:space:1:space: ... :1)の比で分割される(spaceは
SubplotParams
のhspace
或いはwspace
)。
Tight Layout
その1
fig = plt.figure(facecolor="skyblue", tight_layout=dict(pad=0))
ax1 = fig.add_subplot(131, facecolor="blue")
ax2 = fig.add_subplot(132, facecolor="white")
ax3 = fig.add_subplot(133, facecolor="red")
fig.subplots_adjust(bottom=0, left=0, top=1, right=1, wspace=1)
print(ax1)
print(ax2)
print(ax3)
fig.savefig("6.png", facecolor="skyblue")
AxesSubplot(0,0;0.2x1)
AxesSubplot(0.4,0;0.2x1)
AxesSubplot(0.8,0;0.2x1)
(446x302)
6.png
その2
fig = plt.figure(facecolor="skyblue", tight_layout=dict(pad=0))
ax1 = fig.add_subplot(131, facecolor="blue")
ax2 = fig.add_subplot(132, facecolor="white")
ax3 = fig.add_subplot(133, facecolor="red")
fig.subplots_adjust(bottom=0, left=0, top=1, right=1, wspace=0)
print(ax1)
print(ax2)
print(ax3)
fig.savefig("7.png", facecolor="skyblue")
AxesSubplot(0,0;0.333333x1)
AxesSubplot(0.333333,0;0.333333x1)
AxesSubplot(0.666667,0;0.333333x1)
(446x302)
7.png
インライン表示はその1とその2で同じ結果。出力画像は6.pngに比べて7.pngは各プロットエリアの横幅が小さい(間の余白が広い)。
インライン表示と出力画像の間でもプロットエリアの大きさが異なる。
わからなかった
- キャンバスと各オブジェクトに合わせて、各プロットエリアを拡大縮小しているっぽい。
- その1(6.png)とその2(7.png)の違いは?
bbox_inches="tight"
の有無の違いは? - ちなみに
Figure.subplots_adjust()
とFigure.add_subplot()
を実行する順番は関係なかった。
ほかにもいろいろ試したが、「結果どうなるかよくわからないけど、とりあえずうまく配置してくれる」っていう感想になった。
Constrained Layout
tight_layout以上にわからなかったので略