python

1時間で理解するmatplotlibの基礎

2021-05-15

matplotlibで押さえておきたい基礎部分を1時間程度で理解できるようにまとめました。

ガッツリ勉強したいわけじゃないけれど、ある程度は自分で応用しながら使えるくらいの理解はしておきたい。そんな方のために、最初に理解するべき部分について解説します。

matplotlibとは

matplotlibは、Pythonでデータからグラフを描画するためのライブラリです。統計や機械学習など大規模なデータを扱う場合にデータの可視化は必須ですが、その他にもプログラムの性能評価の結果をグラフにするなど、可視化できることによる付加価値向上が期待できます。

またmatplotlibはjupyterlabなど対話式の環境でのデータ操作と相性が良いので、併用して使用されるケースが多いです。僕は最近までjupyterlabを使ったことがなかったのですが、いざ使ってみると本当に便利で手放せなくなりました。matplotlibをこれから使おうという方はぜひともインストールして使ってみて下さい。

本記事での解説は、jupyterlab環境を想定しています。

Hello World的なグラフを作成してみる

まずは詳しい説明ではなく、実際にmatplotlibを動かしてみましょう。すでに1度でもmatplotlibを動かしたことがあるという方はこの章は読み飛ばして大丈夫です。

インストール

インストールはpipコマンドで可能です。

pip install matplotlib

この記事での説明で一部PyQt5パッケージも使用する部分があるのでインストールしておいて下さい。

pip install PyQt5

基本的なグラフを描画してみよう

matplotlibでグラフを描画するときにインポートが必要なのが、matplotlib.pyplotモジュールです。インポートするときに、pltという別名をつけるのが一般的になっています。

import matplotlib.pyplot as plt

