Help us understand the problem. What is going on with this article?

pythonのmatplotlibの使い方をまとめてみた

はじめに

今回はmatplotlibの使い方をまとめていきます。

matplotlibについては多くの人が使い方をまとめているので、特に目新しいことはないかもしれませんがお付き合い頂ければ幸いです。

前回の記事でnumpyとpandasの使い方についてまとめているので、よろしければご確認ください。

pythonのnumpyについてまとめてみた
pythonのpandasの使い方をまとめてみた

今回の記事を書くに当たり、以下の記事がとても参考になりました。

早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話

matplotlibの流儀について

matplotlibには二つの流儀が存在します。

全てのplt.なんとかで済ませるPyplotインターフェースと、figaxを定義した後に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()

オブジェクト指向インターフェースを用いる場合は、以下の階層構造を理解する必要があります。
image.png
このように、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()

image.png

一つの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()

image.png

まだ何もプロットしていないので、以上のような空の箱が生成されています。データの中身をみてみましょう。

print(axes)
print(axes.shape)

image.png

このように、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()

image.png

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()

image.png

複数の線を描画する

同一の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()


rwidthは棒の幅を指定していて、デフォルトでは1になっています。1のとき、横の棒と重なるので今回は0.8を指定して見やすくしています。

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)により、画像を良い感じで保存することができます。

終わりに

今回の記事はここまでになります。

他によく使うような機能を見つけ次第こちらの記事に追記していこうと思います。

ここまでお付き合い頂きありがとうございました。

renesisu727
プログラミングを利用した材料研究を行っているM1の学生です。専門は化学です。自分が作成したものを共有していきます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした