Matplotlib & Seaborn 入門講座 | 08.Pythonを使った複数グラフの作成方法【subplot , subplots】

挨拶

こんにちは。キノコードです。
Matplotlib & Seaborn入門講座の8回目です。
今回は、matplotlibの中のsubplotメソッドを使って、複数のグラフを並べて表示させる方法を学びます。
subplotメソッドを使うことで、可視化する領域を好きなように分割し、複数のグラフを縦や横に並べて表示させることができます。
さらに、同じくmatplotlibの中のgridspecメソッドを使って、グラフの表示比率を変更する方法もご紹介します。
応用的な話になりますが、これを使えるようになれば自由自在にグラフを作成することができます。
復習と実践を通して、ぜひ習得してください。
また、キノコードでは、キノコードを応援するYouTubeのメンバーシップを募集しています。
キノコードは、プログラミングやIT、テクノロジーの知識であったり、その活用を日本中に広めたいと思っています。
キノコードでのYouTubeの活動などを応援してくださる方は、チャンネル登録ボタンの横にある「メンバーになる」をクリックをお願いします。
メンバーシップをはじめた理由などの動画もありますので、そちらもご視聴ください。
概要欄にURLを貼っておきます。
それではレッスンスタートです。

Matplotlib & Seaborn 入門講座 | 08.Pythonを使った複数グラフの作成方法【subplot , subplots】

ライブラリインポート

import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np

まずは、ライブラリをインポートする記述をします。
matplotlibをpltという名前でインポートします。
続いて、notebook上にグラフを表示させるための記述をします。
さらに、numpyもインポートします。
numpyとは、高水準の数学関数があり、多次元配列なども高速に計算することができるライブラリです。
実行します。
インポートが完了しました。

2つのグラフをsubplotで表示

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

まずは、2つのグラフをsubplotで表示させてみましょう。
はじめに、グラフを作成するためのデータを用意します。
今回は、サインとコサインのグラフを表示させていきます。
式の詳細については、ここでは割愛します。
実行します。

plt.plot(x,y_sin)

サインのグラフのみ表示させてみましょう。
実行します。

plt.plot(x,y_cos)

コサインのグラフはこのようになっています。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.plot(x,y_sin)
plt.plot(x,y_cos)

1つのセルの中にこれらの記述を並べて実行してみます。
matplotlibでは、後から記述したものが上書きされて表示されます。
従って、このようにサインの上にコサインが重なった1枚のグラフが表示されます。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.subplot(121)
plt.plot(x, y_sin)

plt.subplot(122)
plt.plot(x, y_cos)

plt.show()

では、サインとコサインのグラフを別々に作成し、2枚のグラフを同時に表示させたい場合はどのようにすれば良いでしょうか。
ここで、matplotlibのsubplotメソッドを使います。
pltドットplotの記述の前の行で、subplot丸括弧を書きます。
3つの数字は左から行数、列数、グラフを配置させる位置を示します。
従って、2つのグラフを横に並べて表示させたい場合は、1行2列なので前2つの数字は1、2です。
今回は、左から数えて1つ目にサインのグラフ、2つ目にコサインのグラフを表示させたいので、サインは121、コサインは122とします。
実行します。
グラフを並べて表示できました。
しかし、軸のラベルが隣のグラフと重なってしまっています。

matplotlib.pyplot.subplots_adjust() グラフ同士の余白を調整

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.subplot(121)
plt.plot(x, y_sin)

plt.subplot(122)
plt.plot(x, y_cos)

plt.subplots_adjust(wspace=0.5)
plt.show()

グラフ同士の余白を調整したい場合は、matplotlibのsubplots_adjustメソッドを使います。
subplots_adjustと書いて丸括弧、グラフ横のスペースを調整するにはwspace(ダブリュースペース)を設定します。
デフォルトでは、0.2です。
数字が大きいほど余白を広げられるので、ここでは0.5としてみます。
実行します。
軸ラベルとグラフの重なりを解消できました。
ここで、お気づきの方もいらっしゃるかもしれませんが、グラフの全体のサイズが常に同じになっています。
そのため、余白をあけるほどデフォルトの表示領域に収まるように表示されてしまうので、グラフが小さくなります。

matploylib.pyplot.figure() 全体のグラフサイズ変更

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,3))

plt.subplot(121)
plt.plot(x, y_sin)

plt.subplot(122)
plt.plot(x, y_cos)
plt.show()

