Matplotlibはややこしい

Pythonでグラフを描くなら、Matplotlibの使用は避けて通れません。「Python グラフ」などで調べると、ほぼ確実にplt.plotなどMatplotlibの関数を見ることになるでしょう。

しかし、いざMatplotlibを使ってみようとしても、思ったように動作しないことが多いです。ネットからサンプルコードを探して、同じようにスクリプトを書いてみても、変なグラフができてしまったり、グラフが表示されないなどのトラブルに見舞われることがあります。


いったいなぜ、このような事態が起こるのでしょうか。それはもしかすると、Matplotlibに潜む「ややこしさ」が原因かもしれません

本記事では、Matplotlibが持つ3つの「ややこしさ」について紹介します。Jupyter notebookでMatplotlibを動かすにあたって、これらを注意すれば上記のトラブルに遭遇する確率は減るかもしれません…。


1. plt.plotとax.plotの違い


Matplotlibをネット検索してみると、plt.plotでグラフを描く方法と、ax.plotでグラフを描く方法の2種類が存在することに気づくでしょう。

どうやら、Matplotlibには2種類の書き方の流派が存在するようですplt.plotMATLABでの書き方を模したもので、ax.plotオブジェクト指向的な書き方となっています。


どちらが良い書き方なのかは正直判断できませんが、ax.plotの方は画像情報をオブジェクトとして保存でき、必要に応じて加筆なども可能なので、こちらの書き方のほうが自分には合ってそうです。plt.plotの方は、Jupyterのセルを跨いだときにどのように動作するのか予想できない怖さもあるので。


import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(2,1)
axes[0] = axes[0].plot(x, np.sin(x))
axes[1].plot(x, np.cos(x))


f:id:emoriiin979:20210114233948p:plain


オブジェクト指向的にMatplotlibでグラフを描画するには、上記のようにコードを書きます。ちなみに、figaxesというのはMatplotlibにおけるFigureクラスとAXESクラスを指します。これらが何者なのかはこの記事で詳しく説明されています。


2. Pandasのdf.plotの存在


いくつかの記事では、PandasのDataFrameをグラフ化する際に、DataFrameクラス自身が持つplotメソッドを使用していることがあります。実はこちらもMatplotlibで実装された機能なのですが、これは上記のMatplotlibの流派とどのように関わってくるのでしょうか。


このdf.plotですが、上記のfigaxesと組み合わせて使うことができます


import pandas as pd
from sklearn import datasets

iris = datasets.load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)

fig, axes = plt.subplots(1, 2, figsize=(8,4))
df.plot(ax=axes[0])
df.plot(ax=axes[1], kind='hist')


f:id:emoriiin979:20210115000242p:plain


df.plotにはaxesを指定する引数が用意されています。ここに、作成済みのaxesオブジェクトを指定すれば、そのaxesdf.plotのグラフを格納することができます。


3. Jupyterでのfigure表示


Jupyter notebookでMatplotlibの画像を表示させるには、%matplotlib inlineというマジックコマンドを入力しなければならないと、調べると出てくると思います。しかし、%matplotlib inlineを入力しなくても、画像が勝手に表示されてしまうという経験がある方もいるでしょう。

それは、もしかするとMatplotlib backendのデフォルト設定が「inline」になっているからかもしれませんGoogle Colabでは、%matplotlib inlineを指定しなくてもbackendが「inline」に設定されていました。


f:id:emoriiin979:20210115001039p:plain


Backendが「inline」になっていると、plt.show()を記述しなくても作成されたcurrent figureが表示されます。current figureplt.subplots()figが作られたときに格納され、plt.show()で表示できます。

すなわち、Google ColabでMatplotlibを使う場合は、特にplt.show()を書かなくても、勝手にcurrent figureが表示されます。もし、画像を表示したくないときはplt.close()を使います。


ちなみに、current figureではないfigを表示したいときは、Jupyterではdisplay関数で見ることができます。


fig, axes = plt.subplots(2,1)
axes[0] = axes[0].plot(x, np.sin(x))
axes[1].plot(x, np.cos(x))
plt.close()

display(fig)


f:id:emoriiin979:20210114233948p:plain


まとめ


本記事では、Matplotlibに潜む3つのややこしさについて紹介しました。


  • Matplotlibの書き方には、plt.plotax.plotの流派が存在する
  • 上記の流派とは別に、'df.plot'という書き方も存在する
  • JupyterでMatplotlibの画像がいつ表示されるのかが分かりづらい


上記のややこしさに対して、本記事では下記のような解決策を選択しました。


  • オブジェクト指向的なax.plotの方が使いやすい
  • df.plotは既存のaxesオブジェクトを引数に指定できる
  • Google Colabではinline指定は不要で、plt.close()display関数などで表示のタイミングを指定できる


上記のややこしさを解消できれば、ネットに転がっているサンプルコードもより理解できるようになるでしょう。ぜひ参考にしてみてください。

以上です。