Treemap という可視化手法の紹介

## Treemapとは

階層データに適した可視化技法の一つである。
階層データとは下記のようなデータだ。

| group | subgroup | subsubgroup | value | 
| --- | --- | --- | --- |
| A | 1 | foo | 11 |
| A | 1 | bar | 22 |
| A | 2 | hoge | 2 |
| A | 2 | moge | 4 |
| B | 1 | moge |3 |
| B | 2 | moge | 49 |
| B | 2 | foo | 9 |
| B | 2 | bar | 4 |

## とにかくTreemapを作ってみる

例として
plotly社のドキュメント「Treemap Charts in Python」の「Treemap of a rectangular DataFrame with plotly.express」を取り上げる。

https://plotly.com/python/treemaps/

実行可能な例(Colabのノートブック)は[こちら](https://colab.research.google.com/drive/1hPhkeV6gHurWjhHx-ZJXLu9z6Tl-YT81?usp=sharing)

このようなデータフレーム(レストランか何かの訪問客情報、各行が1客のデータを示す)に対して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/3fd5d99b-1860-438a-643f-f3a0529171a6.png)

下記のコードを実行すると画像のTreemapが得られる。
plotly.expressを使っている。
`path`は「day、time、sexの階層順に分類していってくださいよ」と指定するものである。最初に挙げたデータ例と対応させる場合、dayがgroup、timeがsubgroup、sexがsubsubgroupになる。

```python
import plotly.express as px
df = px.data.tips()
fig = px.treemap(df, path=['day', 'time', 'sex'])
fig.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/c033568e-1596-4085-458d-eab462b78f45.png)

ここで長方形の面積が示しているのはその値を持つグループの要素のカウント数(dfでいうと行数)である。ThurとFriのカウント数を足すと、確かにSunと大体同じ値(可視化結果で言うと面積)になっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/168ea04f-82cb-60aa-b79c-6dbaf12400ed.png)

この可視化により

- 曜日毎の客数
- ランチ、ディナーの客数
- 男女の客数

を一つのビューで把握することができる。
(なかなか便利だな、と感じられたのではないだろうか?)


ちなみに最初に示した階層データで言うところのvalue列のデータも参考にしたい場合は、下記のように`values`オプションを`treemap()`に追加するとよい。マウスホバーでその長方形内に含まれる客がいくらお金を使ってくれたか(`total_bill`列)の「総額」情報が表示される。

```python
fig = px.treemap(df, path=['day', 'time', 'sex'], values='total_bill')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/97c5699c-5a72-18db-e243-7c92ca265411.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/f7954c84-9d0a-21dc-e665-8bf1cd335bf1.png)


## Treemap のアルゴリズムと亜種、適用例について

Treemapをどう実装するか?と考えた場合、下記のようなアルゴリズムは誰でもすぐに思いつくと思う。

1. `path`の最初の列の値毎に行数をカウントする
2. 1.のカウント比に応じて長方形をカットする
3. 2.の各長方形毎に`path`の次の列に対して同様のことを繰り返す

といってもピンと来ないかと思うのでコードで実例を示す。
まず前述の`foo`のような行セレクトの書き方は面倒なのでdfにMultiIndexを設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/bc76337c-3179-5525-17e9-dc81475a60b1.png)

すると下記のようにして1.~3.で述べたカットすべき長方形の面積比がわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7591/b6c4400d-d668-4b4c-a6f4-58e36a48f13f.png)

これを,"Sun", "Thur", "Fri" に対しても行い、各長方形のカットを繰り返すとTreemapが出来上がるだろう。
これはド単純なアルゴリズムであり他にもTreemapの種類が存在する。
そのようなもので自分が知るのは「Voronoi Treemaps」だ。
特に蛋白の機能階層をその「Voronoi Treemaps」を使って可視化したものに [Proteomaps](https://www.proteomaps.net/) がある。論文doiは https://doi.org/10.1073/pnas.1314810111 だ。

- 勝手にその論文の図をここに貼るのは問題があるのではないか?と考えた
- Free Full Text である

ためその可視化結果はご自身で確認していただきたい。

## よりよい Treemap 可視化のために

Treemapに限らないが

- インタラクティブにする
- 他の可視化コンポーネントと連携させる

ことを行うと、より詳しくデータを理解することができるはずだ。
少なくともDashを用いてこれを実現している例がある。
https://qiita.com/OgawaHideyuki/items/725f4ffd93ffb0d30b6c#%E3%83%84%E3%83%AA%E3%83%BC%E3%83%9E%E3%83%83%E3%83%97%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%8F%AF%E8%A6%96%E5%8C%96

ぜひ単にTreemapを書くだけでなくこういった拡張まで行いその可能性を感じてみてほしい。