holoviewsでグラフを作成するときのTIPS

- jupyter notebookでの操作を想定
- [PythonDataScienceHandbook](https://jakevdp.github.io/PythonDataScienceHandbook/)のグラフをholoviewsで描画しながら勉強中

# 事前準備
## モジュールインポート
```py
import holoviews as hv
import bokeh
hv.extension('bokeh')
```
## データ作成
```py 
import numpy as np

y = np.random.randn(10)
x = np.arange(10)
```

# グラフ
## 散布図
```py 
hv.Scatter((x,y))
```

## 折れ線グラフ

```py
hv.Curve((x,y))
```
- 積み上げ
    - hv.Area.stackに相当するメソッドが見当たらない
    - 描画前にデータを加工して対応


    ```py 
    hv.Overlay([ hv.Curve((x,y)),  hv.Curve((x ,y + y))])
    ```

## 面グラフ

```Python:
hv.Area((x,y))
```

- 積み上げ

    ```Python:
    ov = hv.Overlay([ hv.Area((x,y)),  hv.Area((x,y))])
    hv.Area.stack(ov)
    ```

## スプレッドグラフ
- 日本語で正しくは何グラフというのか不明。

```Python:
# 全要素同じ幅の場合はint           
hv.Spread((x, 2 * x + 3 , 5 ) )  
```
![bokeh_plot (4).png](https://qiita-image-store.s3.amazonaws.com/0/234604/19872726-a785-631a-daa2-a1a5e4c851de.png)

```Python:
# 要素ごと幅が変わる場合はxと同じ要素数の配列
hv.Spread((x, 2 * x + 3 , np.random.randn(len(x)) * 5 ) ) 
```

![bokeh_plot (5).png](https://qiita-image-store.s3.amazonaws.com/0/234604/3429c5e0-63ac-f697-d462-cbe43bffb1d9.png)

```Python:
# Curveとオーバレイする場合
hv.Curve((x, 2 * x + 3 )) * hv.Spread((x, 2 * x + 3 , 5 )).options(alpha=0.3,line_alpha=0) 
```
![bokeh_plot.png](https://qiita-image-store.s3.amazonaws.com/0/234604/13fe0996-efd4-0584-4223-4a3cbac0d447.png)


## 画像

```py 
hv.Image(np.meshgrid(x,x))
```
## ヒートマップ
- データ構造
    - こんな感じの2次元配列を第一引数に渡す

    |y |y  |値  |
    |---|---|---|
    |a  |a  |1  |
    |a  |b  |2  |
    |b  |a  |3  | 
    |b  |b  |4  |

    ```py 
data = [
    ['a','a',1],
    ['a','b',2],
    ['b','a',3],
    ['b','b',4],    
]
hv.HeatMap(data)
```

![bokeh_plot (1).png](https://qiita-image-store.s3.amazonaws.com/0/234604/b8001bf8-af3a-514e-e733-b5996b364d9c.png)


# レイアウト
## 並べて表示
```Python:
hv.Layout([ hv.Curve((x,y)),  hv.Scatter((x, y))])
```
```Python:
hv.Curve((x,y)) + hv.Scatter((x, y))
```


- パネルの行ごとの列数指定

```Python:
hv.Layout([ hv.Curve((x,y)),  hv.Scatter((x, y)), \
                              hv.Area((x, y))]).cols(2)
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234604/030d337e-de0c-8361-2dc0-f3b119f79803.png)


## 重ねて表示
```Python:
hv.Overlay([ hv.Curve((x,y)),  hv.Scatter((x, y))])
```
```Python:
hv.Curve((x,y)) * hv.Scatter((x, y))
```



# オプション
## 凡例
```Python:
hv.Scatter((x, y), label="hoge") * hv.Scatter((x + 2, y),  label="huga")
```

- 要素が一つの場合はグラフのタイトルとして表示される


## 軸
- タイトル指定

```py 
hv.Scatter((x, y),"x_axis","y_axis" )
```

    - グラフを重ねた場合最初に指定した値が有効となる

```py 
hv.Scatter((x, y),"x_axis","y_axis" ) * hv.Scatter((x + 2, y),"x_axis + 2","y_axis" )
```

- 範囲指定

```py 
hv.Scatter((x,y)).redim(x={'range':(10,20)}, y={'range':(-1,1)})
```


- フォーマット指定
    - 事前準備
    
    ```bash
pip install flexx
```

    - 処理
    
    ```py
    def fmt (x):
        return "%d" % ("hoge" + x )
    # 下記ではエラーとなった
    # fmt = lambda x : "%d" % ("hoge" + x )
    hv.Curve((x,y), vdims=hv.Dimension('y', value_format=fmt))
    ```

        - format()関数では動作しなかったり動作しないフォーマット文字列がある。
        - 指数表示を整数に修正する程度の役には立つ
        - flexxの仕様によるものではないかと推測

- 非表示化
    - 画像だけ表示したいときに軸と軸のタイトルを非表示化

    ```py
    hv.Image(np.meshgrid(x,x)).options(xticks=False,     yticks=False, xaxis=None, yaxis=None)
    ```

## 色の指定
- グラフごとの指定

```py 
hv.Scatter((x, y)).options(color="blue")
```

```py 
hv.Scatter((x, y)).options(color="#123456")
```
- まとめて指定

```py 
g = hv.Scatter((x, y)) * hv.Scatter((x + 1, y))
g.options({'Scatter':{'color':hv.Cycle(["yellow","green"] ) }} )
```
- 点ごとに指定
    - matplotlibでないと動作しなかった

    ```py 
import random
hv.extension('matplotlib')
colors = [ random.sample(["red","blue"], 1) for x in range(10) ]
hv.Scatter((x, y)).options(color=colors)
```

    - bokehの場合の回避策

    　色指定用の要素をデータに追加し要素ごとにプロット
      
    ```py 
    import pandas as pd 
    import random 
    c = [random.choice([ 0,1]) for x in range(50) ]
    data = np.array([x,y,c]).T
    df = pd.DataFrame(data, columns=['x','y','c'])
    ds = hv.Dataset((df))
    ds.to(hv.Scatter,vdims=['y'],kdims=['x']).overlay('c')
```


- 軸を指定
デフォルトのカラーマップが選択されるよう。

```py 
hv.Scatter((x, y)).options(color_index='y')
```

- カラーマップ

```py 
hv.Scatter((x, y)).options(color_index='y', cmap='RdBu')
```


- 指定可能なカラーマップ

    ```py 
    hv.Palette.colormaps.keys()
    ```

# コンテナ
##　ホロマップ
- 第一引数のディクショナリのキーが、スライドバーの選択項目になる。

```py
data = {
    1: hv.Curve((x,y * 1 )),
    2: hv.Curve((x,y * 2 )),
    3: hv.Curve((x,y * 2 ))
}
hv.HoloMap(data, kdim=["data"])
```

- 下記のように後から代入することもできる。

```py
holomap = hv.HoloMap(kdim=["data"])
for i in [1, 2, 3]:
    holomap[i] = hv.Curve((x, y * i))
holomap
```
## [グリッドコンテナ]( http://holoviews.org/gallery/demos/bokeh/iris_splom_example.html#bokeh-gallery-iris-splom-example)