【Python】matplotlibで論文に使えるきれいなグラフを作る

# はじめに

発表や論文に載せる用のグラフはきれいに作らなければならなく、手軽に使える**エクセル**よりは、**Ngraph**や**gnuplot**などのソフトを使うことが多いと思います。
しかし、**Pythonユーザーにはぜひmatplotlibを使用してグラフを作成してほしい**と思います。
実際にエクセルで何も考えずに作ったグラフと、本記事の設定でPythonの`matplotlib`ライブラリを使用して作成したグラフを以下に示します。

![描画-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/404b7f66-b02f-7b26-e3f3-39f59f06326e.png)





とはいっても`matoplotlib 論文`で検索するとある程度の解説しているページが出てきます。
そのため、本記事では以下を中心にまとめてみます。
* 色々調べてたどり着いたよく使うグラフの設定一覧
* グラフのサイズ・比率について
* きれいに見える軸の設定方法
* 保存について



# 全般のグラフの見た目の設定

`matplotlib`のデフォルトの見た目も悪くないですが、論文用にグラフの見た目を一括で変更します。
以下が、重要な設定をまとめたもので、細かい調整をしたい時用の設定はコメントアウトしています。
グラフを作成する前にこちらをコピペすると一気に見た目が変わります。

```python
import matplotlib.pyplot as plt

#フォント設定
plt.rcParams['font.family'] = 'Times New Roman' # font familyの設定
#plt.rcParams['mathtext.fontset'] = 'stix' # math fontの設定
plt.rcParams["font.size"] = 15 # 全体のフォントサイズが変更されます。
#plt.rcParams['xtick.labelsize'] = 9 # 軸だけ変更されます。
#plt.rcParams['ytick.labelsize'] = 24 # 軸だけ変更されます


#軸設定
plt.rcParams['xtick.direction'] = 'in' #x軸の目盛りの向き
plt.rcParams['ytick.direction'] = 'in' #y軸の目盛りの向き
#plt.rcParams['axes.grid'] = True # グリッドの作成
#plt.rcParams['grid.linestyle']='--' #グリッドの線種
plt.rcParams["xtick.minor.visible"] = True  #x軸補助目盛りの追加
plt.rcParams["ytick.minor.visible"] = True  #y軸補助目盛りの追加
plt.rcParams['xtick.top'] = True  #x軸の上部目盛り
plt.rcParams['ytick.right'] = True  #y軸の右部目盛り


#軸大きさ
#plt.rcParams["xtick.major.width"] = 1.0             #x軸主目盛り線の線幅
#plt.rcParams["ytick.major.width"] = 1.0             #y軸主目盛り線の線幅
#plt.rcParams["xtick.minor.width"] = 1.0             #x軸補助目盛り線の線幅
#plt.rcParams["ytick.minor.width"] = 1.0             #y軸補助目盛り線の線幅
#plt.rcParams["xtick.major.size"] = 10               #x軸主目盛り線の長さ
#plt.rcParams["ytick.major.size"] = 10               #y軸主目盛り線の長さ
#plt.rcParams["xtick.minor.size"] = 5                #x軸補助目盛り線の長さ
#plt.rcParams["ytick.minor.size"] = 5                #y軸補助目盛り線の長さ
#plt.rcParams["axes.linewidth"] = 1.0                #囲みの太さ


#凡例設定
plt.rcParams["legend.fancybox"] = False  # 丸角OFF
plt.rcParams["legend.framealpha"] = 1  # 透明度の指定、0で塗りつぶしなし
plt.rcParams["legend.edgecolor"] = 'black'  # edgeの色を変更
plt.rcParams["legend.markerscale"] = 5 #markerサイズの倍率

```

以下のプログラムにこの設定を適用する前と後のグラフを示します。

```python
plt.figure(dpi=300)
plt.plot([0.1,0.9], [0.1,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()
```

![ビットマップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/6624de60-3318-5899-05f8-8fbe8a1bd584.png)

なんとなく論文に載ってそうなグラフになってきましたね。
フォントや全体のサイズなどは自分に合ったものを選んで使用してみてください。
フォントの種類などは`plt.rcParams font family`などと調べたら山ほど出てくると思います。


### 参考にしたサイト

なお、こちらの設定は以下のサイトを参考にしました。
ありがとうございました。

https://qiita.com/MENDY/items/fe9b0c50383d8b2fd919

https://qiita.com/Nick_utuiuc/items/9bf839f5612c54606348

https://phst.hateblo.jp/entry/2020/02/28/000000

https://qiita.com/M_Kumagai/items/b11de7c9d06b3c43431d

https://python-academia.com/matplotlib-rcparams/





# グラフのサイズ


グラフの縦横比は白銀比の`1：1.4`や黄金比の`1：1.6`が望ましいといわれています。また、正方形の`1：1`もたまに見ます。
一方`matplotlib`のデフォルトはドキュメントを調べると`4.8：6.4`すなわち`1：1.33`と出てくるのですが、`plt.rcParams["figure.figsize"]`で調べると`4：6`すなわち`1：1.5`になっているみたいです。
今回は白銀比の`1：1.4`で進めていこうと思います。


![ビットマップ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/7a9404ef-f328-1941-6ee0-47fb16a5e46a.png)




