こんにちは,米国データサイエンティストのかめ(@usdatascientist)です.
データサイエンスのためのPython入門第22回です(講座の目次はこちら).今回は,前回学習したfigureオブジェクトでグラフをplotし,そのplot結果をpngとpdfで保存する方法を紹介します!
(「データサイエンスのためのPython講座」動画版がでました!詳細はこちら)
実際の業務では,「Jupyterでグラフを出して終わり」ということはなく,基本的にpngやpdfで保存するところまでやります.
特に画像を扱っていると,大量の画像を並べて保存する必要があったりするので,pngだけでなくpdfでの保存が必要になったりします.
どちらも操作は似ていますし,必要なコードは1~4行です(本当に素晴らしい).それでは,解説していきます!
目次
グラフの大きさを調整する
保存の方法を学ぶ前に,グラフの大きさを調整する方法を紹介します.保存してみてグラフが小さかったら嫌ですよね?
グラフの大きさを調整するには,figureオブジェクトを作る際に,figsize引数およびdpi引数を指定します.(オブジェクト指向を使ったmatplotlibの説明は前回の記事を参考にしてください.)
今回はplt.subplots()を使ってplotします.前回同様,指数関数をplotします.指数関数の作り方については第9回を参照ください.
1 2 3 4 5 6 7 8 9 |
import numpy as np import matplotlib.pyplot as plt %matplotlib inline x = np.linspace(-3, 3, 10) y1 = np.exp(x) y2 = np.exp(x)*2 fig, axes = plt.subplots() axes.plot(x, y1) |
これがノーマルなオブジェクト指向でのplotの仕方です.
それでは,figsize引数とdpi引数を使ってグラフのサイズを変えてみましょう.figsizeにはタプルで(横幅,高さ)をインチ数で指定します.dpiというのは,Dots per inchです.1inchの中に何ドット入るかということですね.つまり,figsizeで指定したインチ数xdpiがドット数になります.
すこしややこしいかもしれませんが,実際にはdpiはデフォルトの値を使って,figsizeのみでサイズを変更します.
1 2 3 |
# この場合モニタで100画素 x 100画素のグラフが表示される fig, axes = plt.subplots(figsize=(1, 1), dpi=100) axes.plot(x, y1) |
実際にはdpiを指定する場面はないので,dpiはjupyterのデフォルトを使用すれば問題ないでしょう.
figsizeで縦横比を指定したり数を調整することでサイズを変えます.
1 2 |
fig, axes = plt.subplots(figsize=(10, 3)) axes.plot(x, y1) |
こんな感じです.簡単ですね〜
pngで保存する
これは一番手軽で一番使います.簡単です.figureオブジェクトのsavefig()関数を呼ぶだけです.引数にファイル名(パス)を指定します.
今回は前回学習した複数のグラフを並べて表示して保存してみます.今回はカレントディレクトリに’savefig_sample.png’として保存します.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
fig, axes = plt.subplots(2, 1, figsize=(10, 3)) axes[0,].plot(x, y1) axes[1,].plot(x, x*x) axes[0,].set_title('first') axes[1,].set_title('second') axes[0,].set_xlabel('x') axes[0,].set_ylabel('y') axes[1,].set_xlabel('x') axes[1,].set_ylabel('y') fig.savefig('savefig_sample.png') |
pngで保存するときは通常,グラフのタイトルや軸のラベルをつけて保存します.この辺りについては前回と前々回の記事で解説しています.
グラフを複数並べたりタイトル,軸のラベルをいれると,軸のラベルとタイトルがかぶったりして見にくくなります.
plt.tight_layout() をコールすることでこの辺をいい具合に調整してくれます.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
fig, axes = plt.subplots(2, 1, figsize=(10, 3)) axes[0,].plot(x, y1) axes[1,].plot(x, x*x) axes[0,].set_title('first') axes[1,].set_title('second') axes[0,].set_xlabel('x') axes[0,].set_ylabel('y') axes[1,].set_xlabel('x') axes[1,].set_ylabel('y') plt.tight_layout() fig.savefig('savefig_sample.png') |
綺麗ですよね!
保存したら,Jupyterの左側のファイルナビゲーションでファイルが保存されていることを確認しましょう.ダブルクリックで開いて中身を見ることもできます.
また,もし複数のグラフを一つにまとめて描画する場合は,凡例をつけて保存するのが一般的です.(この辺りについては第20回でも説明してます.)
凡例をつけるには axes.legend() でOKでした.(前回記事参照)
1 2 3 4 5 |
fig, axes = plt.subplots() axes.plot(x, y1, label='first') axes.plot(x, y2, label='second') axes.plot(x, y1+y2, label='first + second') axes.legend() |
legend() にloc引数を入れることで,凡例の位置を変更できます.デフォルトだと’best’になっていて,良さげなところに置いてくれます.
文字列を指定しても,数字を指定してもOKです.JupyterでShift+Tabで以下の表をリファレンスで確認することができます.(Jupyter操作については第2回を参照)
=============== =============
Location String Location Code
=============== =============
‘best’ 0
‘upper right’ 1
‘upper left’ 2
‘lower left’ 3
‘lower right’ 4
‘right’ 5
‘center left’ 6
‘center right’ 7
‘lower center’ 8
‘upper center’ 9
‘center’ 10
=============== =============
pdfで保存する
大抵のケースではpngで保存できればいいと思いますが,時々pdfで保存したいケースがでてきます.特に以下のようなケースです.
- 大量のグラフをfor文で回した結果を保存したい(グラフよりも画像であることが多いです)
- titleなどにIDをつけて,あとでコピーできるようにしたり,ctrl+Fで検索できるようにしたい
「自分にはまだいらないかな」と思ったら飛ばしてください.必要な時に戻って読んでくださいね
pdfで保存するには, matplotlib.backends.backend_pdf.PdfPages クラスを使います.
覚える必要ないです.私も覚えてません.毎回昔書いたコードからコピッたりググってます.
みなさんも業務で作る際にはこのページに来て,毎回コピーして貼り付ければOKです.
それではまず,PdfPagesを以下のようにimportします.
1 |
from matplotlib.backends.backend_pdf import PdfPages |
これでスクリプトの中でPdfPagesクラスを使えるようになります. PdfPages() にpdfのファイル名(パス)を入れて pdf というインスタンスを作成します.
1 |
pdf = PdfPages('savefig_sample.pdf') |
(先ほどの例では拡張子がpngでしたが,今回はpdfであることに留意しましょう.)
インスタンスを作ると,新しく「savefig_sample.pdf」というファイルが作成されているのがわかるかと思います.(Jupyterで画面左側を見てみてください)
pdfインスタンスを通じて,このファイルにいろんなことができちゃう!という仕組みです.(オブジェクト指向すごい)
といっても大体やることは保存するくらいなので,保存してみます!
グラフは先ほどのコードのまんまです.保存するには pdf.savefig() に,figureオブジェクトをいれるだけです.pngの時に似ています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# PdfPagesをimport(覚える必要なし,コピペで使い回す) from matplotlib.backends.backend_pdf import PdfPages # pdfインスタンス作成.この時点でファイルができる pdf = PdfPages('savefig_sample.pdf') #------グラフ作成-------- fig, axes = plt.subplots() axes.plot(x, y1, label='first') axes.plot(x, y2, label='second') axes.plot(x, y1+y2, label='first + second') axes.legend(loc=0) #----------------------- #pdfに保存 pdf.savefig(fig) #close処理(一応やる) pdf.close() |
pdfインスタンスは常にpdfファイルを開いて更新できる状態にあるので,処理が終わったらclose()をコールして閉じましょう.
きちんとsavefig_sample.pdfが更新されているか確認してください.
大量のグラフをpdfで保存する
pdfで保存する際の一番の利点は「大量のグラフを一つのファイルで保存」できることです.
試しにグラフをfor文で回してpdfに保存してみましょう.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pdf = PdfPages('savemultifig_sample.pdf') for i in range(0, 10): #------グラフ作成-------- fig, axes = plt.subplots() #グラフの形状が徐々にかわるように設計しました.(適当です.) axes.plot(x, y1 + x*i) #タイトルをつけます.pdfで文字検索ができることを確認してください. axes.set_title('ID:#{}'.format(i)) #----------------------- #forループのなかで保存 pdf.savefig(fig) #ループ後に閉じます pdf.close() |
savemultifig_sample.pdfが保存されていると思います.そのpdfを開いてみてください.1ページに1グラフ描画されているはずです.
試しにctrl+Fで「#4」と検索してみてください.ID#4のグラフにすぐに飛べます.
これ,すごく便利なんですよね・・・特に画像を扱っていると1000枚くらいの画像やその関連グラフを一気にfor文で回してこのように一つのpdfにすることができます.
しかも文字列検索ができるので必要なデータにすぐアクセスできます.
ぜひ業務で使ってみてください!(データが大きすぎるとpdfが壊れてしまうこともあるようです.その辺のサジ加減は適度に・・・)
まとめ
今日学んだことをまとめます!とにかく今後は,subplots()を使って,オブジェクト指向でグラフをplot することに慣れるといいと思います.
- plt.subplots(figsize=(w, h)) で図のサイズ変更
- fig.savefig('パス/ファイル名.png') でpngで保存
- plt.tight_layout() でplot同士の重なりを解消
- axes.legend(loc='best') :loc引数で凡例の位置を変更
- from matplotlib.backends.backend_pdf import PdfPages でimportして pdf = PdfPages(ファイル名) でpdfインスタンス作って pdf.savefig('パス/ファイル名.pdf') でpdfファイルを保存します.処理がおわったら pdf.close() で閉じましょう
- pdfでの保存は,大量のグラフや画像のplotを保存したり文字列検索ができるのがメリット
こんな感じです.pngでの保存は必修だと思うので覚えましょう.pdfは余力があったらやってみてください.
それでは!
追記)次回記事書きました!次回はほかにも色々なグラフを書いてみましょう!