投資のためのデータサイエンス

個人の投資活動に役立つデータ分析にまつわる話題を綴ります。

Dashによるwebアプリの構築の基礎

Pythonによってデータの分析をして得られたグラフなどのアウトプットについては、画像ファイルに保存して、Word文書やPowerPointのスライドに貼り付けて報告資料にする、というのが最も一般的でしょう。一方、実務ではエンドユーザが自ら分析したい変数や条件を指定してプログラムを動かして結果を得るようにする、すなわちプログラムを実装することが求められる場合も多くあります。
このためPythonにもエンドユーザが直接扱えるwebアプリを構築するためのツールが多数提供されています。ここでは、その中の一つであるDashライブラリを用いて、ユーザが指定したデータ表を出力できるプログラムを作成します。
DashをJupyter Notebook (Google Colaboratory)上で動かすためには、普通のDashの代わりにJupyter Dashライブラリを用います。ここでは全国都道府県の様々な指標を収録したエクセルファイル(データ出典:https://www.nstac.go.jp/SSDSE/)から、ドロップダウンリストで指定された都道府県のデータ表を表示してみます。

# ライブラリのインポート
import numpy as np
import pandas as pd
from jupyter_dash import JupyterDash
import pandas as pd
import numpy as np
import dash_html_components as html
import dash_core_components as dcc
from dash import dash_table as dt
import plotly.graph_objects as go
from dash.dependencies import Input, Output
from dash_table import DataTable, FormatTemplate
from dash_table.Format import Format

まず、原データのExcelファイルを読み込みます。

 df1 = pd.read_excel('/content/drive/My Drive/Colab Notebooks/都道府県各種指標.xlsx',sheet_name='data')
 df1.head(3)

f:id:nicjps230:20211127234202j:plain
このデータフレームの各種指標の列を縦に再展開します。

df501 = pd.melt(df1, id_vars=['年度','都道府県'], value_vars=df1.columns[3:])
df501.head()

f:id:nicjps230:20211127234222j:plain
次に、外部のスタイルシートを読み込み、JupyterDashの「箱」にあたるものと、画面に表示する列を定義します。

# 外部スタイルシートを読み込む
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
# JupyterDashの「箱」を作る
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
# 表示する列を定義する
columns1 = [
    dict(id='年度',name='年度'),
    dict(id='都道府県',name='都道府県'),
    dict(id='variable', name='指標'),
    dict(id='value', name='値')
]

次に、画面に表示するコンテンツとして、ドロップダウンリストとデータテーブルを定義します。ドロップダウンリストでは都道府県と指標を選び、これらをデータテーブルのフィルターとします。各コンテンツにはid=で参照用の名前をつけ、詳細は以下に続くコードで設定します。

# ドロップダウンリストを定義する
content1 = dcc.Dropdown(
    id = 'dropdown-for-pref', # id名はコールバックで必要
    options = [{'label':i,'value':i} for i in df501['都道府県'].unique()], # 値を選択する列を指定
    value = '東京都' # デフォルト値を設定
)
content2 = dcc.Dropdown(
    id = 'dropdown-for-variable', # id名はコールバックで必要
    options = [{'label':i,'value':i} for i in df501['variable'].unique()], # 値を選択する列を指定
    value = '総人口' # デフォルト値を設定
)
# データテーブルを定義する
content3 = html.Div(id='datatable-paging',children=[]) # id名はコールバックで必要

次に、上で定義した2つのコンテンツからなる画面のレイアウトを定義します。

# 画面のレイアウトを定義する
app.layout = html.Div([
                       html.Div(content1, style={'width': '25%', 'display': 'inline-block','margin-right': 10}),
                       html.Div(content2, style={'width': '25%', 'display': 'inline-block','margin-right': 10}),
                       content3
])

次に、データテーブルを描画する関数を定義します。データテーブルは一行おきに色を濃淡に分けて見やすくします。

# データテーブルを描画する関数を定義する
# 一行おきに色のコントラストをつけたデザインにする
def create_dash_table(df):
  return dt.DataTable(
      data=df.to_dict('records'),
      columns=columns1,
      style_cell={'fontsize':20, 'font-family':'IPAexGothic'},
      style_cell_conditional=[
                              {
                                  'if': {'column_id':c},
                                  'textAlign': 'left'
                              } for c in ['年度','都道府県']
      ],
      style_data={
          'color':'black',
          'backgroundColor':'white'
      },
      style_data_conditional=[
                          {
                              'if': {'row_index':'odd'},
                              'backgroundColor': 'rgb(220,220,220)',
                          }
      ],
      style_header={
          'backgroundColor':'rgb(210,210,210)',
          'color':'black',
          'fontWeight':'bold'
  })

続いてコールバックを定義します。ここでは、どこから入力してどこから出力するかを指定します。ここで上でつけたid名を使います。またcomponent_property=でその属性を指定します。コールバックにより起動される関数はその下に空行を挟まずに記述します。関数名は何でもかまいません。ここでは、ドロップダウンリストにより指定された都道府県と指標でデータをフィルターにかけ、データテーブルを再表示しています。

# コールバックを定義する(ドロップダウンリストで選択された値をもとに表を作成する)
# どこから入力し、どこへ出力するかを指定する
@app.callback(
    Output(component_id='datatable-paging',component_property='children'),
    [Input(component_id='dropdown-for-pref',component_property='value'),
    Input(component_id='dropdown-for-variable',component_property='value')]
)
def update_table(input_value1,input_value2): # 行間をあけずに関数部分を書く(関数名は何でも良い。引数は上で定義した入力が順に並ぶ)
  df511 = df501[df501['都道府県'] == input_value1] # 値を選択する列を指定
  df512 = df511[df511['variable'] == input_value2]
  df512.sort_values('年度', ascending=True,inplace=True)
  return create_dash_table(df512)

最後にサーバを起動します。この部分を実行すると、下にリンクのURLが表示され、それをクリックするとアウトプット画面が表示されます。

# サーバーを起動する
app.run_server()

f:id:nicjps230:20211127234318j:plain
上記画面のドロップダウンリストで都道府県と指標を選ぶとその都道府県の指標のデータテーブルが表示されます。
(2011/11/27 複数入力のドロップダウンリスト利用に変更しました)