R を使っている方はご存知だと思うが、R には {Shiny}
というパッケージがあり、データ分析の結果を インタラクティブな Web アプリとして共有することができる。{Shiny}
って何?という方には こちらの説明がわかりやすい。
Python でも {Shiny}
のようなお手軽可視化フレームワークがあるといいよね、とたびたび言われていたのだが、spyre
という なんかそれっぽいパッケージがあったので触ってみたい。
インストール
pip で。
pip install dataspyre
使い方
現時点で ドキュメンテーションはない ので、README と examples フォルダを見る。サンプルとして株価を取得してプロットするWebアプリを作ってみたい。spyre
で Webアプリを作る手順は以下の3つ。
spyre.server.App
を継承したクラスを作る。- 描画をコントロール/指示するクラス変数を指定する。
- 描画を行うメソッド
getData
,getPlot
を書く。メソッド名は描画内容 (output_type) ごとに固定。
最初は examples のものを書き換えながら作るのが楽。各クラス変数/メソッドは相互に関連するため、プログラム全体を示した上で必要と思われる箇所にコメントを入れた。
補足 株価の取得には以下のパッケージを使う。
#!/usr/bin/env python # -*- coding: utf-8 -*- from spyre import server import pandas as pd pd.options.display.mpl_style = 'default' # あらかじめデータを取得しておく # 終値のみを取得し、一つのDataFrameに結合 import japandas as jpd toyota = jpd.DataReader(7203, 'yahoojp', start='2015-01-01')[[u'終値']] toyota.columns = [u'トヨタ'] honda = jpd.DataReader(7267, 'yahoojp', start='2015-01-01')[[u'終値']] honda.columns = [u'ホンダ'] df = toyota.join(honda) class StockExample(server.App): title = u"株価のプロット" # 左側のペインに表示するUIを指定 inputs = [{"input_type":'dropdown', "label": 'Frequency', # label は UI に表示されるラベル # value はそれが選択された時にプログラム中で利用される値 "options" : [ {"label": "月次", "value":"M"}, {"label": "週次", "value":"W"}, {"label": "日次", "value":"B"}], # 変数のキー名 # 変数は各描画メソッド (getData, getPlot) に 引数 params として渡される "variable_name": 'freq', "action_id": "update_data" }] # 画面を更新する設定 controls = [{"control_type" : "hidden", "label" : "update", "control_id" : "update_data"}] # 描画するタブ数とその名前を指定 tabs = [u"トヨタ", u"ホンダ", u"データ"] # tabs で指定したそれぞれのタブに描画する内容を指定 outputs = [{"output_type" : "plot", # matplotlib のプロットを描画する "output_id" : "toyota", # 描画時の id "control_id" : "update_data", "tab" : u"トヨタ", # 描画先のタブ名 "on_page_load" : True }, {"output_type" : "plot", "output_id" : "honda", "control_id" : "update_data", "tab" : u"ホンダ", "on_page_load" : True }, {"output_type" : "table", # DataFrameを描画する "output_id" : "table_id", "control_id" : "update_data", "tab" : u"データ", "on_page_load" : True }] def getData(self, params): """ output_type="table" のときに呼ばれる。DataFrameを返すこと。 """ # inputs で指定した variable_name をキーとして、対応する変数を読み込める # freq にはユーザの選択に応じて、value として指定された M, W, B いずれかが入る freq = params['freq'] # freq でグループ化し平均をとる tmp = df.groupby(pd.TimeGrouper(freq)).mean() return tmp def getPlot(self, params): """ output_type="plot" のときに呼ばれる。matplotlib.figureを返すこと。 """ tmp = self.getData(params) # 同じ output_type で複数のタブを描画したい場合は、 output_id で分岐 if params['output_id'] == 'toyota': ax = tmp[[u'トヨタ']].plot(legend=False) return ax.get_figure() elif params['output_id'] == 'honda': ax = tmp[[u'ホンダ']].plot(legend=False) return ax.get_figure() else: raise ValueError app = StockExample() # port 9093 で Webサーバ + アプリを起動 app.launch(port=9093)
実行後、ブラウザで http://127.0.0.1:9093 を開くと以下のような画面が表示される。inputs
で指定した項目が左側のメニューに、 tabs
で指定した項目がタブとして表示されている。
ドロップダウンやタブの選択を切り替えると、動的にグラフやデータが更新されることがわかる。
DataFrame
の描画はちょっとおかしく、index
自体が描画されず、名前だけが表示されている。これは後日 issue あげて直そうかと思う。
まとめ
お手軽可視化フレームワーク spyre
を試してみた。現行の {Shiny}
と比べると 機能/UI とも十分ではないが、いくつかのデータ / プロットをインタラクティブに共有する用途であれば使えそうだ。
印象として、はじめて {Shiny}
を触ったあの日の気持ちを思い出したような気がする、、。