全体のサイズを設定するには、matplotlibのfigureメソッドを使います。
figureメソッドの記述を省略してもオブジェクトは自動的に生成されますが、先ほどのように、常に6:4で表示されてしまいます。
figureと書いた丸括弧の中にfigsizeと記述し、全体のサイズを指定できます。
左の数字は横のサイズ、右の数字は縦のサイズです。
ここでは扱いませんが、figureメソッドの中で、図の解像度や塗りつぶし、枠線をつけることもできます。
ここでは、figsizeを9:3としてみます。
実行します。
全体の大きさを変更できました。
また、全体を大きくしたことで、軸ラベルと隣のグラフの重なりもありません。

グラフタイトル追加

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,3))

plt.subplot(121)
plt.plot(x, y_sin)
plt.title('sin(x)')

plt.subplot(122)
plt.plot(x, y_cos)
plt.title('cos(x)')

plt.show()

それぞれのグラフにタイトルを付けてみましょう。
titleと書いた丸括弧の中で好きな名前をシングルコーテーションでくくります。
それぞれ、サイン(x)、コサイン(x)とします。
実行します。
タイトルが表示されました。

matplotlib.pyplot.suptitle() 全体のグラフタイトル追加

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,3))

plt.subplot(121)
plt.plot(x, y_sin)
plt.title('sin(x)')

plt.subplot(122)
plt.plot(x, y_cos)
plt.title('cos(x)')

plt.suptitle('Graphs',fontsize=18)
plt.show()

グラフ全体に対して1つのタイトルを表示させたい場合はどのようにすればよいでしょうか。
その場合は、matplotlibのsuptitleメソッドを使います。
suptitleと書いて丸括弧、全体のタイトルにしたい名前を記述しシングルコーテーションでくくります。
フォントサイズを少し大きめの18としておきます。
実行します。
グラフ全体にタイトルを付けることができました。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,3))

plt.subplot(121)
plt.plot(x, y_sin)
plt.title('sin(x)')

plt.subplot(122)
plt.plot(x, y_cos)
plt.title('cos(x)')

plt.suptitle('Graphs',fontsize=18)
plt.subplots_adjust(top=0.8)
plt.show()

タイトルとグラフが少し近いので、間に余白を設定しましょう。
先ほどもご紹介したsubplots_adjustをここでも使用します。
丸括弧の中にtopと記述し数値で設定します。
デフォルトでは0.9です。
この数字は余白の広さではなく、グラフの頭の高さの位置を示します。
従って、数字が小さいほど、グラフの頭が下へ下がります。
ここでは0.8としてみます。
実行します。
タイトルとグラフの距離が少しひらきました。

fig保存

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,3))

plt.subplot(121)
plt.plot(x, y_sin)
plt.title('sin(x)')

plt.subplot(122)
plt.plot(x, y_cos)
plt.title('cos(x)')

plt.suptitle('Graphs',fontsize=18)
plt.subplots_adjust(top=0.78)
plt.savefig('01.png')

作成したグラフを保存しましょう。
savefigと記述した丸括弧の中に好きなファイル名をシングルコーテーションでくくります。
今回はpng形式で保存します。
実行します。
グラフを保存できました。

縦方向にグラフを表示

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.subplot(211)
plt.plot(x, y_sin, color='coral')

plt.subplot(212)
plt.plot(x, y_cos, color='darkcyan')
plt.show()

先ほどまではグラフを横に並べましたが、次はグラフを縦に並べて表示させてみましょう。
1行目にサインのグラフ、2行目にコサインのグラフを表示させます。
行数は2、列数は1なので、前2つの数字はどちらも2、1です。
サインのグラフは1つ目に表示させたいので、211、2つ目に表示させるコサインのグラフは212となります。
グラフに色も付けてみましょう。
plot丸括弧の中に、colorという引数を記述し、好きな色を指定します。
今回は、サインのグラフをコーラル、コサインのグラフをダークシアンとしておきます。
実行します。
グラフを縦に並べて表示できました。

グラフサイズ変更

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,4))
plt.subplot(211)
plt.plot(x, y_sin, color='coral')

plt.subplot(212)
plt.plot(x, y_cos, color='darkcyan')

plt.show()

続いて、グラフ全体の大きさを変更しましょう。
figure丸括弧の中に、figsizeと記述します。
ここでは、9対4としてみます。
実行します。
グラフのサイズを変更できました。

