matplotlib逆引きメモ（グラフの描き方）

今回は、簡単なグラフを描きます。この際に必要なパッケージがnumpyです。

コードを読むと分かりますが、matplotlibのほとんどのモジュールにおいて、numpyパッケージがimportされています。このように、matplotlibとnumpyには密接な関係があります。

以降のプログラムリスト中では、次の３つのimport文とplt.show()は適宜、省略しますので、注意してください。なお、plt.show()をplf.savefig(...)に変更すれば、スクリーンに出力する代わりに画像ファイルが作成されます。

```py3
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

(ここだけをリストに表示)

plt.show() または plt.savefig(出力ファイル名)
```


## 逆引きメモ
+ [フレーム編](https://qiita.com/cnloni/items/20b5908fbae755192498)
+ グラフの描き方


### 2-1. 関数のグラフを書きたい
例えば、次の減衰振動関数を描いてみます。

<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/a9c869c5-1f1c-042c-aaf2-a9e0f8bd9f71.png' title='図2-1' width='80%'><div><b>図2-1 減衰振動関数のグラフ。左図はデータ点数200、右図はデータ点数50</b></div><br/></div>

リスト2-1で描いたのが、図2-1の左図です。numpyの[linspace](https://qiita-image-store.s3.amazonaws.com/0/52659/a9c869c5-1f1c-042c-aaf2-a9e0f8bd9f71.png)は、指定した実数範囲を等間隔に出力するメソッドです。戻り値は[ndarray](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html)です。

ndarrayは、numpyが定義する配列オブジェクトです。ndarrayには、numpyの様々な工夫が詰まっています。例えば、第5行を見てください。yは関数値を格納したndarrayです。本来ならば、forループなどを使って配列yを計算しなければならないのですが、この1行だけで記述出来ます。numpyを一度使うとやめられなくなる理由の一つです。

x座標とy座標のndarray配列を、Axesクラスの[plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)メソッドに送るだけでグラフが描けてしまいます。

```py3:リスト2-1
04 x = np.linspace(0.0, 5.0, 200)
05 y = np.exp(-x) * np.cos(10.0 * x)
06 
07 fig, ax = plt.subplots()
08 ax.plot(x, y)
```

図2-1の左右のグラフは、データ点の細かさの違いです。np.linspaceの第3引数は、作成する配列のサイズです（データ点の数）。これを省略すると、データ点は50個に設定されますので、右図のように折れ線に見えてしまいます。関数の変化の激しさによって、適当な配列サイズを選択してください。


### 2-2. グラフの軸の範囲を変更したい
リスト2-1では、グラフの範囲（論理範囲）は、matplotlibが自動的に決めてくれます。これは便利なことの一つではありますが、目的によっては自分で決めたいときもあります。

例えば、リスト2-1ではX座標は[0, 5]の範囲ですので、X軸もちょうど[0, 5]で描画したいとします。そのときは、リスト12のように、Axesクラスの[set_xlim](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.set_xlim.html)メソッドで指定します。もし、左辺値をおまかせにして、右辺値を指定したい場合は、第1引数をNoneとすればよろしい。同様に、左辺値だけを指定したい場合は、第2引数をNoneにします（第2引数を省略しても可）。

```py3:リスト2-2
# （リスト2-1の変更部分）
07 fig, ax = plt.subplots()
08 ax.set_xlim(0.0, 5.0)
09 ax.plot(x, y)
```

図2-2に描画結果を示します（目盛を枠の内側に描く。リスト15参照）。指定されていないY軸は自動的に決まります。

<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/e8df0549-c71d-e827-bec0-e0cced00c5a8.png' title='図2-2' width='40%'><div><b>図2-2 減衰振動関数のグラフ。X軸の範囲を指定、目盛を内側に描く<b></div><br/></div>

Y軸の範囲を変更する場合には、X軸の場合と同様。[set_ylim](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.set_ylim.html)メソッドを使います。

```py3:リスト2-3
# （リスト2-1の変更部分）
07 fig, ax = plt.subplots()
08 ax.set_ylim(-1.0, 1.2)
09 ax.plot(x, y)
```

X軸とY軸の両方とも範囲を指定する場合には、set_xlimとset_ylimを両方使うより、[ax.axis](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.axis.html)を使う方が便利かも知れません。

```py3:リスト2-4
# （リスト2-1の変更部分）
07 fig, ax = plt.subplots()
08 ax.axis([0.0, 5.0, -1.0, 1.2])
09 ax.plot(x, y)
```


### 2-4. 軸の範囲をおまかせにしたときの値を知りたい
軸の描画範囲をシステムに任せたとき、後でその値を知りたいときがあります（例えば、テキストなどをグラフの中に上書きしたいときなど）。そのときは、[ax.get_xlim](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.get_xlim.html)や[ax.get_ylim](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.get_ylim.html)の戻り値を使います。これらのメソッドの戻り値は、両側の値を格納したタプルです。

リスト2-5で、ax.plotを実行したあとに、ax.get_ylimを実行していることに注意してください。描画する際に初めて軸の範囲が決まるためです。

```py3:リスト2-5
# （リスト2-1の変更部分）
07 fig, ax = plt.subplots()
08 ax.plot(x, y)
09 y1, y2 = ax.get_ylim()
10 print(y1, y2)
```


### 2-5. 目盛をグラフ枠の内側に付けたい
図2-1をよく見てもらうと、目盛が枠の外側についていることが分かります。筆者は目盛を枠の内側に付ける習慣のため、これでは困ります。この場合は、[ax.tic_params](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.tick_params.html)で目盛の付け方を指定します。実行結果は、上に示した図2-2です。

tic_paramsでは、direction以外にも様々なパラメータを設定できます（[公式サイトへのリンク](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.tick_params.html)参照）。

```py3:リスト2-6
# （リスト2-1の変更部分）
07 fig, ax = plt.subplots()
08 ax.set_xlim(0.0, 5.0)
09 ax.tic_params(direction='in')
10 ax.plot(x, y)
```


### 2-6. 複数の関数を描きたい
簡単です。リスト2-7は、3種類の関数を描いたものです。Y座標を格納する配列を3種類用意して（X座標は共有します）、ax.plotを関数の数だけ実行します。グラフの色は自動的に決まります。

```py3:リスト2-7
04 x = np.linspace(0.0, 5.0, 200)
05 y1 = np.exp(-x) * np.cos(9.95 * x)
06 y2 = np.exp(-x) * np.cos(1.73 * x)
07 y3 = np.exp(-x) * (1 - x)
08
09 fig, ax = plt.subplots()
10
11 ax.set_xlim(0.0, 5.0)
12 ax.plot(x, y1)
13 ax.plot(x, y2)
14 ax.plot(x, y3)
```

結果を図2-3に示します（リスト2-7に加えて、凡例も追加しています。リスト2-8参照）。

<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/40225235-7c85-656c-31c1-54546f3cf292.png' title='図2-3' width='50%'><div><b>図2-3 3種類の減衰振動関数のグラフ。凡例を追加</b></div><br/></div>


### 2-7. 凡例を付けたい
リスト2-7にリスト2-8を付け加えます。[ax.legend](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.legend.html)をコールするだけで凡例を付加できます。の第1引数は、各プロットに対応したラベルのリストです。線の色やスタイルを、自動的にラベルに割り付けてくれます。

```py3:リスト2-8
# （リスト2-7に追加）
15 ax.legend(['ω=10', 'ω=3', 'ω=1'])
```


### 2-8. プロットの色はどう決まっているのか？
mpl.rcParams['axes.prop_cycle']で定義されています。図2ｰ4のように、10色を循環してプロットします。

<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/7384c644-0bcf-0bbe-f35c-983ffdc2aa4f.png' title='図2-4' width='60%'><div><b>図2-4 デフォルトで決まっているプロット色（10色）</b></div><br/></div>

参考のために、図2-4を描いたプログラムをリスト2-9に示します。axes.prop_cycleという名前のパラメータは、[Cycler](https://matplotlib.org/tutorials/intermediate/color_cycle.html)という独特のクラスを使っています。そのため、リストに加工してから、legendに渡しています。

```py3:リスト2-9
05 fig, ax = plt.subplots()
06 x = np.linspace(-1.0, 1.0, 2)
07 cc = mpl.rcParams['axes.prop_cycle']
08
09 ryy = [np.sin(np.pi * x) + 1 - (c + 1)/5.0 for c in range(10)]
10 ax.plot(x, np.transpose(ryy))
11 ax.legend(cc.by_key().__getitem__('color'))
```

### 2-9. マーカを使ってプロットしたい
<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/d9c2c4f8-dce4-b0dc-68d9-77ac9d990168.png' title='図2-5' width='50%'><div><b>図2-5 マーカでプロット</b></div><br/></div>

観測データのように特定の座標点に意味がある場合、曲線ではなくマーカでプロットする必要があります（図5）。このときには、リスト2-10の10行目のように、[plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)の第3引数にマーカの種類を表わす記号を与えます。

なお、リスト2-10では、キーワード引数のcolorとmarkersizeを使って色とサイズを指定しています（後述）。

```py3:リスト2-10
05 fig, ax = plt.subplots()
06
07 d = np.loadtxt('list2-10.dat')
08 x = d[:,0]
09 y = d[:,1]
10 ax.plot(x, y, 'o', color='r', markersize=8)
```


### 2-10. マーカにはどんな種類があるのか？
<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/6f0cbb0d-5e86-6d64-a03c-088b2952daa5.png' title='図2-6' width='60%'><div><b>図2-6 マーカの種類</b></div><br/></div>

マーカの種類を表わす記号は、[matplotlib.markers](https://matplotlib.org/api/markers_api.html#markers)で定義されています。

参考のために、図2-6を描いたプログラムをリスト2-11に示します。3行目でimportしているのは、リスト2-9で登場したCyclerクラスです。

```py3:リスト2-11
03 from cycler import cycler
04
05 fig, ax = plt.subplots()
06
07 x = np.linspace(-1.0, 1.0, 40)
08 cc = cycler(marker=list('.ov^<>8s+x'))
09
10 ryy = [np.sin(np.pi * x) + 1 - (c + 1)/5.0 for c in range(10)]
11 ax.set_prop_cycle(cc + plt.rcParams['axes.prop_cycle'])
12 ax.plot(x, np.transpose(ryy), linestyle='None')
13
14 ax.legend(cc.by_key().__getitem__('marker'))
```


### 2-11. 線やマーカの色を指定するには？
<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/5c787184-acc6-f008-63b5-0ab3a3537dc7.png' title='図2-7' width='60%'><div><b>図2-7 色指定の方法</b></div><br/></div>

[ax.plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)に対して、colorキーワード変数を指定すると、線やマーカの色を指定できます。色は、[matplotlib.colorsモジュール](https://matplotlib.org/api/colors_api.html)で定義されています。

色を表現するにはいくつかの方法があります。そのうち、よく使うものを表2-1に示します。

<div><br/><b>表2-1 色の表現方法</b></div>

| 方法 | 例 | 備考 |
| :-- | :-: | :-- |
| RGBを表す16進表現 | color='#4e0550' | RGBA表現も可 |
| RGBを表す実数のタプル | color=(0.3, 0.8, 0.4) | 4要素にしてRGBA表現も可 |
| 昔風の1文字表現 | color='r' | 'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w' |
| CSS4で定義された名前 | color='darkorchid' | [CSS4の色の名前](https://www.w3.org/TR/css-color-4/#named-colors) |
| XKCDサイトで定義された名前 | color='xkcd:vivid blue' | [XKCDの色の名前](https://xkcd.com/color/rgb/) |

図2-7を描いたプログラムをリスト2-12に示します。

```py3:リスト2-12
04 fig, ax = qt.subplots()
05 
06 names = ('#4e0550', (0.3, 0.8, 0.4), 'r', 'darkorchid', 'xkcd:vivid blue')
07 
08 x = np.linspace(-1.0, 1.0, 2)
09 for i in range(len(names)):
10     ax.plot(x, x + 0.2 * (4 - i), color=names[i])
11 
12 ax.legend(names)
```

### 2-12. マーカのサイズを指定するには？
<div><img src='https://qiita-image-store.s3.amazonaws.com/0/52659/63e5fc89-9c48-b690-b81e-a0ce5135213c.png' title='図2-8' width='60%'><div><b>図2-8 マーカのサイズ</b></div><br/></div>

[ax.plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)に対して、markersizeキーワード変数（短縮形msも使える）を指定すると、マーカのサイズを指定できます。サイズの単位はポイントです。

```py3:リスト2-13
03 from cycler import cycler
04 
05 fig, ax = plt.subplots()
06 
07 sizes = (2, 4, 6, 8, 10, 12)
08 num_sizes = len(sizes)
09 
10 x = np.linspace(-1.0, 1.0, 10)
11 cc = cycler(markersize=sizes)
12 
13 ryy = [x + 1 - (c + 1)/5.0 for c in range(num_sizes)]
14 ax.set_prop_cycle(cc)
15 ax.plot(x, np.transpose(ryy), 'o', color='b')
16 
17 ax.legend(cc.by_key().__getitem__('markersize'))
```

### 2-13. ポイントとは何？
ポイント（pt）は長さの単位で、72pt=1インチです。従って、ピクセル（px）との関係はDPIによって変わります。matplotlibでは、figure.dpi=100がデフォルトなので、デフォルトのままでは1px=0.72ptです。figure.dpiを変更すると、ピクセルとポイントの関係は変わります。

(pt値) = 72 / (dpi値) * (px値)

の関係があります。

  
### 2-14. plotのキーワード変数にはどんなものがあるの？
詳細は、matplotlibのドキュメント（[ax.plot](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)）を見てください。よく使うものを表2-2に示します。

<div><br/><b>表2-2 ax.plot()のキーワード引数</b></div>

| キーワード | 意味 | 備考 |
| :-: | :-: | :-- |
| color | 描画色 | 2-11を参照 |
| marker | マーカの種類 | 2ｰ10参照。markerキーワードでマーカを指定した場合、線とマーカが同時に出力される |
| markersize | マーカのサイズ | 実数。ポイント単位 |
| linestyle | 線の種類 | [線の表現](https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linestyle)参照。'None'を設定すると線を描かない |
| linewidth | 線の太さ | 実数。ポイント単位 |