Plotly Dashを使ってインタラクティブなダッシュボードを作成する

dash入門

Plotly Dashはインタラクティブなダッシュボードを作成するフレームワークです。

インタラクティブというのは、カーソルを当てた際に数値等の情報が表示されたり、グラフで選択した部分を拡大したりできるような、動的なダッシュボードです。

これにより、単に表示された結果を見るだけでなく、自分から気になる部分などを分析することができます。

Dashを使うと、非常に便利かつ見栄えのよいダッシュボードを作成できますが、意外にもそれほど難しくはありません。

比較的シンプルで、ドキュメントも充実しているので、個人的にはDashは非常にオススメのツールです。

どんなものが作れるか公式HPのサンプルを見てみましょう。

こちらは静的なスクリーンショットです。

https://dash-gallery.plotly.host/dash-manufacture-spc-dashboard/

こちらは動画にしています。見たい部分を拡大したり、動かしたりとできるので非常に便利です。

https://dash-gallery.plotly.host/dash-wind-streaming/

他にもこちらに例がありますので、興味がある方は覗いてみてください。

ということで、今回から数回にわたって、Dashを使ったダッシュボードの作成方法を紹介したいと思います。

なお、Dashを使う場合、グラフの作成方法がPlotlyと同じなので、Plotlyが使える人にとっては非常に簡単だと思います。

Plotlyに慣れていない人は以下の記事等を参考にしていただければと思います。

今回は、以下のような簡単なダッシュボードを作成します。

非常にシンプルですが、基本的な使い方は理解できると思います。

では、見ていきましょう。

Jupyter Dashの基本的な使い方

まずは、Dashをインストールしましょう。

ここでは、Jupyter Notebook上で動かせるJupyter Dashを使いたいと思います(Jupyter Dashを使わない人はDashをインストールしてください)。

!pip install jupyter-dash

Jupyter Notebookを開いて、JupyterDashをインポートしましょう。

from jupyter_dash import JupyterDash

そして、その他の必要なモジュール類をインポートします。

import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objects as go

最初の2つは、HTMLコンポーネントCoreコンポーネントと呼ばれるダッシュボードを作成する上で必要なパーツです。

3つ目は、plotlyを使ってグラフを描くために必要なものです。

次に、以下のコードを描きます(最初はおまじないと思っていただいて大丈夫です)。

app = JupyterDash(__name__)
server = app.server

さて、ここからダッシュボード部分のコードを書いていきます。

先ほどインポートしましたが、Dashでダッシュボードを作成するには、以下の2つのコンポーネントと呼ばれるものを使います。

  • HTMLコンポーネント
  • Coreコンポーネント

この2つを組み合わせて、動的なダッシュボードを作成していきます。

では、それぞれを見ていきましょう。

HTMLコンポーネント(dash_html_components)

上記でインポートしたdash_html_components(HTMLコンポーネント)は、その名の通りHTMLを構成します。

この部分はWebダッシュボードの静的なパーツの部分になります。

例えば、h1タグやdivタグ、pタグなどです。

Dashでは以下のように使います。

app.layout = html.Div(children=[html.H1('Python Dash'),
                               html.H2('Jupyter Notebook'),
                               html.P('ここではDashでダッシュボードを作成します.')
                               ])
app.run_server()

作法としては、Divタグで囲み、childrenというプロパティにリスト形式でタグを渡してやります

この場合ですと、Divタグの中に、H1タグ、H2タグ、Pタグを入れています。

なお、”children=”は省略しても大丈夫ですので、今後は省略します。

そして、以下を実行するとサーバーが立ち上がります。

app.run_server()

以下のように出ていれば、URLをクリックすることで、画面が表示されます

Dash app running on:
"http://127.0.0.1:8050/"

このような画面になったのではないでしょうか?

ちなみに、サーバーを起動するところで、以下のようにmode=”inline”と指定すると同一notebook上にダッシュボードが表示されます

app.run_server(mode="inline")

なお、プログラムを修正して実行する際は、最初のこの部分から再実行しましょう。

app = JupyterDash(__name__)
server = app.server

Coreコンポーネント(dash_core_components)

Coreコンポーネントはインタラクティブなテーブルやグラフなどを表示する部分になります。

例えば、グラフを表示する場合はdcc.Graph(…)として、…の部分にグラフを渡します。

他には、ドロップダウン・メニューを表示するDropdownや、範囲などを指定するSlider、テキスト情報を表示するTextAreaなど多数あります。

色々なコンポーネントがありますので、使いたいコンポーネントを探すにはこちらをご参照ください。

Dash Core Components | Dash for Python Documentation | Plotly
The Dash Core Component library contains a set of higher-level components like sliders, graphs, dropdowns, tables, and more.