グラフタイトル追加

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,4))
plt.subplot(211)
plt.plot(x, y_sin, color='coral')
plt.title('sin')

plt.subplot(212)
plt.plot(x, y_cos, color='darkcyan')
plt.title('cos')

plt.suptitle('graphs',fontsize=18)
plt.show()

続いて、グラフにタイトルを付けてみましょう。
サインとコサインのグラフそれぞれと、全体にタイトルを付けます。
それぞれのグラフには、title丸括弧の中に好きな名前をシングルコーテーションでくくります。
全体のタイトルは、先ほど紹介したsuptitleです。
フォントサイズを18としておきます。
実行します。
グラフにタイトルを追加できました。
しかし、タイトル同士が重なっていたり、下のグラフのタイトルが上の軸と重なってしまっています。

縦の余白広げる

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,4))
plt.subplot(211)
plt.plot(x, y_sin, color='coral')
plt.title('sin')

plt.subplot(212)
plt.plot(x, y_cos, color='darkcyan')
plt.title('cos')

plt.suptitle('graphs',fontsize=18)
plt.subplots_adjust(top=0.85, hspace=0.6)
plt.show()

タイトルの重なりを解消するために、間隔を開ける記述をしましょう。
先ほどご紹介した、subplots_adjustをここでも使用します。
topを指定することで、グラフ全体のタイトルの重なりを解消します。
ここでは0.85とします。
先ほどは、グラフの横のスペースを開けるためにwspace(ダブリュースペース)を使用しました。
ここでは、縦のスペースを広げたいので、hspace(エイチスペース)を使って数値を設定します。
デフォルトでは0.2です。
数字が大きいほど、余白は広がります。
ここでは、0.6とします。
実行します。
間隔が広がり、タイトルが見やすくなりました。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.figure(figsize=(9,4))
plt.subplot(211)
plt.plot(x, y_sin,color='coral',label='sin')
plt.legend()

plt.subplot(212)
plt.plot(x, y_cos,color='darkcyan', label='cos')
plt.legend()

plt.suptitle('graphs',fontsize=18)
plt.subplots_adjust(hspace=0)
plt.show()

また、hspaceを0とすると、このようにグラフ同士の余白がなくなります。
このような時は、グラフそれぞれにタイトルを付けるのではなく、凡例にするとよいでしょう。

Gridspec グラフ表示比率の変更

from matplotlib import gridspec

続いて、縦に並べたグラフの表示比率を変更してみます。
gridspecを使うことで、比率を簡単に変更することができます。
初めに、gridspecをインポートする記述をします。
実行します。
インポートが完了しました。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

fig = plt.figure(figsize=(9,6))
grid = gridspec.GridSpec(nrows=2, ncols=1, height_ratios=[2,1])

ax1 = fig.add_subplot(grid[0])
ax1.plot(x, y_sin)

ax2 = fig.add_subplot(grid[1])
ax2.plot(x, y_cos)

plt.show()

まず、gridという変数に比率の設定の記述を代入します。
丸括弧の中のnrowsは行、ncolsは列を示します。
従って、ここではグラフを縦に並べたいので、nrowsは2、ncolsは1となります。
height_ratiosでは、比率を数値で設定します。
ここでは2対1とします。
つまり、上のサインのグラフの方が2倍大きく表示されるはずです。
続いて、設定した比率に対してグラフを配置するために、サインのグラフをax1、コサインのグラフをax2と区別します。
サインのグラフは0から数えて1つ目の上側に表示させたいので、grid角括弧の中に0を指定します。
コサインのグラフは0から数えて2つ目の下側なので1です。
実行します。
上側のグラフを大きく表示できました。

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

fig = plt.figure(figsize=(9,6))
grid = gridspec.GridSpec(nrows=1, ncols=2, width_ratios=[2,1])

ax1 = fig.add_subplot(grid[0])
ax1.plot(x, y_sin)

ax2 = fig.add_subplot(grid[1])
ax2.plot(x, y_cos)

plt.show()

今度は、グラフを縦ではなく横に並べてみましょう。
nrowsを1、ncolsを2と変更するだけで、グラフが2対1の横並びで表示できます。
実行します。
横並びで表示できました。

3グラフをsubplotで表示

names = ['A','B','C']
value = [10,20,30]

plt.figure(figsize=(9,3))