この慣習はSciPyとNumpyのメーリングリストで議論されて決定されたもので、世界的にこの書き方が推奨されています。(参考

基本的なグラフはpyplot.plot()関数で描画することができます。詳しい話は後述するので、ここではイメージだけつかめればOKです。

plt.plot([1, 2, 3, 4], [2, 4, 6, 8])

実行結果:

jupyterlab上で実行した場合は、実行したPythonプログラムの下に結果のグラフが描画されます。

基礎となる2つのクラス

matplotlibでのグラフは、描画領域を管理するFigureクラスと、1つのグラフを管理するAxesクラスで構成されています。

描画領域を管理するFigure

Figureインスタンスは、pyplot.figure()関数で作成・取得することができます。

import matplotlib.pyplot as plt

# バックエンドを変更(jupyterlabで実行する場合のみ必要)
%matplotlib qt5

fig = plt.figure()
fig.show()

結果:

Figure.show()メソッドを呼び出すと描画ウィンドウは表示されますが、何も描画されていません。つまり、Figureインスタンスが作成されて領域だけは確保されたけれども、グラフはまだ作成されていない状態…ということがわかりますね。

「%matplotlib qt5」について

サンプルコードで出てきた「%matplotlib qt5」という記述について、少し説明しておきます。

fig.show()はウィンドウを表示して、そのウィンドウに描画するメソッドです。それに対しjupyterlabの環境は、デフォルトでは描画をウィンドウではなくインラインに表示しようとします。この矛盾をなくすために、%matplotlib qt5と記述しています。

これは、jupyterlab上でバックエンドを変更する方法で、公式ドキュメントのThe builtin backendsに記述があります。

今回はFigureインスタンスの理解を深めるためにfig.show()を呼び出していますが、普段使いでは%matplotlib qt5という記述の必要はありません。ということで長々と説明しましたが、結論としてはスルーしてもらって引き続きこの記事を読み進めて下さい。

1つのグラフを管理するAxes

pyplot.subplots()関数を使うと、FigureインスタンスとAxesインスタンスを同時の作成・取得することができます。

import matplotlib.pyplot as plt

%matplotlib qt5

fig, ax = plt.subplots()
fig.show()

結果:

こんどは、内容のない空のグラフが表示されました。グラフを管理するAxesインスタンスが作成されたものの、まだそこに何もプロットしていない状態だからです。

では実際にグラフを描き込んでみましょう。

Axes.plot()メソッドに横軸と縦軸の値を渡すことでプロットすることができます。

import matplotlib.pyplot as plt

# 今回からこの部分はコメントアウト。
# jupyterlabだとウィンドウではなくインラインに表示されるようになる。
#%matplotlib qt5

fig, ax = plt.subplots()

y = [6, 7, 3, 8, 8, 9, 4, 6, 7, 9]
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ax.plot(x, y)

結果:

今度はグラフが描画されました。

1つのFigureに複数のAxes

ここまでの解説では、Figureだけではグラフが描画されず、Axes.plot()メソッドを呼び出すことでようやくグラフが描画されました。ただこれだと、はじめからFigureなんかいらなくてAxesだけあればいいような気がしていませんでしたか?

1つのFigureは複数のAxesを持つことができます。

pyplot.subplots()関数の引数に2以上の値を指定すると、指定した数だけAxesインスタンスが作成されます。そして複数作成されたAxesインスタンスそれぞれは、1つのFigureインスタンスに所属します。

import matplotlib.pyplot as plt
import numpy as np

y = np.array([6, 7, 3, 8, 8, 9, 4, 6, 7, 9])
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

fig, (ax1, ax2) = plt.subplots(2)

ax1.plot(x, y)
ax2.plot(x, -y)

結果:

このように、1つのFigureで複数のAxesをまとめて管理することができます。

MATLABスタイル

MATLABは広く使われている有料の数値解析ソフトです。matplotlibは、MATLABでのグラフ描画シンタックスに似せたシンタックスも提供していています。

MATLABスタイルの記述:

import matplotlib.pyplot as plt

y = [6, 7, 3, 8, 8, 9, 4, 6, 7, 9]
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

plt.plot(x, y)

結果:

pyplotモジュールのplot()関数に描画データを渡すと、すぐにグラフが作成されました。FigureインスタンスやAxesインスタンスを作ってから操作するのに比べて、少ない記述でグラフを作成することが可能です。

pyplotモジュールは内部的にFigureやAxesをもっていて、それらに対しての処理を仲介する形でMATLABと同様のシンタックスを実現しています。

fmtパラメータを指定したスタイルカスタマイズ

plot関数のシグネチャは次のようになっていて、fmtパラメータにスタイル指定文字列を指定することでカスタマイズできます。

plot([x], y, [fmt], *, data=None, **kwargs)
plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

スタイルを指定

fig, (ax1, ax2) = plt.subplots(2)
ax1.plot([1, 2, 3], [10, 20, 30], '.:r')
ax2.plot([1, 2, 3], [10, 20, 30], '-.k')

結果:

fmtパラメータの書式は次のようになっています。

fmt = '[marker][line][color]'

上述したサンプルで指定した'.:r'という文字列は、1文字目の"."がマーカーの種類を、2文字目の":"がラインの種類を、3文字目の"r"がカラーを指定していました。マーカー・ライン・カラーともにいくつか種類が用意されていて、自由に組み合わせることができます。

続いて、指定できるスタイルをmatplotlibを使ってプロットした一覧表を紹介します。自分でスタイルを作成する際の参考にどうぞ。ちなみに、ソースコードは雰囲気が伝わればということで一応載せておきました。この記事で紹介していない機能が多く使ってあるので、興味のある方だけ見てもらえればと思い載せておきました。

マーカー

マーカーは25種類の中から指定可能です。

上記グラフを作成する参考ソースコード:

import matplotlib
import matplotlib.pyplot as plt
import itertools
import numpy as np
import math

%matplotlib ipympl

markers = list('.,ov^<>12348spP*hH+xXDd|_')
x_cycle = itertools.cycle([10, 20, 30, 40, 50])
y = np.arange(math.ceil(len(markers) / 5), 0, -1).repeat(5)

for m, x, y in zip(markers, x_cycle, y):
    # fmt引数にマーカーをセット
    plt.plot(x, y, m, markersize=10)
    plt.text(x-3, y, f'{m}')
    
plt.xticks([])
plt.yticks([])
plt.xlim(left=5)

ラインスタイル

ラインスタイルは4種類あります。

上記グラフを作成する参考ソースコード:

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

%matplotlib ipympl

line_styles = ('-', '--', '-.', ':')
x = y = np.arange(10)

fig = plt.figure()

for idx, ls in enumerate(line_styles):
    ax = fig.add_subplot(2, 2, idx+1)
    # fmtにラインスタイルをセット
    ax.plot(x, y, ls)
    ax.set_title(f'line style "{ls}"')
    ax.set_xticks([])
    ax.set_yticks([])

色は8色あります。白地なのでwhiteは見えていません。

上記グラフを作成する参考ソースコード:

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

%matplotlib ipympl

colors = list('bgrcmykw')
x = np.arange(5)
y = np.zeros(len(x))

for c in colors:
    # fmtに色をセット
    plt.plot(x, y, c)
    y += 1

ylabels = (f'color {c}' for c in colors)
plt.yticks(np.arange(len(colors)), labels=ylabels)
plt.xticks([])
    

kwargsパラメータを指定したスタイルカスタマイズ

先ほどはfmtパラメータを指定してスタイルをカスタマイズする方法について紹介しました。そこでもう一度、plot()関数のシグネチャを見てください。

plot([x], y, [fmt], *, data=None, **kwargs)
plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

kwargsには広範にわたる様々なパラメータを指定することができますが、ここにスタイルを指定することもできます。fmtパラメータを使ったスタイル指定は簡潔に指定できる代わりに自由度が低く、kwargsは記述が冗長になりがちですが自由度が高い、という使い分けができます。(あとはどっちが好みか)

markerパラメータ

markerパラメータでマーカーを指定することができます。matplotlib.markersに記載されているマーカーが指定可能です。fmtパラメータでは指定できないマーカーもあります。

plt.plot(np.arange(10), marker=2)

linestyleパラメータ

linestyleパラメータでラインのスタイルを指定することができます。Linestylesに記載されているラインスタイルが指定できます。fmtパラメータでは指定できないスタイルが多くあります。

ラインの種類と指定方法はLinestylesのページを一度閲覧して、あまり使わないだろーなって戻ってきてもらえたらオッケーです。

colorパラメータ

colorパラメータ(またはcパラメータ)で色を指定することができます。

色表現方法書式
RGBタプル 0〜1で指定(Red, Green, Blue)c=(1, 0.5, 0.1)
RGBAタプル 0〜1で指定(Red, Green, Blud, Alpha)c=(1, 0.5, 0.1, 0.2)
16進数RGB文字列"#RRGGBB"c="#FFAA55"
16進数RGBA文字列"#RRGGBBAA"c="#FFAA5533"
グレー表現文字列"N.N"c="0.5"
省略色名'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'のいずれかc="r"
色名'blue', 'green', 'red', cyan', 'mazenta',
'yellow', 'black', 'white'のいずれか
c="red"
 X11 color names色名文字列
X11の色名称(wikipedia)で紹介のもの)
c="AliceBlue"

