Seabornのカラーパレットで色覚異常を考慮した岡部・伊藤の提案を使う


棒グラフや折れ線グラフなどを[Seaborn](https://seaborn.pydata.org/)で描く際のTIPSです。

グラフ上のカテゴリや系列など、違うものに違う色を付けることで、グラフを読み取りやすくできることがあります。ただ、この時に使う色をどう選ぶかは、それほど自明な方法がありません。有名なカラーパレットを採用したり、あるいはグラフ描画ソフトのデフォルト設定をそのまま使っている人も多いと思います。

この記事では、色覚異常を持った人でも識別しやすいとされるカラーパレット（Okabe-Itoカラーパレット）をSeabornで使ってみる場合についての情報をまとめました。

## CVDセーフな色

グラフ描画に使う色の選び方ですが、1つの考え方として、色覚異常(CVD)を持った人でも違いが識別できる色を選ぶとよいとする方針があります。色覚異常には2型3色覚、3型3色覚など種類があるそうですが、この記事では深入りしません[^n-cvd]。

[^n-cvd]: ただし、色覚異常（正常とされる他の大勢の人とは色が異なって見える）は決して稀ではない点は覚えておくとよいのかなと思います。

色覚異常を持った人でも識別しやすい色のことをCVDセーフな色と呼びます。CVDセーフな色を使ったカラーパレットを用いてグラフ描画を行えば、色覚異常を持った人でも識別しやすいグラフが作れる可能性が高まります。

## 岡部・伊藤のカラーパレット

具体的にCVDセーフなカラーパレットとはどんなものかですが、いくつも提案があるようです。

https://twitter.com/fronori/status/1167654944297504773

『データビジュアライゼーションの基礎』では岡部正隆と伊藤啓が提案したカラーパレットが紹介されていました。

https://www.oreilly.co.jp/books/9784873119533/

岡部・伊藤のカラーパレットは次の8色からなります。カテゴリ分けに色を使う場合においては、おそらく十分な色数です。
![okabe-ito-palette.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64680/56d54d51-991e-675e-4133-1f39c483a5fa.png)

|色名|RGB（16進カラーコード）|
|---|---|
| Black | #000000 |
| Orange | #E69F00 |
| Sky Blue | #56B4E9 |
| blulsh Green | #009E73 |
| Yellow | #F0E442 |
| Blue | #0072B2 |
| Vermilion | #D55E00 |
| reddish Purple | #CC79A7 |


## Seabornでの利用例

まずカラーパレットを定義します。

```python
import seaborn as sns

# この記事の実装ではBlackを最後尾にしています。
# 黒色は視認性は良くてもラベル等ほかの場所で使われやすいだろうとの想像からです。
palette = sns.color_palette(['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000'])
```

グラフ描画関数はカラーパレットをキーワード引数`palette`で取れるので、定義したカラーパレットを渡してやります。

```python
import seaborn as sns

palette = sns.color_palette(['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000'])

# サンプルデータで描画してみる
# コードは公式サンプルより: https://seaborn.pydata.org/introduction.html#composite-views-onto-multivariate-datasets
penguins = sns.load_dataset("penguins")
sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species", palette=palette[:3])
```

実行例
![plot-penguins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64680/baac0a1e-2436-c568-d52e-a7bf9c060063.png)

実装にはちょっとした注意点があります。使用する描画関数によっては、カテゴリ数に厳密に合うように色数を渡してやらないといけないようでした。そして、サンプルで使用した`jointplot`は一致を要求するようでした。
今回のデータは3カテゴリなので `palette[:3]` で3色を切り出しています。

この挙動はやや直感的でないようにも感じられ、Seabornのissueで作者とのやり取りもありますが、少なくとも記事執筆時点のSeabornではそういう振る舞いになってしまうようです。
https://github.com/mwaskom/seaborn/issues/2662

### デフォルトのカラーパレットを変更してしまう書き方

カラーパレットの別の指定方法として `set_palette` を呼ぶ方法があります。こちらの方針だと前述のような`palette`へのスライス操作が必要ないようです。

```python
import seaborn as sns

palette = sns.color_palette(['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000'])
sns.set_palette(palette)

# 以降は `palette` が指定された状態になっている
# ...
```

## カラーパレットによる方法の限界

前述の『データビジュアライゼーションの基礎』では次のような指摘があります。筆者はこの分野に詳しくないため解説はできないのですが、CVDセーフだから常に問題ないわけではないという知識は有用かもしれないと感じました。

> すぐに利用できるCVDセーフなカラースケールがいくつかあるとはいえ、それらが万能薬ではないというのは認識しておく必要があります。CVDセーフなスケールを用いても、CVDを持った人が解読できない図を作成してしまう可能性は非常にあります。1つの重要なパラメータは、色を塗られた視覚要素のサイズです。色の判別は、小さな領域や細い線に塗られているときよりも、大きな領域に塗られているときのほうがはるかに簡単です
> 『データビジュアライゼーションの基礎』p.215 より

## 参考リンク

- https://jfly.uni-koeln.de/color/#pallet
- https://oku.edu.mie-u.ac.jp/~okumura/stat/colors.html
- https://qiita.com/SaitoTsutomu/items/c79c9973a92e1e2c77a7
- https://mikemol.github.io/technique/colorblind/2018/02/11/color-safe-palette.html