matplotlibでの描写 等高線プロットの基礎をわかりやすく説明してみた

## はじめに
自分への備忘録も兼ねて、matplotlibでの等高線描写の基本をまとめてみます・・・

## 等高線の基本
### 等高線描写は「meshgridしてcontour」

まず等高線を描くにあたって必要なものを洗い出しましょう。

等高線を描くには基本的に以下の２つが必要になります。

#### 等高線を書くために必要なもの
* 格子点
* 格子点における高さ

なので、まず格子点を作ります。

#### 格子点を作る
格子点を作るには`numpy.meshgrid`を用います。

例えば、次のような15個の格子点を作りたいとします。
![image1.png](https://qiita-image-store.s3.amazonaws.com/0/265344/897be159-ef07-413e-569a-49c5b96b265d.png)

この場合、次のコードで格子点が作れます。

```python
import numpy as np

# X座標
x = np.arange(3) # array([0, 1, 2])

# Y座標
y = np.arange(5) # array([0, 1, 2, 3, 4])

# 格子点作成
xx, yy = np.meshgrid(x, y)
```
これを実行すると、

```python
print(xx)
-> array([[0, 1, 2],
          [0, 1, 2],
          [0, 1, 2],
          [0, 1, 2],
          [0, 1, 2]])

print(yy)
-> array([[0, 0, 0],
          [1, 1, 1],
          [2, 2, 2],
          [3, 3, 3],
          [4, 4, 4]])
```
のように同じ型を持った行列が生成されます。

これらの各成分を組み合わせることで、全ての格子点を表現できます。

```python
# 格子点のリストとして表現
lattice_point_list = np.array([xx.ravel(), yy.ravel()]).T

print(lattice_point_list)
-> array([[0, 0],
          [1, 0],
          [2, 0],
          [0, 1],
          [1, 1],
          [2, 1],
          [0, 2],
          [1, 2],
          [2, 2],
          [0, 3],
          [1, 3],
          [2, 3],
          [0, 4],
          [1, 4],
          [2, 4]])
```
ndarray.ravelは行列を一次元化するメソッドです。
この格子点のリストを作り出す手法は機械学習とかでもよく使うので覚えておくとよいと思います。

散布図を出すには`matplotlib.pyplot`を使って以下のようにすれば一発です。

```python
import matplotlib.pyplot as plt

# 描写
plt.scatter(xx, yy)
plt.show()
```

![img-20181005165213.png](https://qiita-image-store.s3.amazonaws.com/0/265344/f32c76a6-2f43-eaa2-a8c7-10d613a179ae.png)

#### 格子点における高さ

次に必要になってくるのは格子点における高さの値です。
ここでは例としてわかりやすいので原点からの距離を値としてみます。

原点からの距離は以下の式

$$
\sqrt{x^2 + y^2}
$$

で表されるので、

先程の１５個の格子点の原点からの距離行列を求めると・・・

```python
# 各点の原点からの距離を求める
distance_matrix = np.sqrt(xx**2 + yy**2)

print(distance_matrix)
-> array([[0.        , 1.        , 2.        ],
          [1.        , 1.41421356, 2.23606798],
          [2.        , 2.23606798, 2.82842712],
          [3.        , 3.16227766, 3.60555128],
          [4.        , 4.12310563, 4.47213595]])
```
のようになります。

### 等高線を描く
あとは`plt.contour`で一発です。

ちなみにcontourは等高線という意味の単語です！

```python
plt.contour(xx, yy, distance_matrix)
plt.show()
```

![img-20181005171141.png](https://qiita-image-store.s3.amazonaws.com/0/265344/efc387f2-de2d-d4ed-7571-a2153a5de03c.png)

ちなみに`contourf`とすると塗りつぶされます。

fはなんなのか調べたところfilled contourのfみたいです。

```python
plt.contourf(xx, yy, distance_matrix)
plt.show()
```
![img_20181005172803.png](https://qiita-image-store.s3.amazonaws.com/0/265344/568928e1-1906-a6e5-cfc2-890fcc259e6f.png)



## カラーマップ
カラーマップはcmapで指定できます。
おすすめのものをいくつか挙げておきます。

等高線は以下のデータで作成しています。

```python
# データ作成
x = np.arange(-3, 3, 0.1)
y = np.arange(-3, 3, 0.1)
xx, yy = np.meshgrid(x, y)
z = np.sqrt(xx**2 + yy**2)
```

* Blues

```python
plt.contourf(xx, yy, z, cmap='Blues')
```
![img_20181005173925.png](https://qiita-image-store.s3.amazonaws.com/0/265344/1bc5496b-3b43-3bd8-eccc-d372575081c4.png)

* spring

```python
plt.contourf(xx, yy, z, cmap='spring')
```
![img_20181005175000.png](https://qiita-image-store.s3.amazonaws.com/0/265344/78413f31-823e-4cc6-5ccd-6d8eb0210584.png)

* gray

```python
plt.contourf(xx, yy, z, cmap='gray')
```
![img_20181005175220.png](https://qiita-image-store.s3.amazonaws.com/0/265344/c419711d-93a4-bbd2-e0bf-9ecf41ef9770.png)


matplotlib公式ドキュメントは[こちら](https://matplotlib.org/examples/color/colormaps_reference.html)
いろんなカラーマップがあります！

### アスペクト比について

アスペクト比とは簡単にいうと縦横の比のことです。
これを1:1にしたい場合、以下のコードを追加することで実現できます。

```python
plt.gca().set_aspect('equal') # gcaはget current axesの略
```
これを追加することで先程のものはきれいな正方形になります！

![img_20181005175826.png](https://qiita-image-store.s3.amazonaws.com/0/265344/a269110e-e90e-7773-b8ae-fe0497842e94.png)

## 参考文献
[Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理](https://www.amazon.co.jp/Python%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-NumPy-pandas%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E5%87%A6%E7%90%86-Wes-McKinney/dp/487311845X/ref=dp_ob_title_bk)