Matplotlib

Matplotlib の基礎

 
タイトル・テキスト・凡例

 
軸と目盛

 
色・透明度・線種

 
矢印・画像・アニメーション

 
データの可視化

  
図形の描画

 
Matplotlib の応用

 

Matplotlib

 Matplotlib は現代的オブジェクト指向言語 Python のために開発されたオープンソースのグラフ描画用パッケージです。科学計算用ライブラリ NumPy および SciPyと併用することで、ユーザーのもつデータを様々な方法で可視化できるように設計されています。Matplotlib は学術・産業分野で定評のある有料ソフトウェア MATLAB とほぼ同等の機能をもち、かつ無料であることから、様々な研究分野で活用され始めています。

 Matplotlib の pyplot モジュールが提供するインターフェースは MATLAB をお手本に設計されています。そのため慣れないうちは、その作図コマンドの暗黙的動作に違和感を覚える Pythonユーザーもいるようです。しかし土台はあくまで Python なので、ユーザーは意識的にオブジェクト指向 (OOP) で明示的なコードを記述することもできます。

 当サイトでは基本姿勢として、Matplotlib の骨格である Figure と Axes の階層構造を明示したオブジェクト指向 (OOP) のサンプルコードを掲載します。この記述法は MATLABスタイルに比べると、コードが若干長くなりますが、暗黙的動作を排除することで「どの行のコードで何をしているのか」がわかりやすくなり、結果として「どこを変えればグラフを調整できるのか」ということが明確になります。
 

Advertisement

Matplotlib の基本的な使い方

 当サイトでは Jupyter Notebook 環境を前提に Matplotlib の使い方を解説しますが、マジックコマンドで呼び出さない記法を採用しているので、PyCharm など他の統合開発環境であっても使い方はほとんど同じです。

Figure と Axes

 Matplotlib を使ってグラフを描くときには、最初に NumPy と Matplotlib のサブパッケージである pyplot を読み込みんでから、FigureAxes を用意します。

# NumPyをインポート
import numpy as np

# matplotlibをインポート
import matplotlib.pyplot as plt

# Axesを配置する領域を作成
fig = plt.figure(facecolor = "lightgray")

# FigureにAxesを追加
ax = fig.add_subplot(111)

 上のサンプルコードを実行すると、次のようなグラフが表示されます。[注:Jupyter Notebook を開いて一番最初にグラフを描画させようとすると、<Figure size 640x480 with 1 Axes> のような文だけが表示される場合がありますが、その場合には、もう一度実行するとグラフが描かれます]

 Matplotlibグラフ描画 Axesを追加

 灰色に塗り潰された領域が Figure, 内側の白い部分が Axes です。

 Matplotlibグラフ描画 AxesとFigure

 Figure はウィンドウのようなもので、この中にグラフを描画するための Axes を複数配置することができます。サンプルコードでは Figure の領域がわかりやすいように facecolor (塗り潰しの色) に lightgray (薄い灰色) を指定していますが、デフォルトだと真白なので、Jupyter Notebook の背景色と同化してしまって Figure の範囲がよくわかりません。ちなみに Axes とは「座標軸」を意味する Axis の複数形で、Matplotlib では「グラフ描画領域」という意味で使われています。

 Figure は matplotlib.figure.Figureクラスのインスタンスで、普通は Figureオブジェクト (あるいは単に Figure) とよばれます。Axes は matplotlib.axes.Axesクラスのインスタンスで、Axesオブジェクトまたは Axes とよばれます。詳細については、Matplotlib の公式ドキュメント を参照してください。

 上のコードでは、Axes は figure.add_subplot()メソッドによって追加されています。このことから、Axes のことをサブプロットとよぶ場合もあります。また、ここでは詳しく書きませんが、Axes は figure.add_axes()メソッドによって追加することもできます。どちらのメソッドを使っても、追加されるのは同じ Axesオブジェクトです。
 

Axesにデータをプロットする

 Axes に 1 次関数(直線)のグラフをプロットしてみましょう。

import numpy as np
import matplotlib.pyplot as plt

#サブプロットを描画する領域を作成
fig = plt.figure()

# figにAxesを1つ追加
ax = fig.add_subplot(111)

# -5~5まで0.1刻みの数値の配列を定義
x = np.arange(-5, 5, 0.1)

# グラフに描く関数
y = x

# axにグラフを描画
ax.plot(x, y)

 このコードを実行すると直線のグラフが表示されます。

 Python Matplotlibで描いた直線のグラフ

 上のコードでは、np.arange() を使って -5 から 5 まで 0.1 刻みの数値を要素にもつ配列を定義したあと、y = x によって、x に等しい配列をもう1つ作成しています。そして、axes.plot()メソッドを使って Axes にデータをプロットさせています。これは最低限の設定で描かせたグラフなので、グラフタイトルも軸ラベルもありません。そうした細かい部分の調整を各記事で解説していくことになります。
 

