Python
Dash
plotly

可視化ツールDashのチュートリアル - Part1: インストール~描画 -

はじめに

Dashとは、Python製のWebアプリケーションのフレームワークであり、可視化ツールのPlotlyに従う描画を行うことができます。

この記事は、Dashのチュートリアルを翻訳したものです。

なおDashでの描画にはPlotlyの知識がある程度必要なため、コチラの記事などで復習しておくと理解しやすいです。

インストール

Dashを実行するにはいくつかのライブラリをインストールする必要があります。また開発は現在進行形で行われているので定期的にアップデートしてください。
なおPython2系とPython3系の両方をサポートしています。

pip install dash==0.21.1  # The core dash backend
pip install dash-renderer==0.12.1  # The dash front-end
pip install dash-html-components==0.10.1  # HTML components
pip install dash-core-components==0.22.1  # Supercharged components
pip install plotly --upgrade  # Plotly graphing library used in examples

Dashを使って描画を行う

DashでHTMLを生成する

Dashアプリの構成は以下の2つになります。

  • layout: HTMLの外観を決める
  • interactivity: アプリとデータ操作の連携をとる

実際に棒グラフを描画するHTMLを生成してみましょう。

import dash
import dash_core_components as dcc
import dash_html_components as html

必要なライブラリをインポートします。
dash_core_componentsは、グラフやボタン、ドロップダウンなどのUIを提供しています。
dash_html_componentsは、HTMLのDivタグやH1タグなどを提供しています。

次にアプリの外観を決めましょう。

# アプリの宣言
app = dash.Dash()

# HTMLの外観を定義
app.layout = html.Div(children=[
    # <H1>タグ
    html.H1(children="Hello Dash"),

    # <div>タグ
    html.Div(children="""
    Dash: A web application framework for Python
    """),

    dcc.Graph(
        id="examplr-graph",
        figure={
            "data": [
                 {"x":[1,2,3], "y":[4,1,2], "type":"bar", "name":"SF"},
                 {"x":[1,2,3], "y":[2,4,5], "type":"bar", "name":"Montreal"}
            ],
            "layout": {
                "title": "Dash Data Visualization"
            }
        }
    )
])

上のコードでは、まず初めにHTML.Divを定義し、その中にさらにHTMLタグを作成していることがわかります。

dcc.Graphの部分でPlotlyに従う図を作成するので、データを渡し方もPlotlyの際と同様に辞書型で渡す必要があることに注意しましょう。

ではアプリを起動してみます。

if __name__ == "__main__":
    app.run_server(debug=True)

以上のコードを実行すると以下のような図がブラウザーに表示されます。

01.png

ここで引数のchildrenは、慣例として一番初めの引数として指定され、children=は省略することが可能です。

HTML:応用

dash_html_componentsライブラリでは、1つ1つのHTMLタグに辞書型でクラスを指定することができます。

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

# 背景色とテキストの色を設定
colors = {
    "background": "#111111",
    "text": "#7FDBFF"
}

app.layout = html.Div([
    html.H1(
        children="Hello Dash",
        # ここでスタイルを設定(辞書型で渡す)
        style={
            "textAlign": "center",
            "color": colors["text"]
        }
    ),
    # <h1 style="text-align: center; color: #7FDFF">Hello Dash</h1>

    html.Div(
         children='Dash: A web application framework for Python.', 
         # ここでスタイルを設定(辞書型で渡す)
         style={
             'textAlign': 'center',
             'color': colors['text']
         }
    ),
    # <div style="text-align: center; color: #7FDFF">Dash: A web application framework for Python.</div>

    dcc.Graph(
        id='example-graph-2',
        figure={
            'data': [
                {'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
                {'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': 'Montréal'},
            ],
            'layout': {
                'plot_bgcolor': colors['background'],
                'paper_bgcolor': colors['background'],
                'font': {
                    'color': colors['text']
                }
            }
        }
    )
])

if __name__ == "__main__":
    app.run_server(debug=True)

02.png

このときstyleの指定にはキャメルケース(text-alignではなくtextAlign)であることに注意しましょう。

表を作成する

Pandasのデータフレームから表を生成する。

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/'
    'c78bf172206ce24f77d6363a2d754b59/raw/'
    'c353e8ef842413cae56ae3920b8fd78468aa4cb2/'
    'usa-agricultural-exports-2011.csv')

このデータフレームは以下のようになります。