plt.subplot(131)
plt.bar(names, value)

plt.subplot(132)
plt.plot(names, value)

plt.subplot(133)
plt.scatter(names, value)

plt.suptitle('Three Graphs')
plt.show()

次は、数字を変えて3つのグラフをsubplotで表示させてみましょう。
figsizeを9対3とします。
棒グラフ、線グラフ、散布図の3つのグラフを横に並べて表示させてみます。
行数は1、列数は3なので、前2つの数字は全て1、3です。
3つめの数字は、左から数えたグラフを表示させる順番です。
従って、棒グラフは131、線グラフは132、散布図は133となります。
実行します。
3つのグラフを横並びで表示できました。

配置変更

names = ['A','B','C']
value = [10,20,30]

plt.figure(figsize=(9,3))

plt.subplot(211)
plt.bar(names, value)

plt.subplot(223)
plt.plot(names, value)

plt.subplot(224)
plt.scatter(names, value)

plt.suptitle('Three Graphs', fontsize=16)
plt.show()

続いて、少し複雑な配置にしてみましょう。
上側に棒グラフ、下側に線グラフと散布図を横に並べる配置にしてみます。
まず、棒グラフから見た時の行数は2、列数は1、上から数えて1つ目のグラフなので、211となります。
次に、線グラフから見ると行数は2、列数も2となります。
散布図も同様です。
さらに、上側の棒グラフを2つ分のグラフとすると、線グラフは3つ目、散布図は4つ目のグラフになります。
従って、線グラフは223、散布図は224となります。
実行します。
グラフの配置を変更できました。

全体の縦幅広げる

names = ['A','B','C']
value = [10,20,30]

plt.figure(figsize=(9,6))

plt.subplot(211)
plt.bar(names, value)

plt.subplot(223)
plt.plot(names, value)

plt.subplot(224)
plt.scatter(names, value)

plt.suptitle('Three Graphs', fontsize=16)
plt.show()

縦幅が少し狭いので、グラフ全体のサイズを変更しましょう。
figsizeを9対6としてみます。
実行します。
サイズを変更できました。

配置変更

names = ['A','B','C']
value = [10,20,30]

plt.figure(figsize=(9,6))

plt.subplot(121)
plt.plot(names, value)

plt.subplot(222)
plt.scatter(names, value)

plt.subplot(224)
plt.bar(names, value)

plt.suptitle('Three Graphs', fontsize=16)
plt.show()

さらにグラフの配置を変更してみましょう。
左側に線グラフ、右側に散布図と棒グラフを縦に並べる配置にしてみます。
まず、左側に配置させたい線グラフから見て、行数は1、列数は2、1つ目のグラフなので1です。
ちなみに、グラフの順番は左上にあるグラフがデフォルトでは1となります。
従って、121となります。
続いて、散布図と棒グラフからみた行数と列数は2です。
散布図は、2つ目の位置に配置したいので222、そして棒グラフは、線グラフをグラフ2つ分とすると4つ目の位置なので224となります。
実行します。
グラフの配置を変更できました。

4グラフをsubplotで表示

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

plt.subplot(221)
plt.plot(x, y_sin)

plt.subplot(222)
plt.plot(x, y_cos)

plt.subplot(223)
plt.plot(x, y_sin)

plt.subplot(224)
plt.plot(x, y_cos)
plt.show()

さらに、グラフの数を増やしてみましょう。
4つのグラフをsubplotで表示させてみます。
これまでに紹介したように、全てpltドットsubplotでグラフの位置を指定してもよいのですが、このようにグラフの数が多くなってくると、スクリプトが少しわかりづらいです。

plt→ax

x = np.linspace(-np.pi, np.pi, 201)

y_sin = np.sin(x)
y_cos = np.cos(x)

fig = plt.figure(figsize=(9,6))

ax1 = fig.add_subplot(221)
ax1.plot(x, y_sin)

ax2 = fig.add_subplot(222)
ax2.plot(x, y_cos)

ax3 = fig.add_subplot(223)
ax3.plot(x, y_sin)

ax4 = fig.add_subplot(224)
ax4.plot(x, y_cos)

plt.show()

