環境システム株式会社公式HP

〒660-0083 兵庫県尼崎市道意町7-1-3
尼崎リサーチ・インキュベーションセンター512

アイコン06-6657-5130

アイコンsales@hydrolab.co.jp

お問い合わせ

アイコン06-6657-5130

アイコンsales@hydrolab.co.jp

お問い合わせ

蛇使いな彼女BLOG

【第33回】 pythonのグラフ描画①

2021.04.16

こんにちは皆さん!
最近のモトハシですが、この前受けたデータ図化の仕事で見た目の調整がややこしく、手こずったものがありました。
図化はあまり得意ではないので正直「どうしよう…」と不安でしたが、何とか無事に終わりました…。

さて、そんなこんなで今回から3回に分けてデータ可視化のためによく利用するMatplotlibseabornについて基本的な情報と、実際に図を描画するときの構文を紹介していこうと思います!
次回と3回目はMatplotlibとseabornについて、グラフをカッコよくするために”軸目盛の調整”に重点を置いて説明していくので、よろしくお願いします。

■MatplotlibとSeabornについて

まず、Pythonにおいてデータの可視化に使用するライブラリはMatplotlibSeaborn。大きく分けてこの2つです。

MatplotlibNumpy配列で構成されたマルチプラットフォーム(WindowsやMacなど、異なるOS環境でも動作可能)なデータ可視化用ライブラリで、2003年にリリース後、宇宙望遠鏡科学研究所(Space Telescope Science Insitute,STScI)がグラフ描画パッケージに選定したことをきっかけに財政支援を受け、広く知られることになりました。

対してSeabornは、近年Matplotlibの描画スタイルがやや古臭くなりつつある風潮を受け、より現代的なスタイルを提供するための新しいパッケージとして開発されました。
SeabornPandasのデータ構造と緊密に統合可能だそうです。
(プログラミングの世界にもトレンドがあるんですね!)

また、Matplotlib=「古臭い」 Seaborn=「現代的」なイメージですが、これはもっぱら図のスタイルを指します。
構造的な部分でも、MatplotlibPandasのDataFrameを使うように設計されていない事や、統計データの可視化には向いていない問題からSeabornが開発されましたが、機能的な面でMatplotlibSeabornに劣っているわけではなく、Matplotlibに足りない部分をSeabornが補っているという様な見方が正しいかと思います。

このような特徴から、MatplotlibSeabornはある意味ワンセットです(笑)
いずれにせよMatplotlibが可視化用ライブラリの中心にあることから、Matplotlib構文の理解は不可欠なので、これから基本構造を説明します。

まず、可視化したグラフの簡単な構造を図で示していますが、このようにfigure(白紙)にaxesと呼ばれる(プロット領域、軸ラベル、軸目盛などを含む)青い領域で構成されています。

この構造はImport matplotlib.pyplot as plt として、
plt.plot(x,y)
plt.show()

を実行すればfigureとaxesの操作をせずとも可視化&確認ができます。
また、plt.plot() の( )に何か適当な数値x、yを代入してやれば、これだけで簡単にグラフが描けます。
ですが、pltコマンドを使ってグラフを書くことは初心者でも扱いやすい(私もよくやっていました)反面、おすすめはしません。
1つのfigureに対して1つの座標軸にグラフを作る場合はpltを使うのもありですが、例えば1つのfigureに対して複数の座標軸(axes)にグラフを描画したい場合など、より複雑なグラフを作らなければいけない際、pltの特性上、異なる座標軸に自由にアクセスできないからです。

後の調整や操作のしやすさや、構造の理解に役立つといった点でもfigure/axesを使ったオブジェクト指向な記述にぜひ慣れてください。

■Matplotlibによる可視化

Matplotlibの図化は文法構文(順番)に気を付けないとうまく描画できない事が多くあります。
先に説明したpltコマンドを使って複雑な図を描こうとすると特に、思うような図が描けないジレンマに陥りますしね(゜-゜)

また、グラフの見た目調整のためのツールが数多く存在するためか、コーディングの仕方は何通りか方法があるので、ネットを参考にすると人によって書き方が違う事があります。
ですが、それも何度も写経をしていくうちに、構造的なものが見えてくるはずです。

…と、話が長くなるのでここから本題です。

【使用データ】
使用するデータは、自動昇降機をつかって測定したS湖の水質データです。

↓縦方向に水深、
→横方向に時間です。
左端1列目はインデックスで水深(0~6m)を表していて、2番目の列から水温の値です。
列名はありませんが、右端に行くほど新しい日付のデータになります。


