はじめに
今回はmatplotlibの使い方をまとめていきます。
matplotlibについては多くの人が使い方をまとめているので、特に目新しいことはないかもしれませんがお付き合い頂ければ幸いです。
前回の記事でnumpyとpandasの使い方についてまとめているので、よろしければご確認ください。
pythonのnumpyについてまとめてみた
pythonのpandasの使い方をまとめてみた
今回の記事を書くに当たり、以下の記事がとても参考になりました。
早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話
matplotlibの流儀について
matplotlibには二つの流儀が存在します。
全てのplt.なんとか
で済ませるPyplotインターフェースと、fig
やax
を定義した後にax.plot
で書くオブジェクト指向インターフェースです。
実際に具体例を見ていきましょう。
Pyplotインターフェース
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, 100)
y = x ** 2
plt.plot(x, y)
plt.show()
オブジェクト指向インターフェース
x = np.linspace(0, 1, 100)
y = x ** 2
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)
plt.show()
オブジェクト指向インターフェースを用いる場合は、以下の階層構造を理解する必要があります。
このように、figureオブジェクト
の中にAxesオブジェクト
が存在する階層構造になっていることが分かります。つまり、上のコードはfig = plt.figure()
でfigureオブジェクトを生成し、ax = fig.add_subplot(111)
でaxesオブジェクトを生成しています。
イメージとしては、figureオブジェクトがブラウザのwindowのようなもので、axesオブジェクトがブラウザのタブのようなものだと覚えていてください。
複数のグラフを描画する
複数のグラフを描画するときは以下のようにします。
x_1 = np.linspace(0, 1, 100)
y_1 = x_1
x_2 = np.linspace(0, 1, 100)
y_2 = x_2 ** 2
x_3 = np.linspace(0, 1, 100)
y_3 = x_3 ** 3
x_4 = np.linspace(0, 1, 100)
y_4 = x_4 ** 4
fig = plt.figure()
ax_1 = fig.add_subplot(221)
ax_2 = fig.add_subplot(222)
ax_3 = fig.add_subplot(223)
ax_4 = fig.add_subplot(224)
ax_1.plot(x_1, y_1)
ax_2.plot(x_2, y_2)
ax_3.plot(x_3, y_3)
ax_4.plot(x_4, y_4)
plt.show()
一つのfigureオブジェクトの中に4つのaxisオブジェクトを生成しています。
add_subplot()
の引数は(行, 列, 何番目か)
となっており、上の例では2行2列のデータを生成し、順番にaxesオブジェクトを生成しています。
グラフの大きさの調整
figureオブジェクトを生成するときに、引数にfigsizeを渡すことでグラフのサイズを調整することができます。
x = np.linspace(0, 1, 100)
y = x ** 2
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
ax.plot(x, y)
plt.show()
#figureとaxオブジェクトを同時に生成
今まではfigureオブジェクトを生成してからそれに属するaxオブジェクトを生成していましたが、以下のようにfigureオブジェクトとaxオブジェクトを同時に生成することができます。
fig, axes = plt.subplots(2, 2, figsize=(20, 12))
plt.show()
まだ何もプロットしていないので、以上のような空の箱が生成されています。データの中身をみてみましょう。
print(axes)
print(axes.shape)
このように、axesオブジェクトは2×2のデータが格納されています。その一つ一つが上の四つのグラフに対応しています。
以下のようにすれば、プロットすることができます。
x_1 = np.linspace(0, 1, 100)
y_1 = x_1
x_2 = np.linspace(0, 1, 100)
y_2 = x_2 ** 2
x_3 = np.linspace(0, 1, 100)
y_3 = x_3 ** 3
x_4 = np.linspace(0, 1, 100)
y_4 = x_4 ** 4
fig, axes = plt.subplots(2, 2, figsize=(20, 12))
axes[0][0].plot(x_1, y_1)
axes[0][1].plot(x_2, y_2)
axes[1][0].plot(x_3, y_3)
axes[1][1].plot(x_4, y_4)
plt.show()
axesを1次元配列に変換
axesが二次元のデータになっているので、for文で回しにくいですよね。
ravel()を使って1次元配列に変換することで、for文で回しやすくなります。以下の例を見てください。
fig, axes = plt.subplots(2, 2, figsize=(20, 12))
one_dimension_axes = axes.ravel()
x = np.linspace(0, 1, 100)
for i, ax in enumerate(one_dimension_axes):
ax.plot(x, x ** (i+1))
plt.show()
複数の線を描画する
同一のaxオブジェクトでプロットを行えば複数の線を描画することができます。
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
x_1 = np.linspace(0, 1, 100)
y_1 = x_1
x_2 = np.linspace(0, 1, 100)
y_2 = x_2 ** 2
ax.plot(x_1, y_1)
ax.plot(x_2, y_2)
plt.show()
タイトルや軸、凡例を設定しましょう。
fig = plt.figure()
ax = fig.add_subplot(111)
x_1 = np.linspace(0, 1, 100)
y_1 = x_1
x_2 = np.linspace(0, 1, 100)
y_2 = x_2 ** 2
ax.plot(x_1, y_1, label='y=x')
ax.plot(x_2, y_2, label='$y=x^2$')
ax.set_xlabel('x_value')
ax.set_ylabel('y_value')
plt.legend(loc='best')
plt.show()
plt.xlabel
などを用いてもラベルを作成することができますが、今回はラベルはaxesオブジェクトに属していることを示すためにset_xlabel
を用いてラベルを設定しました。
ラベルはaxesオブジェクトのしたのaxisオブジェクトに格納されています。
axisオブジェクトを作成し、その中のlabel変数を確認しましょう。
xax = ax.xaxis
yax = ax.yaxis
print(xax.label)
print(yax.label)
Text(0.5, 0, 'x_value')
Text(0, 0.5, 'y_value')
線の色・太さ・スタイルを変更
色についてはこちらの記事を参考にしてください。
fig = plt.figure()
ax = fig.add_subplot(111)
x_1 = np.linspace(0, 1, 100)
y_1 = x_1
x_2 = np.linspace(0, 1, 100)
y_2 = x_2 ** 2
ax.plot(x_1, y_1, label='y=x', color='r', linewidth=2, linestyle='solid')
ax.plot(x_2, y_2, label='$y=x^2$', color='g', linewidth=2, linestyle='dashed')
ax.set_xlabel('x_value')
ax.set_ylabel('y_value')
plt.legend(loc='best')
plt.show()
以上のようにax.plot
の引数を指定すれば色やスタイルを変更できます。
左右に二つの軸があるグラフを書く方法
一つ目のプロットは通常の方法で書き、二つ目のプロットはtwinx()を用いて生成したaxを用いてx軸が共通でy軸が異なるグラフを書くことができます。
fig = plt.figure()
ax_1 = fig.add_subplot(111)
ax_2 = ax_1.twinx()
x = np.linspace(0, 5, 100)
y_1 = x
y_2 = x ** 2
ax_1.plot(x, y_1, label='y=x', color='r', linewidth=2, linestyle='solid')
ax_2.plot(x, y_2, label='$y=x^2$', color='g', linewidth=2, linestyle='dashed')
ax_1.set_xlabel('x_value')
ax_1.set_ylabel('y=x')
ax_2.set_ylabel('$y=x^2$')
fig.legend(loc='lower right')
plt.show()
散布図
plotではなくscatterを使用すれば、散布図を生成することができます。
df = pd.DataFrame(data=np.random.randn(200, 2),
columns=['A', 'B'])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(df['A'], df['B'])
plt.show()
点の大きさ・スタイル・色の変更
以下のコードです。
df = pd.DataFrame(data=np.random.randn(200, 2),
columns=['A', 'B'])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(df['A'], df['B'], s=100, c='r', alpha=0.5)
ax.set_xlabel('$x_0$', fontsize=10)
ax.set_ylabel('$x_1$', fontsize=10)
ax.set_title('title')
plt.show()
scatter
内のs
により点の大きさを、c
により色を、alpha
により透明度を設定しています。
点の大きさや色をデータにより変更
以下のコードです。
df = pd.DataFrame(data=np.random.randn(200, 2),
columns=['A', 'B'])
df['data_size'] = np.random.randint(1, 100, 200)
fig = plt.figure()
ax = fig.add_subplot(111)
ax_cmap = ax.scatter(df['A'], df['B'], s=df['data_size']*10, c=df['data_size'], cmap='viridis', alpha=0.5)
fig.colorbar(ax_cmap)
ax.set_xlabel('$x_0$', fontsize=10)
ax.set_ylabel('$x_1$', fontsize=10)
ax.set_title('title')
plt.show()
ax.scatter
のcにdata_sizeを指定し、cmapにviridisを指定しています。viridisはmatplotlibでよく使われるカラーマップです。
カラーマップを作成したmappableオブジェクトを、fig.colorbar
に渡すことにより、右のカラーバーを生成することができます。
棒グラフ
棒グラフを作成します。以下のコードです。
df = pd.DataFrame({'C1': ['A', 'A', 'A', 'B', 'B', 'C'],
'C2': [1, 2, 4, 5, 7, 7],
'C3': [1, 12, 7, 4, 8, 9]})
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar(df['C1'].value_counts().index, df.groupby('C1').sum()['C2'])
plt.show()
df['C1'].value_counts().index
により、C1要素のインデックスであるA,B,Cを受け取っています。
df.groupby('C1')
により、C1要素でグループ化し、sum()で合計を計算し、その中のC2要素を受け取っています。
複数の棒グラフを作成
以下のようにして複数のグラフを生成します。
df = pd.DataFrame(data=100 * np.random.rand(5, 5), index=['A', 'B', 'C', 'D', 'E'],
columns=['C1', 'C2', 'C3', 'C4', 'C5'])
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
x = np.arange(len(df))
bar_width = 0.4
ax.bar(x, df['C1'], color='b', width=bar_width, label='C1')
ax.bar(x + bar_width, df['C2'], color='r', width=bar_width, label='C2')
plt.xticks(x + bar_width/2, df.index, fontsize=20)
plt.legend()
plt.show()
ax.bar
の引数として、最初にxの値、次にyの値、colorに棒の色、widthに幅、labelにラベルを与えます。
xticks
は引数として(x座標, 名前, fontsize=文字の大きさ)を与えました。
ヒストグラム
以下のコードです。
df = pd.DataFrame(data=np.random.randn(200), columns=['A'])
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
ax.hist(df['A'], bins=15, rwidth=0.8, color='b')
plt.show()
bins
により、ヒストグラムの棒の数を調整しています。
ヒートマップ
以下のコードです。
df = pd.DataFrame(data=np.random.rand(5, 5), columns=['A', 'B', 'C', 'D', 'E'])
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
c_ax = ax.pcolor(df, cmap='Blues')
fig.colorbar(c_ax)
plt.show()
pcolor
を用いることでヒートマップを作成することができます。
pcolor
を用いた後の戻り値をfig.colorbar
の引数に渡すことで、カラーバーをつけることができます。
#グラフのスタイルについて
こちらの記事を参考にしました。
x = np.linspace(0, 1, 100)
y = x ** 3
plt.rcParams["font.family"] = "arial" #全体のフォントを設定
plt.rcParams["xtick.direction"] = "in" #x軸の目盛線を内向きへ
plt.rcParams["ytick.direction"] = "in" #y軸の目盛線を内向きへ
plt.rcParams["xtick.minor.visible"] = True #x軸補助目盛りの追加
plt.rcParams["ytick.minor.visible"] = True #y軸補助目盛りの追加
plt.rcParams["xtick.major.width"] = 1.5 #x軸主目盛り線の線幅
plt.rcParams["ytick.major.width"] = 1.5 #y軸主目盛り線の線幅
plt.rcParams["xtick.minor.width"] = 1.0 #x軸補助目盛り線の線幅
plt.rcParams["ytick.minor.width"] = 1.0 #y軸補助目盛り線の線幅
plt.rcParams["xtick.major.size"] = 10 #x軸主目盛り線の長さ
plt.rcParams["ytick.major.size"] = 10 #y軸主目盛り線の長さ
plt.rcParams["xtick.minor.size"] = 5 #x軸補助目盛り線の長さ
plt.rcParams["ytick.minor.size"] = 5 #y軸補助目盛り線の長さ
plt.rcParams["font.size"] = 14 #フォントの大きさ
plt.rcParams["axes.linewidth"] = 1.5 #囲みの太さ
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
ax.plot(x, y)
ax.set_xlabel('X')
ax.set_ylabel('Y')
fig.savefig('test_5.png', bbox_inches="tight", pad_inches=0.05) # 画像を保存
plt.show()
上のように、plt.rcParams
によりグラフ全体の書式設定を行うことができます。また、fig.savefig('test_5.png', bbox_inches="tight", pad_inches=0.05)
により、画像を良い感じで保存することができます。
終わりに
今回の記事はここまでになります。
他によく使うような機能を見つけ次第こちらの記事に追記していこうと思います。
ここまでお付き合い頂きありがとうございました。