複数の Axes を配置する

 先ほどのサンプルコードで、figure.add_axes()メソッドの引数が「111」となっていましたが、これは「 Figure の 1 行 1 列の 1 番目に Axes を追加する」ことを意味しています。今度は 2 行 2 列の 1, 2, 3 番目に Axes を追加するコードを書いてみます。

# NumPyをインポート
import numpy as np

# matplotlibをインポート
import matplotlib.pyplot as plt

#Axesを描画する領域(Figure)を作成
fig = plt.figure(facecolor = "lightgray")

# Figureに3つのAxesを追加
ax_1 = fig.add_subplot(221)
ax_2 = fig.add_subplot(222)
ax_3 = fig.add_subplot(223)

 コードを実行すると次のようなグラフが表示されます。

 Matplotlibグラフ描画 Axesを複数配置

 figure.add_axes()メソッドの引数 22x を指定したときに追加される Axes の位置対応は次のようになっています。

 Matplotlibグラフ描画 Axesの位置対応図
 
 pyplot.subplots() を使うと、複数の Axes オブジェクトを一度に生成できます。
 第 1 引数 nrows と 第 2 引数 ncols には、それぞれ Axes の行方向の数と列方向の数を渡します。sharex と sharey を指定することで、x 軸と y 軸のラベルを共有できます。

 たとえば、縦に 3 個、横に 2 個の Axes を埋め込んだ Figure は以下のコードで作成できます。

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# 3行2列のAxesを埋め込んだFigureを生成
# 軸ラベルは共有する
fig, ax = plt.subplots(3, 2, sharex="col", sharey="row")

 Matplotlib plt.subplots で複数のサブプロットを配置する

 このとき、ax には Axes を要素にもつ配列が格納されます:

# In[2]

# axを表示
print(ax)
[[<matplotlib.axes._subplots.AxesSubplot object at 0x05FE6DF0>
  <matplotlib.axes._subplots.AxesSubplot object at 0x05CDF990>]
 [<matplotlib.axes._subplots.AxesSubplot object at 0x05CFDED0>
  <matplotlib.axes._subplots.AxesSubplot object at 0x05D1B8F0>]
 [<matplotlib.axes._subplots.AxesSubplot object at 0x05D39810>
  <matplotlib.axes._subplots.AxesSubplot object at 0x05D597F0>]]

 3 行 2 列目の Axes にデータをプロットする場合は、次のようなコードで実現できます。

# In[3]

# 正弦波のデータ
x = np.linspace(1, 10)
y = np.sin(x)

# 3行2列目にあるAxesにデータをプロット
ax[2, 1].plot(x, y)

# Figureを再表示
display(fig)

 Matplotlib 特定のサブプロットを選んでデータをプロットする
 

Figureのクリア(初期化)

 Jupyter notebook で Figure と Axes を作成したコードセルを抜けたあと、別のコードセルで Axes.plot() などを使用しても何も表示されないため、Figure オブジェクトや Axes オブジェクトが消えてしまったように錯覚しがちです。

# In[1]

# 3×3サイズのFigureオブジェクトを作成
fig = plt.figure(figsize=(3, 3))

# FigureにAxesを追加
ax = fig.add_subplot(111)

# Axesの設定
ax.grid()  # グリッドを表示
ax.set_title("Axes sample", fontsize=14)  # タイトルを表示
ax.set_xlim([-5, 5])  # x軸の範囲
ax.set_ylim([-5, 5])  # y軸の範囲

 Figure.clf()

# In[2]

# データを作成
x = np.arange(-5, 6)
y = x

# データをAxesにプロット
ax.plot(x, y)
[<matplotlib.lines.Line2D at 0x3e04b10>]

 しかし、実際にはどちらも残っていて、display() で再表示できます (もし本当にオブジェクトが消えてしまったのであれば、plot メソッドの使用時にエラーとなるはずです)。

# In[3]

# Figureを再表示
display(fig)

 Figure.clf():Figureをリセット、Axesを消去する

 Figure のプロットデータや設定をリセットしたいときは Figure.clf() を使います。
 clf() メソッドは Figure に展開されている Axes オブジェクトをすべてクリアします (Figure オブジェクトそのものは消えません)。

# In[4]

# Figureをリセット
fig.clf()

# Figureを再表示
display(fig)
<Figure size 216x216 with 0 Axes>

 