今後、これらのコンポーネントについて詳しく紹介していこうと思いますが、とりあえず、ここでは簡単なグラフを作成する方法を紹介します。

まずは、plotlyを使って図を作成しましょう。

fig = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'],
                         y=df['スノーピーク']))
fig.update_layout(title='スノーピークの株価推移')

これで以下のような図ができます。

Plotlyを使った線グラフの作成方法はこちらで解説していますので、馴染みのない方は以下の投稿をご参照ください。

Python Plotly入門(②Line Chart)

そしてこの作成したグラフをハイライト部分のようにdcc.Graphに設定します。

app.layout = html.Div([html.H1('Python Dash'),
                       html.H2('Jupyter Notebook'),
                       html.P('ここではDashでダッシュボードを作成します.'),
                       dcc.Graph(figure=fig)
                       ])

すると以下のようなダッシュボードが表示されます。

カーソルを当てた際にテキスト情報が表示されますし、特定の範囲を選択するとそこが拡大されます。

グラフの表示の基本は以上になります。

ドロップダウン・メニューの追加

これだけでは面白くないので、ドロップダウン・メニューを追加してみましょう

ドロップダウン・メニューはdash_core_componentのDropdownを使います。

app.layout = html.Div([html.H1('Python Dash'),
                       html.H2('Jupyter Dash'),
                       html.P('ここではDashでダッシュボードを作成します.'),
                       dcc.Dropdown(options=[
                                      {'label': 'スノーピーク', 'value': 'スノーピーク'},
                                       {'label': '楽天', 'value': '楽天'},
                                       {'label': 'ANA', 'value': 'ANA'},
                                       {'label': 'ぐるなび', 'value': 'ぐるなび'},
                                       {'label': 'アルペン', 'value': 'アルペン'},
                                       {'label': '三越', 'value': '三越'},
                                       {'label': 'トヨタ', 'value': 'トヨタ'},
                                       ],
                                    multi=True,
                                    ),
                       dcc.Graph(figure=fig)
                       ])

ドロップダウン・メニューで何を表示するかはoptionプロパティを使って、辞書型変数を渡すことで設定します。

“label”には表示するラベルを指定し、それが選択された場合に返される値を”value”に設定します。

valueの使い方については、のちほど説明します。

上ではmulti=Trueとして、複数を選択することを可能にしています。

コンポーネントの使い方は適宜以下でご確認ください。

Dash Core Components | Dash for Python Documentation | Plotly
The Dash Core Component library contains a set of higher-level components like sliders, graphs, dropdowns, tables, and more.

すると以下のような画面になると思います。

設定したドロップダウン・メニューが追加されていますね。

まだ、この段階ではドロップダウン・メニューから選択しても、何も起こりません。

選択されたラベルを使ってグラフを変更するにはあとで説明するコールバック(Callback)という機能を使います。

CSSを設定する

CSSを設定するには、最初にexternal_stylesheetsをでCSSを指定します。

ここでは、チュートリアルで使っているものを設定していますが、自作のCSSを設定しても構いません。

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
server = app.server

コールバック(Callback)の基本的な使い方

ドロップダウン・メニューで選択した値を使ってグラフを変えたり、スライダーの設定によってグラフを変えたりするには、コールバックという機能を使います。

コールバックは、あるコンポーネントからラベルや数値といったインプットを受け取り、何等かの処理をして数値やグラフなどをアウトプットとして返す機能です。

ここでは、ドロップダウン・メニューで選択された銘柄名をインプットとして、選択された銘柄名を載せたグラフをアウトプットにしたいと思います。

実際にコードを見た方がわかりやすいと思いますので、コードを作成しながら説明していきたいと思います。

まず、dash.dependnciesにあるInput、Outputをインポートします。これは、コールバック関数への入力と、そこからの出力を定義するためのものです。

from dash.dependencies import Input, Output

そして、サーバーを設定します。

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
server = app.server

次に、先ほどと同様にダッシュボードのレイアウトを作成します。

先ほどとほぼ同じですが、違う点は入出力をするhtmlコンポーネント、coreコンポーネントにidを付ける必要があることです。(styleなども少しだけ設定しますが、これについては次回以降に説明したいと思います)

app.layout = html.Div([html.H1('Python Dash'),
                       html.H2('Jupyter Dash'),
                       html.P('ここではDashでダッシュボードを作成します.'),
                       dcc.Dropdown(id='stock_chart_dropdown',
                                    options=[
                                             {'label': 'スノーピーク', 'value': 'スノーピーク'},
                                             {'label': '楽天', 'value': '楽天'},
                                             {'label': 'ANA', 'value': 'ANA'},
                                             {'label': 'ぐるなび', 'value': 'ぐるなび'},
                                             {'label': 'アルペン', 'value': 'アルペン'},
                                             {'label': '三越', 'value': '三越'},
                                             {'label': 'トヨタ', 'value': 'トヨタ'},
                                              ],
                                    multi=True,
                                    style={'width': '50%'},
                                    ),
                       html.Div(id='stock_chart')
                       ], style={'margin-left': '5%', 'margin-right': '5%'})

