はじめに
データ解析とかをしていると、グラフ表現で可視化をすることはよくある。
Pythonではmatplotlibというライブラリを使うが、設定や書式など覚えきれずに度々調べてしまうので、よく使う機能・設定について備忘録的にまとめておく。
なので、「matplotlibとは?」や「pythonの使い方」などについての解説は特にしない。
基本的な描き方
とりあえず描く
一番基本的なプロットをやってみる。
from matplotlib import pyplot as plt
from random import randint
# データの定義(サンプルなのでテキトー)
x = list(range(10))
y = [randint() for _ in x]
# グラフの描画
plt.plot(x, y)
plt.show()
とりあえず描画するだけならば非常にシンプルで、上記サンプルのようにmatplotlib
ライブラリからpyplot
モジュールをインポートし、リスト等で用意したデータをplt.plot()
に渡すだけでよい。
plt.show()
で出力例のようなウィンドウが開いて中にグラフが表示される。(注:サンプルのデータはランダムなのでグラフ自体は異なる)
ちなみにpyplot
モジュールはplt
という名称に置換するのが慣例らしい。
プロットしたいデータが複数ある場合は、plt.plot()
を描画したいデータ分だけ重ねればよい。
from matplotlib import pyplot as plt
from random import randint
# データの定義(サンプルなのでテキトー)
x = list(range(10))
y1 = [randint(0, 100) for _ in x]
y2 = [randint(0, 100) for _ in x]
# グラフの描画
plt.plot(x, y1)
plt.plot(x, y2)
plt.show()
こんな感じに勝手に色分けされて描画される。
複数のグラフを1枚に描く
異なるデータを描画する際、重ねるのではなく別々に描画したいこともある。
from matplotlib import pyplot as plt
from random import randint, random
# データの定義(サンプルなのでテキトー)
x = list(range(10))
y1 = [randint(0, 100) for _ in x]
y2 = [randint(0, 100) for _ in x]
# グラフの描画
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)
ax.plot(x, y1)
ax = fig.add_subplot(2, 1, 2)
ax.plot(x, y2)
plt.show()
少し複雑になった。
最初に、fig = plt.figure()
でグラフのインスタンスを取得し、ax = fig.add_subplot()
でプロットエリアのインスタンスをax
に取得している。ax
に対してplot
を実行することで異なるプロットエリアに描画している。
add_subplot()
に渡す引数は左から、縦のプロットエリア数
,横のプロットエリア数
,割り当てるプロットエリア番号
になっている。プロットエリア番号は左上から横⇒下の順で割りつく。
なので、サンプルのサブプロット部分の指定を下記のようにすると、横並びにもできる。
ax = fig.add_subplot(1, 2, 1)
ax.plot(x, y1)
ax = fig.add_subplot(1, 2, 2)
ax.plot(x, y2)
ちなみに、サンプルではfig
、ax
に明示的にプロットエリアのインスタンスを取得してからプロットしているが、下記のようにも書ける。
# グラフの描画
plt.subplot(2, 1, 1)
plt.plot(x, y1)
plt.subplot(2, 1, 2)
plt.plot(x, y2)
plt.show()
好みの問題かもしれないが、この記法で書いても劇的に短縮されるわけではないのでメリットは薄い。(気がする)
なお、subplot
では強制的にグリッドレイアウトになるが、変則的なレイアウトにする手段もある。
ただし、大抵subplot
で事足りる気がするのでこの記事には含まない。もし、必要になったら**ここ**の記事が参考になる。
よく使うグラフの種類
ここまでの例ではすべて折れ線グラフを使っていたが、いろいろな種類のグラフを書くことができる。
折れ線グラフ:plot
散布図:scatter
棒グラフ:bar
ヒストグラム:hist
ヒストグラム以外の種類は呼び出す関数を変えるだけで、x,yの指定通り描画できる。散布図はplot
関数でlinewidth
とmarker
オプションを設定することでも作成できるが、scatter
関数の場合は、関数名変えるだけなのでこちらのほうが楽。(scatter
は厳密にはバブルチャート作成用らしい)
ヒストグラムに関してはランダムに存在するデータを第一引数に渡し、第二引数で分割数を指定する。上記のサンプルでは正規分布の10000件のデータをyに入れて、適当に30分割して表示してみた。
他にも円グラフやヒートマップなど色々あるが、ここではよく使うものだけまとめておく。ほかのグラフは**公式ドキュメント**に沢山の例があるので、描きたいグラフに近いものを参照すればよい。
グラフの保存
ここまでの例ではplt.show()
でグラフの表示をしてきた。これを使うと、pythonコード実行時にグラフ用のウィンドウが開いて中にグラフが表示される形になる。一応、このウィンドウから保存もできるが、連続で数枚のグラフを作る時や、画像サイズにこだわる時は一々表示はせずにグラフ画像の保存用関数plt.savefig("ファイル名.png")
で保存できる。
ファイル形式は保存するファイル名末尾につけた形式で自動判別される。
上の図は適当な散布図をpng形式で保存したもの。
ファイル名にはパスを指定するので、img
ディレクトリ等を先に作って、その中に連続で画像を保存とかもできる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import numpy as np
from pathlib import WindowsPath as Path
# データの定義(サンプルなのでテキトー)
x = range(100)
y = np.random.normal(100, 20, 100)
# 画像の保存先ディレクトリを作成
img_path = Path("./img")
img_path.mkdir(exist_ok=True)
# グラフの描画
plt.figure(figsize=(4, 2))
plt.plot(x, y, lw=0, marker='.')
plt.savefig("./img/test.png")
jupyterでの表示
jupyterのセルごとに実行結果をoutセルに表示できる。
%matplotlib inline
とノートブックの先頭などに書いておくだけで、他は通常通り書けばよい。
※いつからか不明だが、何も書かなくてもインライン表示できました。とりあえず実行して、表示できないときは上記を書くと解決するかもしれません。
markdown-preview-enhancedのコードチャンクでの表示
実験結果をレポートとしてまとめる時などに、markdown-preview-enhancedを使う場合、コードチャンクとして実行コードを埋め込むことができる。
通常、コードチャンクとしてpythonのコードを埋め込む時は、
```python {cmd}
~
```
のようにpython指定のコードブロックの後ろに␣{cmd}
をつける。
このままでmatplotlibの描画コードを実行すると、plt.show()
で別ウィンドウが開いてしまう。
こんな感じ↓
そこで、コードブロックの後ろを␣{cmd matplotlib}
に変更すると、ドキュメント中に出力がインライン表示されるようになる。↓
hide
も指定して、␣{cmd hide matplotlib}
とすると、描画用のコードを隠してグラフだけ表示することもできる。
※コードチャンク自体デフォルトではセキュリティ上offになっているので、公式ドキュメントの通り有効にしたときのみ使用できる。公式ドキュメントでも下記の注意書きがあるように、悪意あるコードを実行できてしまう危険があるので、機能の有効化は自己責任で。
⚠️ Script execution is off by default and needs to be explicitly enabled in Atom >package / VSCode extension preferences
Please use this feature with caution because it may put your security at risk! Your >machine can get hacked if someone makes you open a markdown with malicious code while >script execution is enabled.
Option name: enableScriptExecution
見た目の調整
ここまではデータをプロットするだけだったが、レポートに載せる時などは当然体裁を整えたくなる。
よく使うオプション
軸、目盛り関連
軸範囲の調整:xlim, ylim
表示する軸範囲をを設定するオプション。
x軸はplt.xlim(min, max)
、y軸はplt.ylim(min, max)
にそれぞれ上下限値を指定する。
なお、axes
を使う場合はax.set_xlim(min, max)
とax.set_ylim(min, max)
と若干名称が変化する。
例えば、下記コードは散布図を描画するが、基本0~100のデータ分布中に10000の値が紛れさせている。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(100)
y = [random.randint(0, 100) for _ in range(40)]
y.append(10000)
y.extend([random.randint(0, 100) for _ in range(59)])
# グラフの描画
plt.scatter(x, y)
plt.show()
こんな外れデータを無視して分布が集中しているところを見たくなったりするときに、データから外れ値を除く処理を掛けなくても、y軸の描画範囲を絞るだけで見れるようになる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(100)
y = [random.randint(0, 100) for _ in range(40)]
y.append(10000)
y.extend([random.randint(0, 100) for _ in range(59)])
# グラフの描画
plt.scatter(x, y)
plt.ylim(0, 120)
plt.show()
数値でない軸目盛りを使う
x軸には時折数値でない値を使いたいこともある。
文字列をそのまま軸目盛りに使いたい場合
項目ごとに正規化した値を比較するようなグラフとかの場合は、x軸に項目名の文字列リストを指定するだけで自動的に項目名を軸にしてくれる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = ['a', 'b', 'c', 'd', "hoge"]
y = [random.randint(0, 100) for _ in x]
# グラフの描画
plt.bar(x, y)
plt.show()
プロットは値そのままで、描画上文字列に置換したい場合
任意の文字列を目盛りに振りたい時は、x軸はplt.xticks(x, ticks)
、y軸はplt.yticks(y, ticks)
を使う。x
,y
は目盛り値のリスト、ticks
には目盛りに対応するラベル(文字列とか)のリストを渡す。ticks
を省略すると目盛りの値がそのままラベルになる。
なお、axes
に設定する場合はset_xticks()
,set_yticks()
になる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
xticks = ["id{}".format(x) for x in random.sample(range(100), len(x))]
y = [random.randint(0, 100) for _ in x]
# グラフの描画
plt.plot(x, y)
plt.xticks(x, xticks)
plt.show()
また、xticks
,yticks
は軸の目盛りを調整するものになるので、デフォルトの目盛り間隔が広すぎる/狭すぎるといったときに、任意の間隔に調整するのにも使う。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
xticks = ["id{}".format(x) for x in random.sample(range(100), len(x))]
y = [random.randint(0, 100) for _ in x]
# グラフの描画
fig = plt.figure()
ax = fig.add_subplot(3, 1, 1)
ax.plot(x, y)
ax.set_title("自動")
ax = fig.add_subplot(3, 1, 2)
ax.plot(x, y)
ax.set_xticks(x)
ax.set_title("全部")
ax = fig.add_subplot(3, 1, 3)
ax.plot(x, y)
ax.set_xticks([i for i in x[::3]])
ax.set_title("3つ飛ばし")
plt.tight_layout()
plt.show()
軸目盛を表示したくない場合
plt.xticks([])
のように空のリストを渡せば軸目盛を消せる。
なお、axes
に設定する場合はset_xticks()
,set_yticks()
になる。
グリッドの表示/非表示
グラフによってはグリッド線のガイドがあると見やすくなるものがある。グリッドはplt.grid()
で表示できる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
y = [random.randint(0, 100) for _ in x]
# グラフの描画
plt.plot(x, y)
plt.grid()
plt.show()
オプション引数でaxis=
に"x"
や"y"
を指定すると、指定した側だけグリッド線を表示できる。
データの表示関連
線の幅を調整:linewidth
折れ線で接続する線の幅を調整するオプション。
plt.plot(x, y, linewidth=xx)
または、plt.plot(x, y, lw=xx)
と指定する。(xxは任意の値)
線の種類:linestyle
折れ線で接続する線の種類を調整するオプション。
plt.plot(x, y, linestyle=xx)
または、plt.plot(x, y, ls=xx)
と指定する。(xxは任意の指定子)
指定子 | 種類 |
---|---|
"-" | 実線 |
"--" | 破線 |
"-." | 一点鎖線 |
":" | 点線 |
点の種類:marker
プロットする点の種類を調整するオプション。
plt.plot(x, y, marker=xx)
と指定する(xxは任意の指定子)
指定子は大量にあるが、主に使うものをピックアップしたのが下表。全種確認したい時は公式ドキュメントを参照。
指定子 | 種類 |
---|---|
"o" | 丸 |
"." | 点 |
"s" | 四角 |
"D" | ダイヤ |
"+" | プラス |
線、点の色:color
描画する線及び点の色を調整するオプション。
plt.plot(x, y, color=xx)
またはplt.plot(x, y, c=xx)
と指定する(xxは任意の色名)
指定する色名の内、下表の色は短縮指定子を使える。
下表に無い色でもかなりの色がプリセットとして色名指定できるようになっている。詳しくは公式ドキュメント参照。
指定子 | 色 | フルネーム |
---|---|---|
'r' | 赤 | "red" |
'g' | 緑 | "green" |
'b' | 青 | "blue" |
'c' | シアン | "cyan" |
'm' | マゼンタ | "magenta" |
'y' | 黄 | "yellow" |
'k' | 黒 | "black" |
'w' | 白 | "white" |
その他
凡例の表示
プロットしたデータの凡例を表示する機能。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
fig, ax = plt.subplots(1, 1)
for i in range(3):
lower = 100 * i
upper = lower + 100
y = [random.randint(lower, upper) for _ in x]
ax.scatter(x, y, label="random:{}-{}".format(lower, upper))
plt.legend()
plt.tight_layout()
plt.show()
なお、凡例の表示位置をplt.legend(loc=xx)
で指定できる。(xxは任意のパターンの指定子)
なお、axes
の場合も同じメソッド名でよい。
指定パターンは下表の通り。
指定子 | 位置 |
---|---|
"best" | 自動(標準) |
"upper left" | 左上 |
"center left" | 左中央 |
"lower left" | 左下 |
"upper center" | 中央上 |
"center" | 中央 |
"lower center" | 中央下 |
"upper right" | 右上 |
"center right" | 右中央 |
"lower right" | 右下 |
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
# グラフの描画
fig = plt.figure()
locs = [
"{} {}".format(a, b)
for b in ["left", "center", "right"]
for a in ["upper", "center", "lower"]
if not (a == "center" and b == "center")
]
locs.insert(len(locs) // 2, "center")
for j, loc in enumerate(locs, 1):
for i in range(3):
lower = 100 * i
upper = lower + 100
y = [random.randint(lower, upper) for _ in x]
ax = fig.add_subplot(3, 3, j)
ax.scatter(x, y, label="{}-{}".format(lower, upper))
ax.set_title("\"{}\"".format(loc))
ax.legend(loc=loc)
plt.tight_layout()
plt.show()
グラフタイトルの表示
グラフに任意のタイトルを書く機能。
plt.title(xx)
で指定する。(xxは表示したい任意の文字列)なお、axes
の場合はax.set_title(xx)
となる。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
y = [random.randint(0, 100) for _ in x]
# グラフの描画
plt.plot(x, y)
plt.title("タイトル")
plt.show()
任意のテキストの表示
axes
内の任意座標を指定して、指定したテキストを描画する機能。
plt.text(x, y, s)
で指定する。
#!/usr/bin/env python
# coding: utf-8
from matplotlib import pyplot as plt
import random
# データの定義(サンプルなのでテキトー)
x = range(10)
y = [random.randint(0, 100) for _ in x]
# グラフの描画
plt.plot(x, y)
plt.text(5, 50, "真ん中")
plt.grid()
plt.show()
終わりに
普段よく使う機能をまとめてみたが、かなりのボリュームになってしまった…
matplotlib
にはまだまだ使ったことない機能も沢山あるが、次はアニメーションをまとめたいと思います。