現役理系院生が研究で使用したPythonの可視化ツール全部まとめてみた[応用編]


#前回の続きです
この記事はPythonの可視化ツールの応用編です。
~~長くなってしまったので応用編は2つに分けることにしました。(応用編2はまだ執筆中です)~~
応用編はこの記事に加筆して1つにしました。
Pythonのplotに慣れていない方は基礎編を前回書きましたので[こちら](https://qiita.com/coffiego/items/52315ea45fcc6d83b5b9)をぜひ！
#はじめに
現在修士2年の大学院生です。
火星大気を数値シミュレーションを使って研究しています。
数値シミュレーションで得られた結果を主にPythonを使って解析していたので、その過程で使った関数などを全部まとめてみました。全てを網羅しているわけではありませんのでそこはご注意ください。。。
ただドキュメントを見て格闘して使ってきたので、これからもしPythonの可視化ツールを使う人いれば、その助けになればと思いまとめてみました！


#この記事でできること

#####・カラープロット(pcolor)
#####・x軸を共有してy軸を右と左に設定する
#####・x軸は同じでグラフを縦に並べる
#####・アニメーション(gifファイル作成)

以下は今度別の記事(今度執筆します)で解説します
- csvファイルの読み込み書き出し
- HDF5ファイルの読み込み、書き出し
 
#使うライブラリー
この記事で使うライブラリーは以下になります。ひとまず以下のコードをコピペしてコードの上に貼っておけば問題ないです。

```python
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理
from matplotlib.colors import LogNorm #color barをlog
from matplotlib import animation as animation #gifファイルを作成
```

#カラープロット(pcolor)の使い方
そもそもカラープロットで何？という方が多いと思うので、以下のグラフのように3次元のデータを2次元のカラーマップで表現したものです。~~せっかくなのでアーティスティックな顔に、、、笑~~
<img width="1027" alt="Screen Shot 2020-03-20 at 13.26.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199901/1ecfaf20-3040-3ce2-641e-b683e431a0f7.png">


pcolorを使ったグラフ描画の構造&解説です。(コピペして使ってください)

```python
#pcolorの構造

#1
#x軸,y軸のデータを用意してmeshする
#おそらくplotしたい3次元データの(x,y)成分があると思います。
#ex) x = y = np.arange(-10, 10, 0.5)
X, Y = np.meshgrid(x, y) #このX,Yはそれぞれlen(x)*len(y)の行列になります。

#2
#Zを作成する。
#plotしたいデータがある場合は、
#ステップ1で作ったX,Yと同じサイズの行列Zを作成します。(csvから読み込むなどして行列にする)
#ない場合(今回のサンプル)
#Z=f(X,Y)として関数を書く
#ex) 
Z = np.exp(-X**2-Y**2)

#データに抜けがあってその範囲をマスクしたい場合(必要ならuncomment)
#Z = np.ma.masked_where(np.isnan(Z), Z)#noneの場所をマスクします

#3
#plotする
fig, ax = plt.subplots(dpi=100) #dpi:解像度

#color mapを作成
c=ax.pcolor(X,Y,Z,cmap='好きなcolor map', vmin=最小値, vmax=最大値)
#c=ax.pcolor(X,Y,Z, norm=LogNorm(最小値, 最大値),cmap='好きなcolor map') #logスケール ver

#color barを追加する
cax = fig.colorbar(c, ax=ax) #color barを追加する

#マスクした場所を斜線で塗りつぶす(必要ならuncomment)
#ax.patch.set(hatch='x', edgecolor='black')
```
イメージしづらいと思うので、例えばサンプルコードのXは,
X=
<img width="410" alt="Screen Shot 2020-03-20 at 14.35.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199901/25702360-d520-d0ff-c644-b8590e186c39.png">
len(x)*len(y)の行列になっています。
Zも同じ大きさの行列で座標(x,y)のz値が要素として構成されています。

pcolor関数は、

```python
c=ax.pcolor(X,Y,Z,cmap='好きなcolor map', vmin=最小値, vmax=最大値)
```
・cmap='color map種類'でどんな配色にするか指定することができます。[この公式ドキュメント](https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html)にたくさん載っています。
・vmin, vmaxに色をつけたい範囲を決めることができます。
つまり、z値がvmin~vmaxまでピクセルに色が付きます。



pcolorで書いた顔のサンプルコードです。

```python
#pcolor
from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理

x = y = np.arange(-10, 10, 0.5)
X, Y = np.meshgrid(x, y)#メッシュして行列作成
#顔の目と鼻と口を表現する関数
Z = np.exp(-(X+5)**2 - (Y-3)**2)+np.exp(-(X-5)**2-(Y-3)**2)+np.exp(-(X)**2-(5*(Y+5))**2)+np.exp(-(10*X)**2-(5*Y)**2)
fig, ax = plt.subplots(dpi=200)
#pcolorでプロット
c=ax.pcolor(X,Y,Z, norm=LogNorm(1e-4, 1),cmap='Set3')
cax = fig.colorbar(c, ax=ax,shrink=0.9)
```

#x軸を共有してy軸を右と左に設定する
こんなグラフです。
<img width="598" alt="Screen Shot 2020-03-18 at 23.24.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199901/e15bed5b-f205-3bfb-fcf5-c5ec855a1714.png">


x軸を共有するときは以下のような構造にすればOKです。(コピペ用)

```python
fig, ax1 = plt.subplots(dpi=100)
##ここにax1のplotを書く
#ax1.plot(...)
#ax1.set_??

ax2 = ax1.twinx()#これでx軸を共有できる!!!
##ここにax2のplotを書く
#ax2.plot(...)
#ax2.set_??
```

以下サンプルコードです。

```python
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理
def fun(x): 
    y = 2**x #ここに自分の関数を書く
    return y
#prepare x,y data
X = np.linspace(1,10,num=100)
Y1 = fun(X)
Y2 = np.exp(X)

#左のy軸用のplot
fig, ax1 = plt.subplots(dpi=100)
ax1.plot(X,Y1,color='g',label=r'$y=2^x$', linestyle='-.',)
ax1.set_xlabel('xaxis')
ax1.set_ylabel("yaxis1")
ax1.set_ylim((0,100))
ax1.tick_params(axis='y')
ax1.legend(loc="upper left")

#右のy軸用のplot
ax2 = ax1.twinx()#これでx軸を共有できる!!!
ax2.plot(X,Y2,color='r', label=r'$y=e^x$')#plotする
ax2.set_ylabel('yaxis2')  # we already handled the x-label with ax1
ax2.set_yscale("log") #右のy軸はlogスケールに設定
ax2.set_ylim((1,10000))
ax2.legend(loc="upper right")
```

#x軸は同じでグラフを縦に並べる
こんなグラフを描きたい！
<img width="806" alt="Screen Shot 2020-03-18 at 23.49.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199901/960a1336-a50d-786a-cf86-750b4ea85b31.png">

縦に二つグラフを並べるときは以下の構造にすればOKです。

```python
#(1)
#subplotを二つ縦に並べる
fig, axs = plt.subplots(2,1,sharex=True,dpi=100)
#上下のグラフの間を0にしてくっつける
fig.subplots_adjust(hspace=0)

#(2)
#上のグラフを描く
axs[0].plot(...)

#(3)
#下のグラフを描く
axs[1].plot(...)

#注意
#グラフの数は自由に変えられます
#ex) 2,1ではなく3,1にすれば3つ縦に並べる,,,
#dpi:解像度
#sharex=Falseにすればただのsubplotになる。
```

以下サンプルコードです。

```python

#好きな関数を定義する
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理
def fun(x): 
    y = 2**x #ここに自分の関数を書く
    return y

#prepare x,y data
X = np.linspace(1,10,num=100)
Y1 = fun(X)#プロットしたいyデータ
Y2 = np.exp(X)

#create 2 subplots vertically adjusted
fig, axs = plt.subplots(2,1,sharex=True,dpi=100)
fig.subplots_adjust(hspace=0)

#上のグラフ
axs[0].plot(X,Y1,color='g',label=r'$y=2^x$', linestyle='-.',)
axs[0].set_ylabel("yaxis1")
axs[0].set_ylim((1,100))
axs[0].tick_params(axis='y')
axs[0].legend(loc="upper right")

#下のグラフ
axs[1].plot(X,Y2,color='r', label=r'$y=e^x$')
axs[1].set_xlabel('xaxis')
axs[1].set_ylabel('yaxis2')  # we already handled the x-label with ax1
axs[1].set_yscale("log") #右のy軸はlogスケールに設定
axs[1].legend(loc="upper right")
```

#アニメーション(gifファイル作成)
一番シンプルなものを作成しました。
![filename.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199901/75529032-08f5-e485-a497-fb848c603944.gif)


gifファイル作成の構造&解説です。(コピペ用)

```python
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理
from matplotlib import animation as animation #gifファイルを作成

#おそらく手元に時間変化しているplotしたいデータがあると思います
#それをX,Y(t)をすると

#まずフレーム毎にplotする関数を作成します
#この変数iが'interval'ずつ増加していくことになる
def iplot(i, args,,,):
   plt.clf()#前のフレームのグラフを消す(残したい場合は削除)
   #ここにフレーム毎のプロットを描く
   #iが増えていくのでそれに応じてplotするデータが変わるように
   #ex) plt.plot(X,Y(i))

#いつものようにfigureを作る
fig = plt.figure(dpi=100) #dpi:解像度

#gifファイル作成
#意味: figにframeの数だけ、毎フレームiをintervalずつ増加させてiplot関数でplotしてください
#fargs=(,,)にはiplot関数のi以外の引数を指定する
#interval毎iが増えていく
#framesでいくつのframeを作るか指定できる
ani = animation.FuncAnimation(fig, iplot,fargs=(args), interval = 1, frames = 50)

#保存する
#filenameを指定
#writer、どの手法を使うか？とりあえずimagegickで問題なし
#fpsで1秒に何フレームにするか指定
ani.save('filename.gif', writer='imagemagick', fps=20)
```

サンプルコードは以下になります。

```python
import matplotlib.pyplot as plt #実際にプロットする
import numpy as np #データの整理
from matplotlib import animation as animation #gifファイルを作成

#plotするXとYを用意する。
X = np.linspace(1,10,num=100)
Y = 2*X #y=2x

#フレーム毎にplotする関数を作成する
#この変数iが(下のanimation関数の中の)'interval'ずつ増加していくことになる
def iplot(i,X,Y):
    plt.clf()#これがないと前のフレームのグラフが残ったままになる
    plt.plot(X+i,Y)#今回はy=2xをx方向に平行移動させる
    plt.xlim((0,60))#範囲を定める
    plt.xlabel('xaxis')
    plt.ylabel('yaxis')
    plt.text(2,18,"y=2(x-"+str(i)+")")

fig = plt.figure(dpi=100)
#gifファイルを作成
ani = animation.FuncAnimation(fig, iplot,fargs=(X,Y), interval = 1, frames = 50)

#保存する
ani.save('filename.gif', writer='imagemagick', fps=20)
```


#最後に
応用編が長くなってしまったので以下の記事は後日書きます。
内容は
- csvファイルの読み込み書き出し
- HDF5ファイルの読み込み、書き出し

です。
では！