Axesのクリア(初期化)

 Axes.cla() は Axes を白紙の状態に戻します。Axes オブジェクト自体は残したまま、データのプロットや、軸や目盛などの各種設定をリセットします。Jupyter notebook でコードセルを抜けたあと、別のコードセルで Axes オブジェクトを使い回したいときなどに cla() メソッドが使えます。

# In[1]

# FigureとAxesを作成
fig = plt.figure(figsize=(3,3))
ax = fig.add_subplot(111)

# Axesの中心に大きな点をプロット
ax.scatter(0.5, 0.5, s=800, c="darkgreen")

 Axes.cla() Axesの初期化

# In[2]

# Axesをリセット
ax.cla()

# Axesの中心に大きな三角形をプロット
ax.scatter(0.5, 0.5, s=800, c="firebrick", marker="^")

# Figureを再表示
display(fig)

 [Matplotlib] Axesのリセット(クリア)

Figure と Axes の書式設定

 Figureオブジェクトを作るときに、大きさや塗り潰しの色、枠線の有無などを指定できます。また、Figure に Axes を追加したあとで、subplots_adjust() メソッドを使って隣り合う Axes 同士の余白を調整できます。以下のサンプルコードを参考にカスタマイズしてみてください。

import matplotlib.pyplot as plt

# Figureオブジェクトの作成と書式設定
fig = plt.figure(
    
    # サイズ
    figsize = (5, 5),
    
    # 塗り潰しの色
    facecolor = "lightgray",
    
    # 枠線の表示
    frameon = True,
    
    # 枠線の色
    edgecolor = "black",
    
    # 枠線の太さ
    linewidth = 4)

# FigureにAxes(サブプロット)を追加
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)

# Axesオブジェクト(サブプロット)間の余白調整
# wspaceは行方向、hspaceは列方向を調整
fig.subplots_adjust(wspace = 0.4, hspace = 0.4)

 Figureオブジェクト書式設定 Axes間の余白①

 最後の行で subplots_adjust() メソッドを使って、隣り合う Axes 間の余白を調整していますが、このコードがないと下の図のように目盛などが詰まって見づらくなってしまいます。

 Figureオブジェクト書式設定 Axes間の余白②
 
 Figureオブジェクトに Axesオブジェクト (サブプロット) を追加するときに、塗り潰しの色や軸の範囲などを設定することができます。これらは Axes 作成後にメソッドで設定することもできます。以下のサンプルコードに Axes の書式設定の例を載せておきます。

import matplotlib.pyplot as plt

# numpyをインポート
import numpy as np

# Figureオブジェクトの書式設定
fig = plt.figure(figsize = (5, 5))

# FigureにAxes(サブプロット)を追加
ax = fig.add_subplot(
    
    #行数と列数、Axes番号
    111,
    
    # 塗り潰しの色
    facecolor = "lightgreen",
    
    # x軸とy軸の範囲
    xlim = [-4,4], ylim = [0,40])

# -4~4, 0.2刻みのデータを用意
x = np.arange(-4, 4, 0.2)

# yのデータを用意
y = np.exp(x)

# Axesに(x,y)データをプロット
ax.plot(x, y)

 Axesオブジェクト書式設定

スタイルシート (plt.style.use)

 style モジュールからスタイルシートを読み込めば、プロットスタイルを手軽に変更できます。スタイルシートは、\mpl-data\stylelib フォルダの中に、拡張子 .mplstyle のついたファイルとして格納されているはずです。スタイルの細かな調整には若干面倒な作業が必要なので、よほどこだわりがなければ、この方法でスタイルを決定すれば十分だと思います。

 最初に NumPy と Matplotlib を読み込んでおきます。

# In[1]

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

# 実行環境
print("実行環境")
print(f"Python {platform.python_version()}")
print(f"NumPy {np.__version__}")
print(f"Matplotlib {matplotlib.__version__}")
実行環境
Python 3.6.9
NumPy 1.18.5
Matplotlib 3.2.2

 以下のコマンドで、使用可能なスタイルシートの一覧を表示できます。

# In[2]

# 使用可能なスタイルシートの名前一覧
plt.style.available
['Solarize_Light2',
 '_classic_test_patch',
 'bmh',
 'classic',
 'dark_background',
 ・・・・・・
 'seaborn-white',
 'seaborn-whitegrid',
 'tableau-colorblind10']

 同じグラフに対して色々なスタイルを適用して変化の様子を見るので、あらかじめグラフを描く関数を用意しておきます。

# In[3]

