PythonだけでもインタラクティブなWebアプリは作れる【ストレングスファインダーのダッシュボード作成】

[BrainPad Advent Calendar 2020](https://qiita.com/advent-calendar/2020/brainpad) 23日目の記事です。

本記事では、**インタラクティブな可視化アプリ**を、**Python だけで**作った話をします。
今回作ったアプリは、**ストレングスファインダーのダッシュボード**です。

私は BrainPad に新卒で入社して以降、データサイエンティストとして仕事をしています。業務で使う言語は専ら Python です。今まで Web アプリを作った経験はありません。

今回作りたいダッシュボードは、インタラクティブな操作が必要不可欠です。
そういった Web アプリを作ろうとすると、JavaScript からは逃れられないよな・・・と思っていましたが、今回は Python のみで完結させることができました。
なる早で作りたかったこともあり、学習コストがほとんどかからなかったのはとてもよかったです。

# アプリについて
まず、作ったアプリの内容について簡単に紹介します。
※以降、アプリの内容についての記載なので、技術面が気になる方は読み飛ばしてください。

## 何ができるアプリ？
**複数人のストレングスファインダーの受診結果を可視化できるアプリです。**

[ストレングスファインダー](https://www.gallup.com/cliftonstrengths/ja/253634/%E3%83%9B%E3%83%BC%E3%83%A0.aspx)とは、米国ギャラップ社が開発したオンラインの「才能診断」ツールです。Webサイト上で177個の質問に答えることで、34個の「資質」の順位が得られるものになります。自己理解やチームビルディングなどに活用できます。
ストレングスファインダーについては色々と書きたいことはあるのですが、ここでは詳細は割愛します。

例えば、私の上位 TOP5 の資質は以下でした。

|順位| 資質 |概要|
|----|----|----|
|1   |戦略性|目的に向けて複数のアプローチを考えることが得意|
|2|責任感|一度やると言ったらやる|
|3|活発性|アイデアを実行することで結果を出す、とりあえずやってみる|
|4|着想|新しいアイデアを考えるのが好き|
|5|包含|仲間はずれがいると放っておけない|

BrainPad でも受診が推奨されており、**約半数**の社員が受診をしています。
ただし、アセスメントを受けただけでは意味がありません。

そこで、社員の相互理解やチームビルディング、コミュニケーションネタとして活用してもらいたいと思い、社内限定のダッシュボードを作るに至りました。

## 一部機能紹介

- 部署ごとの上位資質の傾向を提示
- 任意のグループ内で不足している資質の提示
- 任意のグループ内における個人の突出している資質の提示
- 距離が近い人同士のマッチング

例えば、受診済み社員の氏名を複数人入力すると、その集団の傾向を提示する画面はこんな感じです。
※氏名にモザイク処理してます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177134/106495a1-b08c-a802-5924-d7a389bb6587.gif" width=500>

ちゃんとインタラクティブに動いてます。
（アプリに対する社内の反応や具体的な活用などについてはまた別の機会に・・・）

# 用いた主要なフレームワーク、ライブラリ
- Dash：Flask, Plotly.js, React.jsをベースに作成されたPythonのWebフレームワーク
- Flask：PythonのWebフレームワーク
- plotly：可視化ライブラリ
    - 普段は可視化ライブラリとして matplotlib や seaborn などを使うことが多いですが、Plotly を使うとぐりぐり動かせるグラフを書くことができる

インタラクティブな動作を可能にしたのは **Dash** という Web フレームワークです。

# Dash とは
Dash はグラフを Web アプリ化するためのフレームワークです。グラフは Plotly で記述し、裏ではFlaskが動いています。

## これだけ分かればOK
Dash は2つのコンポーネントで構成されています。**layout** と **callback** です。
[Dash の公式チュートリアル](https://dash.plotly.com/installation)にも記載がある内容なので、詳細はそちらを参照いただきたいのですが、とりあえずこの2つが理解できればそれなりのアプリが作れると思います。

### layout
名前の通り、アプリの外観を決めるコンポーネントです。
一般的な Web アプリの場合は HTML がこの役割を担います。つまり、HTML も書かなくていいということです。

例えば、以下のようなページを作りたいとします。
※[公式チュートリアル](https://dash.plotly.com/layout)から抜粋
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177134/c281b0a9-15db-ca4c-3757-2d8db8afb22c.png" width=350>
見出し1に"Hello Dash"、その下にテキスト、更にその下にグラフが表示されています。
下記のように記述することで実装可能です。

``` python
app.layout = html.Div(children=[
    # 見出し1
    html.H1(children='Hello Dash'),

    # テキスト
    html.Div(children='''
        Dash: A web application framework for Python.
    '''),

    # グラフ
    dcc.Graph(
        id='example-graph',
        figure=fig
    )
])
```

このように、アプリの外観を定義するのが layout です。
背景色やテキストの色なども layout で設定可能です。

次に、 callback についてです。

### callback
アプリとデータ操作の連携をとるコンポーネントで、インタラクティブな操作は callback で設定します。
例えば、以下のようにユーザーからの入力をそのままテキストで出力したいとします。
※[公式チュートリアル](https://dash.plotly.com/basic-callbacks)から抜粋
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177134/abaf5adc-5964-45dd-ad50-1d3fb598eeb9.gif" width=500>
以下のように記述することで実装可能です。

```python
# layout で外観を設定
app.layout = html.Div([
    html.H6("Change the value in the text box to see callbacks in action!"),
    # 入力ボックスに対して任意のIDを設定（今回の例だと 'my-input'）
    html.Div(["Input: ",
              dcc.Input(id='my-input', value='initial value', type='text')]),
    html.Br(),
    # 出力に対して任意のIDを設定（今回の例だと 'my-output'）
    html.Div(id='my-output')
])

# callback の設定
# 上記の layout で設定した入出力のIDを指定する
@app.callback(
    Output(component_id='my-output', component_property='children'),
    Input(component_id='my-input', component_property='value')
)
# インタラクティブな操作をする関数を記述する
#（今回の例だと入力を受け取ってそのまま返す）
def update_output_div(input_value):
    return 'Output: {}'.format(input_value)
```

layout, callback ともに非常にシンプルです。

# その他便利だったライブラリ

[dash_bootstrap_components](https://dash-bootstrap-components.opensource.faculty.ai/) という、Dash 内で Bootstrap※ が使えるライブラリが便利でした。※Bootstrap：Twitter社が開発した CSS のフレームワーク。イイ感じにフロントが作れる

こんな感じのドロップダウンメニューや、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177134/eec32ceb-08e7-6fe5-ae5a-ef07bdd181bc.gif" width=350>
こんな感じのカードがサクっと作れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177134/c56ae5db-fbc0-92b4-f0c0-610daba8814c.png" width=350>
HTML や CSS も書かずに済みます。

# まとめ
日頃 Python しか書いてないけどインタラクティブな Web アプリをサクッと作りたい！という方には Dash をオススメします。今回紹介したような、ライトなダッシュボードを作るくらいなら、Dash で十分事足りるなと思いました。
とはいえ、かゆいところに手が届かなかったりもするので、エンジニアとしては実装手段の選択肢はたくさん持っているに越したことはないですね。と当たり前のことを言って本記事を締めくくりたいと思います。