heatmapに斜線 (hatch) を加える (python, matplotlib)

# はじめに
ヒートマップ上で特定の値を示す部分に斜線（'/'）を描きたかったので，メモ．

# やりたいこと
以下のようなヒートマップで，特定の値の部分を斜線でいい感じにしたい．

```python:show_heatmap.py
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(0)
Z =np.random.rand(10, 10)
Zm = Z * 0
Z[3:5, 5:8] = 1
fig, ax = plt.subplots(figsize=(9, 7))
ax1 = ax.pcolormesh(Z)
fig.colorbar(ax1)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/204f0738-b40d-e501-74bb-0e58bb73ae1c.png)

上の図では，`Z[3:5, 5:8] = 1`として図の一部の値を1に設定しています．
この`Z[3:5, 5:8]`の部分に斜線を引きます．

# 解決方法
最終的なコードは以下．

```python:show_heatmap_with_hatch.py
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(0)
Z =np.random.rand(10, 10)
Zm = Z * 0
Z[3:5, 5:8] = 1
fig, ax = plt.subplots(figsize=(9, 7))
ax1 = ax.pcolormesh(Z)

Zm = np.ma.masked_where(Z!=1, Z)
ax2 = ax.pcolor(Zm, hatch='/', edgecolor='grey',facecolor='none', linewidth=0.0)

fig.colorbar(ax1)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/2a7abe1d-cb07-25f7-81e1-5ddc58bb75e1.png)

# 何をしているか
上記のコードで，最初と異なるのは以下の2行です．

```python
Zm = np.ma.masked_where(Z!=1, Z)
ax2 = ax.pcolor(Zm, hatch='/', edgecolor='grey',facecolor='none', linewidth=0.0)
```

## 1行目：行列のマスク
一部のみ斜線で示すために，コードの1行目でその部分を表す行列（`Zm`）を作成しています．

`numpy.ma.masked_where` を用いることで，条件に該当する部分が無効にされた（マスクされた）行列を作成することができます．
参考：[numpy.ma.masked_where 公式ドキュメント](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.masked_where.html)

もともとの行列（`Z`）とマスクされた行列（`Zm`）は以下のようになっています．
<img width="616" alt="スクリーンショット 2019-12-03 13.53.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/d964c787-cd0a-37c3-bbd3-bfeeb49b3b73.png">


<img width="616" alt="スクリーンショット 2019-12-03 13.53.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/67c775c9-f2fa-a1b2-c7fa-39baad0c821c.png">

行列の中身を見ると，`Zm`では，条件式(`Z!=1`)に該当する要素以外は`--`で表されています．
プロット時にこの行列`Zm`を用いることで，条件式に該当する部分は無視してプロットを行うことができます．

## 2行目：hatchで斜線を描画
参考：[python – matplotlib 2.0で領域をハッチのみ（背景色なし）で埋めるにはどうすればいいですか？](https://codeday.me/jp/qa/20190618/1041536.html)

コードの2行目では，行列`Zm`を用いて斜線を描画しています．
`matplotlib.pyplot.pcolor`では，以下のパターンのhatchを用いることができます．
> /   - diagonal hatching
\   - back diagonal
|   - vertical
-   - horizontal
+   - crossed
x   - crossed diagonal
o   - small circle
O   - large circle
.   - dots
*   - stars

参考：[matplotlib.collections.Collection.set_hatch](https://matplotlib.org/3.1.1/api/collections_api.html#matplotlib.collections.Collection.set_hatch)

ここで使用したオプションは以下の通りです．

- `edgecolor`：hatch の色
- `facecolor`：hatchの背景色．'none'に設定することでヒートマップの色を残してhatchのみを表示させることができる．
- `linewidth`：グリッドの太さ．0より大きい値を指定するとグリッドが表示される．

オプションを変更したときの図の外観は以下のようになります．
（`ax.pcolor`の行以外は最終的なコードと同じです）

```python
ax2 = ax.pcolor(Zm, hatch='/', edgecolor='grey',facecolor='none', linewidth=1.0)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/aa00bcaf-26c2-822a-9aba-c1bb5a55624c.png)


```python
ax2 = ax.pcolor(Zm, hatch='/', edgecolor='grey',linewidth=0.0)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/13cdac85-38eb-4d3c-1225-fce630d3095e.png)

```python
ax2 = ax.pcolor(Zm, hatch='/', edgecolor='red',facecolor='none', linewidth=0.0)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167418/65ae65d2-8ae4-5c0c-8490-4c04dcd4a237.png)


### 参考サイト一覧
- [numpy.ma.masked_where 公式ドキュメント](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.masked_where.html)
- [python – matplotlib 2.0で領域をハッチのみ（背景色なし）で埋めるにはどうすればいいですか？](https://codeday.me/jp/qa/20190618/1041536.html)
- [matplotlib.collections.Collection.set_hatch](https://matplotlib.org/3.1.1/api/collections_api.html#matplotlib.collections.Collection.set_hatch)