● EN=データ読み込み時にエラーが発生したファイルのインデックス

Pandasでデータを1つずつ読み込む際に、項目数の乱れが原因でエラーが出た箇所です。
例えば、tempの0番目(=一番左の水深列を除く2列目のどこかの行)でエラーが出ているのが確認できます。


● Date=日付データ

tempの列名として扱うデータ。

※生データ→可視化用データ に編集するコードはこちら[リンク]

■Matplotlibを使った線グラフと散布図

ここでは、figureと axesの生成を分けて行っています。
ax = fig.add_subplot(111) でfigureの1行1列目の1番目にaxという変数名の座標軸(axes)を配置した後、ax.plot()で線グラフの描画、ax. plot_date()で線グラフの上に散布図の描画を行っています。


*線グラフの描画
fig = plt.figure(figsize = (8, 5))
ax = fig.add_subplot(111)

x=date         # 日付時刻
y=temp[0,1:]         # 最表層(水深0m)の水温

ax.plot(x,y,color='k', label='water temperature') # 時系列plot

*同じ座標軸に散布図を追加
# エラー箇所を重ねて表示
ex=[x[i] for i in EN]
ey=y[EN]

#ax.scatter(ex,ey,label='Unreliable data',color='r',alpha=0.5) # Error発生
ax.plot_date(ex,ey,label='Unreliable data',color='r',alpha=0.5) # 推奨

# 凡例の追加
plt.legend(loc='lower right')
plt.show()


※ちなみに、散布図を描画するときはたいていax.scatter()を使うのですが、今回使用したデータが数値ではなく、x軸が日付データの為ax.scatter()はエラーを返します💧
こういう臨機応変さのないところが古臭いと言われるのでしょうか…(笑)


次に、figureと axesの生成を一度に行う方法です。
plt.subplots(2,1,…)とありますが、こう記述することで同じ大きさの描画領域を行方向に2つ作成できます。
さらに、sharex/shareyをTrueにすることでx軸とy軸を共有しています。

*複数の座標軸にグラフを描画
fig,(ax1,ax2)=plt.subplots(2,1,sharex=True,sharey=True,figsize=(8, 5))

x=date # 日付時刻
y=temp[0,1:] # 最表層の水温

# 時系列グラフを1番目のグラフに表示
ax1.plot(x,y,color='k',label='water temperature')

ex=[x[i] for i in EN]
ey=y[EN]

# エラー箇所を2番目のグラフに表示
ax2.plot_date(ex,ey,label='Unreliable data',color='r',alpha=0.5)

plt.legend(loc='lower right')
plt.show()

あれ?上の線グラフに凡例がついていない??
…この原因部分は
plt.legend(loc=’lower right’)
pltコマンドは座標軸が複数ある場合、思った通りに動いてくれない事があります。

凡例を両方とも表示するには例えばこんな風に書きます。

fig,(ax1,ax2)=plt.subplots(2,1,sharex=True,sharey=True,figsize=(8, 5))

…(省略)

ax1.plot(x,y,color='k',label='water temperature')
ax1.legend(loc='lower right')

ax2.plot_date(ex,ey,label='Unreliable data',color='r',alpha=0.5) # 推奨
ax2.legend(loc='lower right')

plt.legend(loc='lower right')
plt.show()

補足ですが、同じpltコマンドでもplt.show()はaxesではなくアクティブな状態のfigureを検索して表示させるコマンドなので、ちょっと特別です。
書籍などにはplt.show()は「スクリプトの最後に一度のみ実行します」などと書かれていることもありますが、モトハシのようにそれを鵜呑みにしてfor~構文などで何個もfigureを作っていると、最後にshowしたときにそれらが一度に書き出されて大変焦ります(笑)

当然メモリにも負担を掛けているので、フリーズすることもしばしばありました。

モトハシも学習して、今はこれを防ぐために
plt.show()させずにfig.savefig()としてローカルに保存させた後、plt.close()と書いてウインドウを閉じたりしています。

可視化の全体の流れとしては
① Figure・axesの作成
② データ描画
タイトル/軸/目盛/テキスト等の設定
③ グラフの(Show/savefig)

大雑把に言えばこんな感じです。
この通り可視化自体はとてもシンプルなコードでできます!
3つの要素にいろんな設定が追加されると複雑になってきますが、それは次回とします。

今日はMatplotlibのfigure、axes構造に着目したお話でした。


[参考書籍]
※Pythonデータサイエンスハンドブック―
Jupyter,Numpy,pandas,Matplotlib,scikit-learnを使ったデータ分析、機械学習 / (株)オーム社

pagetop