なお、コードはこちらになります。
`figsize`の値は**インチ**であるらしく、比率が同じでも値が大きくなると文字が相対的に小さくなるので注意してください。
```python
#デフォルト
plt.figure(dpi=300)
plt.plot([0,0.9], [0,0.9], label="line")
plt.title("デフォルト")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()

#白銀比
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()


#黄金比
plt.figure(dpi=300, figsize=(1.618*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()

#正方形
plt.figure(dpi=300, figsize=(4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()
```



# 軸設定


これまでのグラフでは、軸の数値は自動でmatplotlibが設定していました。
しかしきれいなグラフは**枠の端に数値が来る**必要があります。
さらに、右上に伸びるグラフでは**右上にスペースを空ける**ときれいに見えます。
そこで、`plt.xlim`及び`plt.ylim`で軸の範囲を設定します。
さらに、軸に使用する数値だったり、文字を指定することもできます。
![描画2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/ec5d4593-823e-773a-1a05-d7b773419d5c.png)

このグラフを作成したコードはこちらです。
```python
import numpy as np

#軸範囲指定なし
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")
plt.legend()
plt.show()


#軸範囲指定あり
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")

plt.xlim(0, 1) #x軸範囲の指定
plt.ylim(0, 1) #y軸範囲の指定

plt.legend()
plt.show()


#軸目盛りを指定
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")

plt.xlim(0, 1) #x軸範囲の指定
plt.ylim(0, 1) #y軸範囲の指定
plt.xticks(np.arange(0, 1.1, 0.5)) #x軸目盛りの指定
plt.yticks(np.arange(0, 1.1, 0.1)) #y軸目盛りの指定

plt.legend()
plt.show()


#軸目盛りを文字で指定
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")

plt.xlim(0, 1) #x軸範囲の指定
plt.ylim(0, 1) #y軸範囲の指定
plt.xticks([0,0.9], ["point1", "point2"], rotation='vertical') #x軸目盛りの指定
plt.yticks([0,0.5,1], ["min","ave","max"]) #x軸目盛りの指定

plt.legend()
plt.show()
```

文字で指定することについてはこちらにドキュメントがあります。

https://matplotlib.org/stable/gallery/ticks/ticklabels_rotation.html#sphx-glr-gallery-ticks-ticklabels-rotation-py



# 保存
次に、作成したグラフを保存する方法について説明します。
保存する際は、`plt.show()`の前に`plt.savefig(ファイル名)`で保存できます。

私の場合、普段以下のようにして保存しています。
```python
plt.figure(dpi=300, figsize=(1.414*4, 4))
plt.plot([0,0.9], [0,0.9], label="line")
plt.xlabel("X label")
plt.ylabel("Y label")

plt.xlim(0, 1) #x軸範囲の指定
plt.ylim(0, 1) #y軸範囲の指定

plt.legend()
plt.tight_layout()
plt.savefig("test.png", format="png", dpi=300, transparent=True)

plt.show()
```

以下、詳しく引数などについて説明していきます。

## 余白
`plt.tight_layout()`とすることで、余白を小さくできます。
スライド等で図を入れるときにトリミングしなくてよくなり、扱いやすくなります。

## ファイル形式
ファイル名で拡張子を指定するか、`format="png"`などとすることでファイルの形式を変えることもできます。
画質を下げたくない場合は`png`、ファイルサイズを抑えたいときは`jpeg`、latexで埋め込むなら再コンパイルしなくていい`pdf`、ベクターの画像としていじりたいなら`svg`という使い分けがいいでしょう。
他にも対応しているファイル形式はあるので調べてみてください。

## 解像度
今回のプログラムでは`plt.figure(dpi=300)`とfigureを作るタイミングで解像度を決めていましたが、保存時にも指定できます。
`plt.savefig(ファイル名, dpi=300)`などの引数を指定することで解像度を変更することもできます。

## 透明度
`transparent=True`という引数を指定することで背景を透明にすることができ、スライド等で使用しやすくなります。
なお、`jpg`などでは透明度をデータとして持てないので透明にできないので注意してください。



## 他の引数

他の引数についてはドキュメテーションを読んでください。
メタデータの指定など細かくできます。

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html



# 他にできること

今回紹介した方法は私が普段一番多く使用する方法で、他にも対数軸や指数表記、色を変えたり散布図や棒グラフを作るなどいろいろなことができます。
matplotlibについての記事は調べたら山ほど出てくるので、ぜひ調べてみてください。



# 【最終手段】matplotlibの外でいじる

`matplotlib`内の機能のみでグラフを作っていても、デザインやレイアウトなどでいずれ限界が来ます。
そんな時は、`svg`の形式で画像を保存し、`Inkscape`などのベクターのソフトでいじるという手があります。
それぞれのオブジェクトはレイヤー化されたベクターデータとして出力されているため、無劣化で変えることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/2ceb08ca-50d9-f345-c8cb-1744d0875fea.png)




# 最後に

本記事では、論文に載せられるグラフを目指して`matplotlib`を使用してグラフを作成する方法を解説しました。
しかし、私もまだまだグラフ作成については未熟なので、間違いなどあるかもしれません。
もし、間違いやコメント、きれいなグラフを作る他の観点などありましたら是非コメントをください。
よろしくお願いいたします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/993303/44c20a1f-91c1-5dfb-9bc4-64ee0a240347.png)