上記グラフを作成する参考ソースコード:

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

%matplotlib ipympl

y = np.ones(5)

colors = (
    (1, 0.2, 0.5), # RGBタプル
    (1, 0.2, 0.5, 0.2), # RGBAタプル
    "#00FF55", # 16進RGB数文字列
    "#00FF5533", # 16進数RGBA文字列
    "0.5", # グレー表現文字列
    "b", # 省略色名
    "red", # 色名
    "Aqua", #  X11 color name
)

for color in colors:
    plt.plot(y, c=color)
    y += 1

plt.xticks([])
plt.yticks(range(1, 9), [str(c) for c in colors])
for text in plt.yticks()[1]:
    text.set_rotation(60)

あとがき

最初に知っておくべき基礎の部分の説明は、以上です。1時間で読めましたか?

多くの人がFigureとAxesの関係を理解しないままpyplot.plot()関数を呼び出して、ググって出てきたコードをなんとなくコピペして使っていると思います。一方であなたは基礎を理解するために1時間使いました。後々になってその差が大きく表れると思います。

実はここで解説したもの以外にも、インタラクティブモード、バックエンド、デフォルトの設定、ファイルへ保存、複雑なプロット、Artistクラス、リソース管理、その他もろもろ…基礎の次に覚えるべき部分はたくさんあります。

必要になったときに必要な部分だけ、公式チュートリアルから選択して身につけていけば大丈夫です。

-python

© 2022 ヂまるBlog