StreamlitでBCPチェッカーアプリを作ってみた


こんにちは！今回は、Streamlitを使って簡単なウェブアプリを作る方法と、それを無料でデプロイする方法をご紹介します。さらに、このアプリを通じて、気候変動時代におけるBCP（事業継続計画）の重要性についても触れていきたいと思います。

アプリは次のサイトで試せます。あなたの会社の事業継続性は大丈夫？

https://chomoku-bcp-app.streamlit.app/

コードはgithubにあります。

https://github.com/hideyuki-ogawa/bcp-app

## Streamlitとは？

[Streamlit](https://streamlit.io/)は、Pythonのデータサイエンティストやエンジニアが、簡単にウェブアプリケーションを作成できるフレームワークです。数行のコードで、インタラクティブなダッシュボードやデータ可視化ツールを作成できます。また、Community Cloudには無料でアプリケーションがデプロイできます。

## BCPチェッカーアプリの概要

今回作成したアプリは、企業のBCP（事業継続計画）の準備状況をチェックするためのものです。ユーザーは20の質問に答え、その結果に基づいて企業のBCP準備レベルを評価します。20の質問は中小企業庁のウェブサイトにありました。ウェブアプリにすることで、より使いやすくなり、どうしたらよいかもわかりやすくなったと思います。

## アプリケーションの主要機能

1. 質問表示と回答入力
2. 進捗状況の表示
3. 結果の集計と表示
4. レーダーチャートによる視覚化

## コードの重要ポイント

アプリケーションの主要な部分について、わかりやすく解説します。

### セッション状態の管理

```python
if "current_num" not in st.session_state:
    st.session_state["current_num"] = 0

if "answers" not in st.session_state:
    st.session_state["answers"] = {}
```

このコードは、ユーザーの状態を保存するためのものです。ウェブアプリでは、ページをリロードすると通常はデータが消えてしまいますが、Streamlitの`session_state`を使うと、データを保持できます。

- `current_num`: 現在の質問番号を記録します。初めてアプリを開いたときは0になります。
- `answers`: ユーザーの回答を保存する辞書です。最初は空の状態です。

これらの値は、ユーザーがアプリを使用する間ずっと保持され、質問を進めたり、結果を表示したりするのに使われます。

### 動的なUI更新

```python
if st.session_state["current_num"] == 0:
    show_title()
elif st.session_state["current_num"] <= len(df):
    show_quiz()
else:
    display_results()
```

このコードは、アプリの「画面」を切り替える役割を果たします。

1. `current_num`が0の場合（つまり、アプリを開いた直後）：タイトル画面を表示します。
2. `current_num`が質問の数以下の場合：クイズ画面を表示します。
3. それ以外（つまり、全ての質問に答え終わった後）：結果画面を表示します。

この仕組みにより、ユーザーの進行状況に応じて適切な画面が表示されます。

### 質問の表示とユーザー入力の処理

```python
def show_quiz():
    c_num = st.session_state["current_num"]
    q_num = c_num - 1
    quiz = df.loc[q_num, "質問"]
    st.header("BCPチェッカー", divider="rainbow")
    st.title(f"質問: {c_num}")
    st.write(f"{quiz}")
    st.button("はい", on_click=increment_session, args=(1,))
    st.button("いいえ", on_click=increment_session, args=(0,))
    st.button("?", on_click=increment_session, args=(0,))
```

この`show_quiz`関数は、実際の質問画面を作る役割を果たします。

1. `c_num`で現在の質問番号を取得します。
2. `q_num`は実際のデータフレームの行番号です（0から始まるため、1を引いています）。
3. `quiz`変数に、データフレーム`df`から現在の質問文を取得します。
4. `st.header`と`st.title`で画面上部にタイトルと質問番号を表示します。
5. `st.write`で実際の質問文を表示します。
6. `st.button`で回答用のボタンを3つ作ります。
   - 各ボタンをクリックすると`increment_session`関数が呼ばれ、回答が記録されます。
   - `args=(1,)`や`args=(0,)`は、ボタンがクリックされたときに`increment_session`関数に渡される引数です。

この方法で、ユーザーは簡単に質問に回答でき、その回答はすぐにアプリに記録されます。

### データの可視化

```python
def show_chart(df):
    fig = px.line_polar(df, r="ans", theta="cat", line_close=True)
    fig.update_traces(fill="toself")
    fig.update_layout(
        polar={"radialaxis": {"visible": True, "range": [0, 4], "color": "black"}},
        autosize=True,
    )
    st.plotly_chart(fig, use_container_width=True)
```

この`show_chart`関数は、ユーザーの回答結果をレーダーチャートとして表示します。

1. `px.line_polar`で、極座標系のグラフ（レーダーチャート）を作成します。
   - `r="ans"`: 各カテゴリーの得点を半径として使用
   - `theta="cat"`: カテゴリー名を角度として使用
2. `update_traces(fill="toself")`で、グラフの内側を塗りつぶします。
3. `update_layout`で、グラフの見た目を調整します。
   - 軸の範囲を0から4に設定（各カテゴリーの最大得点が4のため）
   - 軸の色を黒に設定
4. `st.plotly_chart`で、作成したグラフをStreamlitアプリ上に表示します。

この関数により、ユーザーは自分のBCP対策状況を視覚的に理解することができます。

## Streamlit Community Cloudでのデプロイ

アプリケーションの作成後、[Streamlit Community Cloud](https://streamlit.io/cloud)を使用して無料でデプロイできます。手順は以下の通りです：

1. GitHubにコードをプッシュ
2. Streamlit Community Cloudにログイン
3. 「New app」をクリック
4. GitHubリポジトリを選択
5. デプロイ設定を行い、「Deploy」をクリック

数分後には、あなたのアプリがインターネット上で公開されます！

## なぜBCPが重要なのか？

気候変動の影響により、自然災害のリスクが高まっています。BCPは、災害時に企業が迅速に対応し、事業を継続するための重要なツールです。

このアプリを通じて、企業は自社のBCP準備状況を簡単に確認でき、改善点を見つけることができます。

## まとめ

Streamlitを使えば、データサイエンティストやエンジニアでなくても、簡単にウェブアプリを作成できます。さらに、Streamlit Community Cloudを利用すれば、無料でアプリをデプロイすることができます。

BCPチェッカーのような実用的なアプリケーションを作成・公開することで、社会課題の解決に貢献できるかもしれません。皆さんも、Streamlitを使って自分のアイデアをウェブアプリにしてみてはいかがでしょうか？

## 参考リンク

- [Streamlit公式サイト](https://streamlit.io/)
- [Streamlit Community Cloud](https://streamlit.io/cloud)
- [中小企業庁：BCP策定運用指針](https://www.chusho.meti.go.jp/bcp/)

以上、StreamlitでBCPチェッカーアプリを作成した体験をお伝えしました。皆さんのプロジェクトにStreamlitを活用していただければ幸いです！