# グラフを並べて描く関数
def test_plot():
    fig, ax = plt.subplots(1, 2, figsize=(8,3.5))
    np.random.seed(1137)
    x0 = np.random.randn(1000)
    x1 = np.linspace(-6, 6)
    ax[0].hist(x0)
    for k in range(3):
        ax[1].plot(x1, x1 + 3*k)
    plt.show()

 最初にデフォルトのスタイルでプロットしてみましょう。

# In[4]

# デフォルトのスタイルでプロット
test_plot()

matplotlib デフォルトのスタイル (default_style)

 plt.style.use("stylename") でスタイルシートを変更できますが、その後のプロットすべてに影響を与えます。スタイル・コンテキスト・マネージャーを使用すれば、デフォルト設定を変更せずに一回限りでスタイルを適用できます。スタイルシートに "grayscale" を指定して、白黒の図を描いてみましょう。

# In[5]

# 白黒の図を描く
with plt.style.context("grayscale"):
    test_plot()

matplotlib style_sheet 白黒 (gray scale)

 dark_background は背景を黒く塗り潰したデザインです。

# In[6]

# 背景を黒く塗り潰す
with plt.style.context("dark_background"):
    test_plot()

matplotlib dark_background (背景を黒く塗り潰す)

 bmh は bayesian bethods for hackers (ハッカーのベイジアン・メソッド) の略です。

# In[7]

# Bayesian Methods for Hackers style sheet
# ベイジアン・メソッド・スタイル
with plt.style.context("bmh"):
    test_plot()

matplotlib bayesian bethods for hackers (ハッカーのベイジアン・メ ソッド)

 seaborn 風のスタイルも指定できます。たとえば、seaborn-pastel は淡い色調でグラフがデザインされます。

# In[8]

# seabornのパステル調スタイル
with plt.style.context("seaborn-pastel"):
    test_plot()

seaborn-pastel

 ggplot は R 言語で使用されているヴィジュアルツールです。

# In[9]

# R言語のスタイルシート
with plt.style.context("ggplot"):
    test_plot()

matplotlib ggplot style (R言語のヴィジュアルツール)

MATLAB スタイル

 Figure クラスと Axes クラスのインスタンス生成を宣言せずにデータをプロットする、いわゆる MATLAB スタイル も選択できます。

 MATLAB スタイルにおいては、あらゆる操作は matplotlib.pyplot モジュールの関数を介して実行されます。たとえば、pyplot.plot() は基本的かつ汎用性の高いプロット機能を提供します。

 単体のグラフを作成する場合、ユーザーは Figure や Axes を準備する必要はありません。これらのオブジェクトは自動生成されます。

# In[1]

import numpy as np
import matplotlib.pyplot as plt

# y=logxのデータ
x = np.linspace(1, 10)
y = np.log(x)

# データをプロット
plt.plot(x, y, color="red")

 Matplotlib MATLABスタイル

 pyplot の関数は、常に現在の Figure と Axes に対してはたらきかけます。
 pyplot.subplot() は Figure を作成して Axes を追加する関数ですが、実行するたびにアクティブな Axes は移り変わります。たとえば、以下のコードは Figure に 2 つの Axes を加えますが、プロットは 2 番目の Axes に対して実行されます。

# In[2]

# 2行1列のうち1つめのAxesを生成
plt.subplot(2, 1, 1)

# 2行1列のうち2つめのAxesを生成
plt.subplot(2, 1, 2)

plt.plot(x, y, color="red")

 MATLAB 的なコードで表示されたグラフ

 MATLAB スタイルのコードはオブジェクト指向に比べて簡潔ですが、ユーザーは常にアクティブな Figure と Axes を意識しなくてはならず、複数の Axes を扱いにくいというデメリットがあります。

 Jupyter notebook を使用している場合、コードセルを抜けて別のコードセルで pyplot.plot() などのデータプロット関数を実行すると、以前のオブジェクトは受け継がれずに、全く新しい Figre と Axes が生成されます。

# In[3]

plt.plot(x, y, color="dimgrey")

 MATLAB スタイル、対数関数のプロット

 作成した Figure を別のコードセルで再利用したいと考えるならば、plt.gcf() で現在の Figure オブジェクトを取得して保存しておきます。gcf は get current figure の略です。

# In[4]

x = np.linspace(0, 10, 65)
y = np.sin(x)

plt.plot(x, y, color="forestgreen")

fig = plt.gcf()

 matplotlib, plt.gcf()

# In[5]

# figを再表示
display(fig)

 matplotlib, plt.gcf()

 同様に現在の Axes を取得する関数は pyplot.gca() です。
 gca は get current axes の略です。
 MATLAB スタイルのコードはバックグラウンドで pyplot.gcf() と pyplot.gca() でアクティブな Figure と Axes を取得しながらプロットを処理します。