ゼロからはじめるmatplotlib〜4.オブジェクト指向スタイル〜

今回はmatplotlibをオブジェクト指向スタイルで使ってみます。

# plt.subplotsの理解

前回使った`plt.subplot()`と似たメソッドの`plt.subplots()`を使います。

まずはJupyter notebookで下のように書いて実行してみましょう。

```py
fig, ax = plt.subplots()
```
<出力結果>
![subplots6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280728/5c04a985-6fd7-4eda-7ab6-f21afe000d74.png)

すると以下のように、出力されます。

また、変数を確認すると、

```py
fig
```
<出力結果>
![subplot7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280728/86371af5-3a93-5cd9-7766-51c6f9babbb4.png)

このように真っ白な画面が出力されます。

同様にaxに関しても変数を確認してみると、

```py
ax
```
<出力結果>

```py
<matplotlib.axes._subplots.AxesSubplot at ...>
```

このようにaxesオブジェクトが表示されます。

ここから`fig`の変数には図全体を調節する__Figureオブジェクト__、
`ax`の方にはグラフを描画する__axesオブジェクト__が入っていることがわかります。

ざっくり言えば、「グラフ用紙(axes)とグラフ全体のレイアウト(Figure)が用意されている。」
みたいなイメージです。

この用意したグラフ用紙と全体のレイアウトに対して、メソッドを追加していくことでグラフを調節できます。

## 具体的にオブジェクト指向スタイルで描画してみる。

1行2列のグラフ用紙にsin関数とcos関数を並べます。
1行のときは、axesオブジェクトの[]番目を指定します。
後でまた書きますが、複数行のときは[行,列]というように指定します。

```py
x = np.arange(0,2*np.pi,0.01)
fig, ax = plt.subplots(1,2)

# 左のグラフ
ax[0].plot(x, np.sin(x))
ax[0].set_title("sinx")


# 右のグラフ
ax[1].plot(x, np.cos(x))
ax[1].set_title("cosx");
```

<出力結果>
![subplot8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280728/1641362f-6644-dee1-05da-86ded6275806.png)


左のグラフと右のグラフが被っていますね。
これを避けるために、グラフの全体(Figureオブジェクト)に対してtight_layoutメソッドを使ってみましょう。

- 改善バージョン

```py

x = np.arange(0,2*np.pi,0.01)

# facecolorで外側をskyblueにしてみた。
fig, ax = plt.subplots(1,2, facecolor='skyblue')

# 左のグラフ
ax[0].plot(x, np.sin(x))
ax[0].set_title("sinx")

# 右のグラフ
ax[1].plot(x, np.cos(x))
ax[1].set_title("cosx");

# グラフの配置が自動調整されます。
fig.tight_layout()
```
<出力結果>
![subplot9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280728/e1d3df42-6436-a436-224b-0cb4fa30bb47.png)

## 複数行のplot
グラフ用紙を選択するときは,[行の番号,列の番号]で指定します。

```py
theta = np.arange(0,2*np.pi,0.01)

# 全体のサイズ調節
fig, ax = plt.subplots(2, 3, facecolor='skyblue')

# 右上[0,0]
ax[0,0].plot(theta, np.sin(theta))
ax[0,0].set_title("sin")
ax[0,0].grid()

# 中上[0,1]
ax[0,1].plot(theta, np.cos(theta))
ax[0,1].set_title("cos")
ax[0,1].grid()

# 右上[0,2]
ax[0,2].plot(theta-np.sin(theta), 1-np.cos(theta))
ax[0,2].set_title("cycloid")
ax[0,2].grid()

# 左下[1,0]
ax[1,0].plot(np.power(np.cos(theta),3), np.power(np.sin(theta),3))
ax[1,0].set_title("asteroid")
ax[1,0].grid()

# 中下[1,1]
ax[1,1].plot((1+np.cos(theta))*np.cos(theta), (1+np.cos(theta))*np.sin(theta))
ax[1,1].set_title("cardioid")
ax[1,1].grid()

# 右下[1,2]
theta2 = np.arange(0,10*np.pi,0.01) # インボリュート曲線用
ax[1,2].plot(np.cos(theta2)+theta2*np.sin(theta2), np.sin(theta2)-theta2*np.cos(theta2))
ax[1,2].set_title("involute of circle")
ax[1,2].grid()

# グラフ位置の自動調整
fig.tight_layout()
```

<実行結果>
![subplot10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280728/58cfdca9-5b8a-9a31-769e-ba9a0b1c45f6.png)

# まとめ
今回はオブジェクト指向型の描画方法に関してやりました。

今までのようにplt.〜メソッド重ねていくのではなく、Figureオブジェクトとaxesオブジェクトをいじっていくことで描画していきます。
こちらの書き方の方が、細かいところまで指定できる、for文内で使用したり関数化しやすいなどのメリットがあるのである程度慣れたら、こちらの書き方に慣れた方が良いと思います。

matplotlibの構造を知りたいという方は下の記事を参照してください。（とてもわかりやすいです！！！）

- [早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話](https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9)

- [matplotlibのArtistの階層構造-keisukeのブログ-](http://kaisk.hatenadiary.com/entry/2014/12/01/005809)