ですので、インプットするコンポーネントであるドロップダウン・メニューに”stock_chart_dropdown”というidを振ります。

そして、選択された銘柄名をもとにグラフを作成して出力するので、グラフを設定するhtml.Divには”stock_chart”というidを振っています。

続いて、ドロップダウン・メニューからインプットを取ってきて、グラフを変更し出力するというコールバック部分を作成します。

以下のようにします。詳細はこれから説明します。

@app.callback(
  Output(component_id='stock_chart', component_property='children'),
  Input(component_id='stock_chart_dropdown', component_property='value')
)
def update_graph(company_names):
  if company_names is None or company_names == []:
    return None
  title = ''
  fig = go.Figure()
  for company_name in company_names:
    fig.add_trace(go.Scatter(x=df['Date'],
                            y=df[company_name],
                            name=company_name))
    title += company_name + ', '
  title = title[:-2]
  fig.update_layout(title=title+'の株価推移',
                    showlegend=True,
                    width=1000,
                    height=500)
  return dcc.Graph(figure=fig)

先ほども言いましたが、Jupyter Dashの場合、app.layoutを修正する場合は毎回、app = JupyterDash(…)から実行しなおしましょう。

app.layoutの修正部分やcallbacckの部分だけを再実行するだけだと、うまくいかない場合があります。

@app.callback

まず、コールバック関数の前に@app.callbackと書きます。

引数はInputとOutoputです。

さらにInput、Outputはともにcomponent_idとcomponent_propertyを引数として取ります。

@app.callback(
  Output(component_id='stock_chart', component_property='children'),
  Input(component_id='stock_chart_dropdown', component_property='value')
)

component_idは、どのコンポーネントかを指定します。

例えばインプットであればドロップダウン・メニューで選択されたものをインプットするので、component_idにはドロップダウン・メニューを表すidである”stock_chart_dropdown”を指定しています。

アウトプットは、idが”stock_chart”のDivタグにグラフを出力するので、component_idは”stock_chart”を指定します。

component_propertyはcomponent_idで選んだコンポーネントのどのプロパティを使うか?を指定します。

インプットであれば、ドロップダウン・メニューの選択された項目を表す”value”を指定します。

アウトプットは、Divタグのchildrenプロパティに出力するので、component_propertyには”children”を指定します。

関数の作成

そのあとに関数を書きます。

関数名は何でも構いません。ここでは、update_graph(company_names)としています。

引数はInput()で指定されたものです。

ここでは、ドロップダウン・メニューの選択される項目は銘柄名なので、company_nameという変数名にしています。

初めの数行は、銘柄が選択されていない場合の処理などを入れています(結構こういったところが面倒くさかったりします)。

あとは、以下のコードで、Plotlyの作法に従ってグラフfigを作成しています。

fig = go.Figure()
  for company_name in company_names:
    fig.add_trace(go.Scatter(x=df['Date'],
                            y=df[company_name],
                            name=company_name))
    title += company_name + ', '
  title = title[:-2]
  fig.update_layout(title=title+'の株価推移',
                    showlegend=True,
                    width=1000,
                    height=500)

そして、dcc.Graphコンポーネントのfigureプロパティにfigを指定し、グラフ・コンポーネントを返しています。

return dcc.Graph(figure=fig)

最後に、Webサーバーを起動します。

app.run_server()

すると、以下のようなダッシュボードが出来上がります。

まとめ

今回は、Pythonを使ってダッシュボードを作成するPlotlyのDashの基本的な使い方を見てきました。

基本は以上で、あとはどんなコントロールを使うか、どのようなグラフなどを使ってどのように配置するか、を決めていけば本格的なダッシュボードを作成することができます。

次回以降はもう少し各パーツの詳細を見ていきたいと思います。

では!

mm0824

システム開発会社や金融機関で統計や金融工学を使ったモデリング・分析業務を長く担当してきました。

現在はコンサルティング会社のデータ・サイエンティストとして機械学習、自然言語処理技術を使ったモデル構築・データ分析を担当しています。

皆様の業務や勉強のお役に立てれば嬉しいです。

mm0824をフォローする
dash入門 データ可視化
mm0824をフォローする
楽しみながら理解する自然言語処理入門

コメント

タイトルとURLをコピーしました