そこで、軸を意味するAxisの省略名axの1から4にグラフを代入する記述をします。
また、addアンダースコアsubplotを実行することで、Axisオブジェクトが生成されます。
これにより、それぞれのグラフにアクセスし、軸ラベルや目盛りの設定がしやすくなるといったメリットがあります。
また、Axisオブジェクトを生成するための土台として、pltドットfigureを記述し、figureオブジェクトを生成します。
figureオブジェクトの中ではグラフ全体の大きさを変更することもできます。
今回は9対6とします。
まず、左上のグラフをax1とすると、行数は2、列数も2なので、221となります。
他の数字も同じ容量で記述します。
また、生成したそれぞれのAxisオブジェクトにグラフの設定を追加していくことがわかりやすいように、pltの部分をaxドットplotの形で記述します。
実行します。
4つのグラフを表示できました。

subplots

fig, ax = plt.subplots(nrows=2,ncols=2,figsize=(9,6))   

ax[0,0].plot(x, y_sin)
ax[0,1].plot(x, y_cos)
ax[1,0].plot(x, y_sin)
ax[1,1].plot(x, y_cos)

plt.show()

また、matplotlibのsubplotsメソッドで、figureオブジェクトとAxisオブジェクトをまとめて生成し、スクリプトをよりスッキリさせることができます。
figとaxをカンマでつなげて記述しイコール、subplotsの丸括弧の中で行数と列数の指定をします。
nrowsが行、ncolsが列です。
従って、ここではnrowsイコール2、ncolsイコール2とします。
同時にfigsizeも記述しておきます。
9対6とします。
続いて、ax角括弧の中で生成されたそれぞれのグラフのAxisにアクセスする記述をします。
一つ目の数字が行番号、2つ目が列番号です。
実行します。
同じように作成できました。

fig, ax = plt.subplots(2,2,figsize=(9,6))  

ax[0,0].plot(x, y_sin)
ax[0,1].plot(x, y_cos)
ax[1,0].plot(x, y_sin)
ax[1,1].plot(x, y_cos)

plt.show()

また、nrows、ncolsを省略してこのように記述することもできます。

縦に並べて表示

fig, ax = plt.subplots(4,1,figsize=(9,6))   

ax[0].plot(x, y_sin)
ax[1].plot(x, y_cos)
ax[2].plot(x, y_sin)
ax[3].plot(x, y_cos)

plt.show()

さらに、グラフを縦に4つ並べる記述をしてみましょう。
行数は4、列数は1なので、subplots丸括弧の中の記述は4、1です。
縦にグラフを並べる場合は、このような0から数えた単数字でアクセスします。
実行します。
グラフが縦に並びました。

軸の共有

fig, ax = plt.subplots(2,2,figsize=(9,6), sharex=True, sharey=True)   

ax[0,0].plot(x, y_sin)
ax[0,1].plot(x, y_cos)
ax[1,0].plot(x, y_sin)
ax[1,1].plot(x, y_cos)

plt.show()

また、subplotsメソッドの丸括弧の中で、軸の共有の指定もできます。
shareエックス、shareワイ、イコールTrueとすることで、グラフの間の軸ラベルを削除することができます。
実行します。
軸ラベルが外側のみになりました。

グラフタイトル追加

fig, ax = plt.subplots(2,2, figsize=(9,6), sharex=True, sharey=True)   

ax[0,0].plot(x, y_sin)
ax[0,0].set(title='sin')

ax[0,1].plot(x, y_cos)
ax[0,1].set(title='cos')

ax[1,0].plot(x, y_sin)
ax[1,1].plot(x, y_cos)

plt.suptitle('sin & cos Graphs', fontsize=18)
plt.show()

最後にグラフのタイトルを追加してみましょう。
上2つのグラフと全体の3カ所にタイトルをつけてみます。
タイトルを付けたいaxにsetと記述し丸括弧、titleという引数を記述し、好きな名前をシングルコーテーションでくくります。
グラフ全体のタイトルは先ほど紹介したsuptitleで記述します。
実行します。
グラフにタイトルを追加できました。

挨拶

キノコードではmatplotlibやSeabornのレッスンだけではなく、仕事の自動化のレッスン、人工知能のレッスンなども配信しています。
キノコードの新着動画はチャンネル登録をしていただければ、通知が届きますので、ぜひチャンネル登録をお願いします。
それでは、次のレッスンでお会いしましょう。

レッスンで使ったファイルはこちら

■保存方法
Mac:右クリック⇒「リンク先を別名で保存」
Windows:右クリック⇒「名前を付けてリンク先を保存」
Jupyter Labのファイルはこちら