インタラクティブなグラフをwebアプリで公開するには
Bokehサーバーを使用する必要があります。
今回はBokehサーバーを利用したweb上で表示して
ユーザーがいじる事ができるインタラクティブグラフの作成方法を紹介します。
まずはインポート
1 2 3 4 5 6 7 8 |
#アウトプットと別画面表示 from bokeh.io import output_file, show #ユーザーが入力できるテキスト、ボタン、パラグラフウィジェット from bokeh.models.widgets import TextInput, Button, Paragraph #レイアウトをアレンジするオブジェクト from bokeh.layouts import layout |
とりあえず何かそれっぽいhtmlファイルを生成
1 2 3 4 5 6 7 8 9 10 11 12 |
#html出力 Bokehサーバー使用時には不要なので後で削除します。 output_file("bokehserver1.html") #テキスト入力フォームとボタン text_input=TextInput(value="ABC") button=Button(label="ボタンText") #テキスト、ボタンのウィジェットを指定 lay_out=layout([[button,text_input]]) #表示 こちらもBokehサーバー使用時には不要なので後で削除します。 show(lay_out) |
実行結果
何かができました(笑)
ボタンもあればテキスト入力フォームも動いています。
この時点ではまだBokehサーバーにはつながっておりませんので
何も動作はしません。
上記のコードは違いを理解する為だけにありますので
実際はhtmlのアウトプットやshowメソッドは不要です。
では実際にBokehサーバーを使用して動くようにしてみます。
動的にテキストを変化させる為にcurdocオブジェクトを使用します。
1 2 |
#curdocをインポート from bokeh.io import curdoc |
ボタンを押した際に発生するアクションを設定
1 2 3 4 5 6 |
def update(): output.text="Hello," + text_input.value button.on_click(update) curdoc().add_root(lay_out) |
上記2つを元のコードに合わせると以下のようになります。
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from bokeh.io import curdoc from bokeh.models.widgets import TextInput, Button, Paragraph from bokeh.layouts import layout text_input=TextInput(value="AAA") button=Button(label="Text") output=Paragraph() def update(): output.text="Hello," + text_input.value button.on_click(update) # button.on_click(update) lay_out=layout([[button,text_input],[output]]) curdoc().add_root(lay_out) |
エディターで上記コードをwidget.pyという名前で保存し、
コマンドラインから実行します。
例:
C:\Users\xxxx>bokeh serve widgets.py
すると以下のようにlocalhostのアドレスが出てきます
2018-07-21 22:54:49,162 Bokeh app running at: http://localhost:5006/widgets
ブラウザにhttp://localhost:5006/widgetsを打ち込むと先ほどの動かなかった
webアプリが動くようになります。
以下は元素データから取得した元素ごとの沸点を表示するグラフのコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
#ライブラリーのインポート from bokeh.plotting import figure from bokeh.io import curdoc from bokeh.sampledata.periodic_table import elements from bokeh.models import Range1d, PanTool, ResetTool, HoverTool, ColumnDataSource, LabelSet, Select from bokeh.models.annotations import Span, BoxAnnotation, Label, LabelSet from bokeh.layouts import layout #N/Aを含む行を削除する118あった行が31個まで減る elements.dropna(inplace=True) #辞書を使用してガスは黄色というように記憶させる colormap={'gas':'yellow','liquid':'orange','solid':'red'} #elementsのデータフレームに色(color)のカラムを追加しつつカラムstandard stateにある値に対する色を入れていく elements['color']=[colormap[x] for x in elements['standard state']] #データフレームのままだと柔軟に動かせないのでカラムデータソースに3つに分けて入れる gas=ColumnDataSource(elements[elements["standard state"]=="gas"]) liquid=ColumnDataSource(elements[elements['standard state']=='liquid']) solid=ColumnDataSource(elements[elements['standard state']=='solid']) #figureオブジェクトを作成 f=figure() #glyphの作成 無地のグラフに一本ずつグラフの線を追加していく #今回は丸で表すのせcircle()を追加し、その色やサイズを指定していく f.circle(x="atomic radius",y="boiling point",#x軸を原子のサイズ、y軸を沸点に指定 size=[i/10 for i in gas.data["van der Waals radius"]],#sizeカラムを作り、そこに半径の1/10の数値を入れる fill_alpha=0.2,color="color",legend="Gas",source=gas)#colorは先程追加したカラムを参照するので""で指定、sourceはカラムデータソースの変数なので""はつかない #以下もう2本のグラフを追加する f.circle(x="atomic radius", y="boiling point", size=[i/10 for i in liquid.data["van der Waals radius"]], fill_alpha=0.2,color="color",legend='Liquid',source=liquid) f.circle(x="atomic radius", y="boiling point", size=[i/10 for i in solid.data["van der Waals radius"]], fill_alpha=0.2,color="color",legend='Solid',source=solid) #x軸y軸に名前を付ける f.xaxis.axis_label="Atomic radius" f.yaxis.axis_label="Boiling point" #各要素(3つ分)の沸点の平均を計算する、sumでカラム内要素を足してlenで取得したカラム内項目数で割る gas_average_boil=sum(gas.data["boiling point"])/len(gas.data["boiling point"]) liquid_average_boil=sum(liquid.data["boiling point"])/len(liquid.data["boiling point"]) solid_average_boil=sum(solid.data["boiling point"])/len(solid.data["boiling point"]) #沸点の最低値と最高値を取得 solid_min_boil=min(solid.data["boiling point"]) solid_max_boil=max(solid.data["boiling point"]) #各要素(3つ分)の平均値に目印となる(Spanと呼ぶ)色付きの線を設定する #これら平均値を表す目印はユーザーの指定によって変化する span_gas_average_boil=Span(location=gas_average_boil,dimension="width",line_color="yellow",line_width=2) span_liquid_average_boil=Span(location=liquid_average_boil, dimension='width',line_color='orange',line_width=2) span_solid_boil=Span(location=solid_average_boil, dimension='width',line_color='red',line_width=2) #上記で設定した平均値を表す目印をfigure()オブジェクトに追加する #無地のグラフに一本ずつグラフの線を追加していく作業を先ほど行ったのでここに更に足す形になる f.add_layout(span_gas_average_boil) f.add_layout(span_liquid_average_boil) f.add_layout(span_solid_boil) #span_solid_boilの位置に関する値をアップデートする自作関数を設定 #select.valueから帰ってくる値はstringとなっているのでfloatに変換する必要がある def update_span(attr, old, new): span_solid_boil.location=float(select.value) #変数optionの中にリスト形式でデータから取得した値とそれを説明する文字列をタプルのペアで入れる #データから取得した値はstringに変換する必要がある options=[ (str(solid_average_boil),"Solid Average Boiling Point"), (str(solid_min_boil),"Solid Minimum Boiling Point"), (str(solid_max_boil),"Solid Maximum Boiling Point")] #選択ウィジェットを作成 select=Select(title="Select span value", options=options) select.on_change("value",update_span) #選択ウィジェットの配置と有効化 lay_out=layout([[select]]) curdoc().add_root(f) curdoc(.add_root(lay_out)) |
コメントを残す