plotlyでbubble-pieチャート作成

# 1.はじめに
* pie-bubbleチャートという種類のグラフをplotlyで作成した。
* 自分の欲しい機能を追加していきたい（簡単なcallbackとか）

# 2.経緯
* bubble-pieチャートというのがあって、昔から試作を繰り返しては、きれいさとかグラフの動作で不満な部分があってずっと検討していた。
* 一番惜しかったのが、[zingchart](https://www.zingchart.com/)。が、円グラフの内訳の数字がうまく出せず断念。

* javascriptで
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/f51d5d8e-9f80-a884-174d-d970268910b9.png)](https://www.zingchart.com/docs/chart-types/bubble-pie)

* Rで
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/c2949e4e-97b5-4fd2-cc04-7cc612913e49.png)](https://stackoverflow.com/questions/38959093/packed-bubble-pie-charts-in-r)


* python(matplotlib)で
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/404813b0-a68a-55a2-d7c1-1c6e6a926279.png)](https://matplotlib.org/2.1.0/gallery/pie_and_polar_charts/pie_demo2.html#sphx-glr-gallery-pie-and-polar-charts-pie-demo2-py)



---


* もっと動的にきれいに出したいなとか、軸などきれいに設定したいと思いつつ過ごしていたところ、plotlyをヘビーに使っていたのに鑑みて、plotlyで作成してみた。
* 最終的にできたのがこんな感じ↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/ac83917b-b636-406b-690e-1096ed1ae304.png)






plotyなので、内訳をいくつか除いてもすぐに再描画してくれる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/441baec3-b659-895f-e572-8e8eefc4d703.png)



# 3.ソース
 全体のソースコードは[ここ]()から
ポイントは

* 円グラフを描画するGrid（メッシュ）の作り方
go.pie()の引数として指定しないといけないのが、
　・label(円グラフの中の内訳)
　・domain （各円グラフに対応するグラフ上の４点指定のエリア）
　・values（各円グラフの内訳に対応する件数.リスト形式で）
の３つ。

例えば
```python
labels=["hydrogen","oxygen","co2","methane"]
val = [1,3,2,4]
domain = [
 {'x': [0.0, 0.5], 'y': [0.0, 0.5]},
 {'x': [0.0, 0.5], 'y': [0.5,1.0]},
 {'x': [0.5, 1.0], 'y': [0.0, 0.5]},
 {'x': [0.5, 1.0], 'y': [0.5, 1.0]},
]

go.Pie(labels = labels,
       values = val,
       domain = domain,
       )

```

のような形。domainが一番理解しにくかったですが、パネルを置いてくイメージで。
x軸のリスト（下の例だとkai_list）と、ｙ軸のリスト(kadai_list)があった場合に、
len(arr1) * len(arr2)のメッシュをうまくdomainsにはまるように生成させるのが下記の２関数。np.linspaceとitertoolsを活用。

```python
import numpy as np
def getrangearr(num: int = 5) -> np.ndarray:
    """
    num個の点からなる範囲の配列を返します。

    Args:
        num: 点の数 (デフォルト: 5)

    Returns:
        num個の点からなる範囲の配列
    """

    start = 0
    stop = 1
    lins = np.linspace(start, stop, num)

    mesh = []
    for i in range(len(lins) - 1):
        mesh.append([lins[i], lins[i + 1]])

    return np.array(mesh)

import itertools as it
import numpy as np

def getmesh(arr1: List[int], arr2: List[int]) -> List[List[int]]:
    """
    arr1とarr2の全組み合わせを返します。

    Args:
        arr1: 配列1
        arr2: 配列2

    Returns:
        arr1とarr2の全組み合わせのリスト
    """

    combi = []
    combinations = it.product(arr1, arr2)
    for combination in combinations:
        combi.append(combination)

    return combi


xlen = len(kai_list) + 1
ylen = len(kadai_list) + 1
xarr = getrangearr(xlen)
yarr = getrangearr(ylen)

meshd = getmesh(xarr,yarr)
domains = [{'x':mesh[0],'y':mesh[1]} for mesh in meshd]

```

* 罫線のかけ方
ｘ軸、ｙ軸ともにレンジを[0,1]にした関係で、通常の罫線が不要になり、各円グラフの中心をとおるｘｙの罫線を追加する部分で苦労。
最終的に

```python
for i,xpos in enumerate(xarr):
    fig.add_vline(x=(xpos[0] + xpos[1])/2, line_width=0.3, line_dash="dash",line_color="gray")

for i,ypos in enumerate(yarr):
    fig.add_hline(y=(ypos[0] + ypos[1])/2, line_width=0.3, line_dash="dash",line_color="gray")


```
のようにして、各円グラフの中心を通る破線を描画して、その上に各円グラフを載せていくように設定！


* add_annotation
ここも苦労したけど、描画するデータラベルとの関係で書きにくいので省略。

# 4.その他・今後追加したい機能
* [ここ](https://plotly.com/python/click-events/)や[ここ](https://plotly.com/python/v3/selection-events/)に書いてあるような簡単なイベント機能で、選択エリアの関連データをdataframeなどで出せるようにしたい。dash使えば、という自分の声もありますが。
* 現状の出し方だと、plotlyの利点であるズームボタンとかエリア選択が利用不可能になってしまっていたので、復活させたい。
* plotly expressを使って時系列変化もできるようにしたい。