DataframeからBokeh(Rangetoolとselect)でインタラクティブなグラフを描こう

#概要
　普段はArduinoやM5stackなどのマイコンやガジェットをいじってるのですが、何台もセンサーをつないでデータが集まったのはいいものの、それをインタラクティブに可視化する手段があまりない。何かいいのはないか？ということでBokehを見つけて勉強を始めました。
　ところが日本語の参考になる記事は多くなく[公式ドキュメント](https://docs.bokeh.org/en/latest/index.html)や[Gallery-Bokeh 2.0.0 Documentation](https://docs.bokeh.org/en/latest/docs/gallery.html)、Qiita記事を参考にしましたがなかなか苦労したのでこの記事を見て役に立てれば幸いです。

#完成したグラフ
　読み込んだcsvをDataframeにし、X-AxisとY-Axisにcsv内のcolumnをSelectを使って選択しグラフ化しています。下グラフの選択範囲をRangetoolで選択し拡大画像が上に描画されるようにしています。
　なお今回csvは[csvからbokehグラフ出力](http://harmonizedai.com/article/csvtohtml/)の記事のcsvをそのままお借りしています。本来はcolumnが2種類以上あるcsvであればどんなデータでも問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542127/1bad8085-badd-2c09-830d-585d45de032a.png)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">結構手こずったけどRangetool×Select完成！<a href="https://twitter.com/hashtag/bokeh?src=hash&amp;ref_src=twsrc%5Etfw">#bokeh</a> <a href="https://t.co/7m9Fy2683a">pic.twitter.com/7m9Fy2683a</a></p>&mdash; サクヤtypeR 化学工学×AIoT (@typeR_Anonymous) <a href="https://twitter.com/typeR_Anonymous/status/1241711942399647745?ref_src=twsrc%5Etfw">March 22, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#実行環境
Windows10
Anaconda
Python3.7
pandas1.0.1
Bokeh 1.4

#ソースコード

```range_select.py
import pandas as pd
from bokeh.io import curdoc
from bokeh.layouts import column, layout, row
from bokeh.models import  RangeTool, Select
from bokeh.plotting import figure

df = pd.read_csv('bachelors.csv')
columns = sorted(df.columns)

#create figure function
def create_figure():
    xs = df[x.value].values
    ys = df[y.value].values
    x_title = x.value.title()
    y_title = y.value.title()

    kw = dict()
    kw['title'] = "%s vs %s" % (x_title, y_title)

    p = figure(plot_height=250, plot_width=600, tools="pan,box_zoom,reset,save",
                 **kw,x_range=(xs[10], xs[15]))

    p.xaxis.axis_label = x_title
    p.yaxis.axis_label = y_title
    p.line(x=xs, y=ys)

    range_select = figure(title="選択ボックスの中央と端をドラッグして、上の範囲を変更します。",
                plot_height=250, plot_width=600, y_range=p.y_range,
                tools="", toolbar_location=None )

    range_tool = RangeTool(x_range=p.x_range)
    range_tool.overlay.fill_color = "navy"
    range_tool.overlay.fill_alpha = 0.2

    range_select.line(x=xs, y=ys)
    range_select.ygrid.grid_line_color = None
    range_select.add_tools(range_tool)
    range_select.toolbar.active_multi = range_tool
    range_select.xaxis.axis_label = x_title
    range_select.yaxis.axis_label = y_title

    controls = column(x, y, width=200)
    graph = column(p, range_select)
    
    return controls, graph

#update function
def update(attr, old, new):
    layout.children[:] = create_figure()[:]

#create select widget
x = Select(title='X-Axis', value='Year', options=columns)
x.on_change('value', update)

y = Select(title='Y-Axis', value='Agriculture', options=columns)
y.on_change('value', update)

controls = column(x, y, width=200)
graph = create_figure()[1]
layout = row(controls, graph)

curdoc().add_root(layout)
```
#実行方法
以下をターミナルで打ち込み実行すると、Bokeh serverが立ち上がりローカルホストからctrl+クリックでブラウザにグラフを表示させることができます。

```
bokeh serve range_select.py
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542127/4d77a47f-f652-8d5c-b65c-3fee9b898180.png)



#おわりに
インタラクティブなグラフが手軽にできると見てるだけで結構楽しいです。60行程度のコードでできるのも驚きです。
Dataframeでグラフ化できると機械学習モデルの結果を同時に表示させたりsqlから多種のデータを読みこんで描画させたり、など応用が広がってよさそうです。


##参考
[Gallery-Bokeh 2.0.0 Documentation](https://docs.bokeh.org/en/latest/docs/gallery.html)
[@kimisyoさんのBokeh記事@Qiita](https://qiita.com/kimisyo/items/8aac9c5a08d883d94bbb)
[csvからbokehグラフ出力](http://harmonizedai.com/article/csvtohtml/)