Python Dash + Plotlyでダッシュボードを作成（マルチページアプリ対応）

# Python Dash + Plotlyでダッシュボードを作成（マルチページアプリ対応）

今回はダッシュボードアプリを実用レベルで使えるように
レイアウトをそれぞれ別ファイルに記載し別URLで違うグラフを表示できるようにする。

Dashドキュメント →　https://dash.plotly.com/

## インストール

```
$ pip install dash==1.19.0
$ pip install pandas
```

## Dash ディレクトリ構成

```
dash/  
|-- apps  
|   |-- app1.py  
|   |-- app2.py  
|   `-- __init__.py  
|-- app.py  
|-- Dockerfile  
|-- index.py  
`-- requirements.txt  
```

## Docker実行環境

### Dockerfile

Dash実行用のコンテナを作成
DashはPython環境で実行されます。

```Docker
FROM python:3.7.4

WORKDIR /app
ADD . /app

RUN apt-get update && apt-get install -y locales && locale-gen ja_JP.UTF-8 && apt-get clean;
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

ENV TZ Asia/Tokyo
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8

ENV PORT 8080
EXPOSE 8080

CMD ["python", "index.py"]
```

### requirements.txt

パッケージを管理

```
dash==1.19.0
pandas==1.2.3
```

## サンプル

### dash/app.py

アプリ起動
app.layoutに存在しない要素にコールバックを許容する為
`suppress_callback_exceptions = True` と設定

```Python
import dash

app = dash.Dash(__name__, suppress_callback_exceptions = True)
server = app.server
```

### dash/apps/app1.py

layout記述に関してはドキュメント参照
app.pyのアプリを使いコールバックの設定
app2.pyも同じように作成

```Python
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

from app import app

layout = html.Div(
    [
        html.H3("App 1"),
        dcc.Dropdown(
            id="app-1-dropdown",
            options=[
                {"label": "App 1 - {}".format(i), "value": i}
                for i in ["NYC", "MTL", "LA"]
            ],
        ),
        html.Div(id="app-1-display-value"),
        dcc.Link("Go to App 2", href="/apps/app2"),
    ]
)


@app.callback(
    Output("app-1-display-value", "children"), Input("app-1-dropdown", "value")
)
def display_value(value):
    return 'You have selected "{}"'.format(value)
```

### dash/index.py

ルーティング実装部分

`dcc.Location`から`display_page`のInputにパスが渡り
app1.py、app2.pyで用意したレイアウトをDiv`page-content`に表示している。


```Python
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

from app import app
from apps import app1, app2

app.layout = html.Div(
    [dcc.Location(id="url", refresh=False), html.Div(id="page-content")]
)


@app.callback(Output("page-content", "children"), Input("url", "pathname"))
def display_page(pathname):
    if pathname == "/":
        return app1.layout
    elif pathname == "/apps/app1":
        return app1.layout
    elif pathname == "/apps/app2":
        return app2.layout
    else:
        return "404"


if __name__ == "__main__":
    app.run_server(host="0.0.0.0", port=8080, debug=True)
```

## ブラウザで確認

### Dockerビルド、ラン

```
docker build -t dash .
docker run --name dash -p 8080:8080 -v ~/Sites/dash/:/app -it --rm dash
```

正常にURL変更でレイアウト変更ができている。
![AnyConv.com__dash01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/febfaef5-c587-243b-1712-da07f735121f.gif)

---

次は実際にグラフ実装を投稿していきます。
いいね！と思ったら LGTM お願いします :clap::clap::clap:

【PR】プログラミング新聞リリースしました！ → https://pronichi.com
【PR】週末ハッカソンというイベントやってます！ → https://weekend-hackathon.toyscreation.jp/about/