03.png

このデータをHTMLの表へ変換するための関数を定義します。

def generate_table(dataframe, max_row=10):
    return HTML.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

そしてアプリの外観を設定し起動します。

app = dash.Dash()

app.layout = html.Div(children=[
    html.H4(children='US Agriculture Exports (2011)'),
    generate_table(df)
])

if __name__ == '__main__':
    app.run_server(debug=True)

以上を実行すると以下の図が得られます。

04.png

複雑な可視化を行う

dash_core_componentsにはGraphと呼ばれるコンポーネントが存在し、Ploylyの35種類以上の図に対応しています。(Plotlyの公式HP)

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go

app = dash.Dash()

df = pd.read_csv(
    'https://gist.githubusercontent.com/chriddyp/' +
    '5d1ea79569ed194d432e56108a04d188/raw/' +
    'a9f9e8076b837d541398e999dcbac2b2826a81f8/'+
    'gdp-life-exp-2007.csv')

このデータフレームは以下のようになります。

05.png

それでは大陸でグループ分けを行い、それぞれの国のデータを可視化してみましょう。

app.layout = html.Div([
    dcc.Graph(
        id='life-exp-vs-gdp',
        figure={
            'data': [
                go.Scatter(
                    # 1人当たりGDP
                    x=df[df['continent'] == i]['gdp per capita'],
                    # 寿命
                    y=df[df['continent'] == i]['life expectancy'],
                    text=df[df['continent'] == i]['country'],
                    mode='markers',
                    opacity=0.7,
                    marker={
                        'size': 15,
                        'line': {'width': 0.5, 'color': 'white'}
                    },
                    name=i
                # 大陸ごとのデータを抽出する。
                ) for i in df.continent.unique()
            ],
            'layout': go.Layout(
                # x軸はログスケール
                xaxis={'type': 'log', 'title': 'GDP Per Capita'},
                yaxis={'title': 'Life Expectancy'},
                # left, bottom, top, right
                margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
                legend={'x': 0, 'y': 1},
                hovermode='closest'
            )
        }
    )
])

if __name__ == '__main__':
    app.run_server()

06_r2.gif

Markdownを使用する

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

markdown_text = '''
### Dash and Markdown

Dash apps can be written in Markdown.
Dash uses the [CommonMark](http://commonmark.org/)
specification of Markdown.
Check out their [60 Second Markdown Tutorial](http://commonmark.org/help/)
if this is your first introduction to Markdown!
'''

app.layout = html.Div([
    dcc.Markdown(children=markdown_text)
])

if __name__ == '__main__':
    app.run_server()

07.png

他のdash_core_componentsを試す

dash_core_componentsには、Graph以外にもドロップダウンやマークダウン、テキストボックスなど様々なオプションが存在します。

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

app.layout = html.Div([
    html.Label('Dropdown'),
    dcc.Dropdown(
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': u'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        # ここに選択した値が入る(ここではデフォルト値を設定している)
        value='MTL'
    ),

    html.Label('Multi-Select Dropdown'),
    dcc.Dropdown(
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': u'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        value=['MTL', 'SF'],
        # 複数の選択を可能にする引数
        multi=True
    ),

    html.Label('Radio Items'),
    dcc.RadioItems(
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': u'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        value='MTL'
    ),

    html.Label('Checkboxes'),
    dcc.Checklist(
        options=[
            {'label': 'New York City', 'value': 'NYC'},
            {'label': u'Montréal', 'value': 'MTL'},
            {'label': 'San Francisco', 'value': 'SF'}
        ],
        # リスト型で与えていることに注意
        values=['MTL', 'SF']
    ),

    html.Label('Text Input'),
    dcc.Input(value='MTL', type='text'),

    html.Label('Slider'),
    dcc.Slider(
        min=0,
        max=9,
        marks={i: 'Label {}'.format(i) if i == 1 else str(i) for i in range(1, 6)},
        value=5,
    ),
# 表示を2列に分けるstyleを設定
], style={'columnCount': 2})

if __name__ == '__main__':
    app.run_server(debug=True)

08.gif

困ったときは

それぞれの引数など何かわからないことがあった場合は、help関数を使いましょう。

help(dcc.Dropdown)

終わりに

以上がDashを使用してグラフをHTMLに描画する方法です。
どんな図を出力するにしても

  • layout
  • interactivity

の2つを設定することが基本です。