プレスリリースやお知らせ、開発ブログ、会社の活動状況、Mattermost・aws・AI等の技術情報などを発信しています。

【入門】Streamlitでダッシュボードを作ってみよう

ディーメイクAdvent Calendar 2023 12/19の記事です。

こんにちは、CTOのsakasaiです。

最近とある事情でUS配列のキーボードを使ってるんですが、なかなか慣れずにtypoが捗ってます。

今回はずっといじろうと思っていじれてなかったStreamlitをやっといじってみたので、超入門的に簡単なダッシュボードを作ってみました。

Streamlitとは

https://streamlit.io/

もう出てからはだいぶ経ちますが、機械学習・ディープラーニングなどをJupyter Notebook上で実行するのが当たり前になってきた頃に、ほぼそのままの記述でブラウザで見れるダッシュボードが作れるみたいな感じで出てきたように記憶してます。

データサイエンス周りの人達とかによく使われているイメージです。(自分の勝手な印象なので間違っている可能性はあります)

ChatGPTに聞いてみたところ

Streamlitは、データ分析や機械学習のプロトタイピング、データ可視化などのアプリケーションを簡単に作成するためのPythonライブラリおよびフレームワークです。Streamlitを使用すると、Pythonのコードを書くだけでウェブアプリケーションを迅速に構築できます。

Streamlitの主な特徴と用途には以下のようなものがあります:

  1. シンプルな構文: StreamlitはPythonスクリプトに追加するだけでウェブアプリケーションを作成できます。HTMLやCSSの知識は不要で、Pythonの知識だけでアプリを構築できます。
  2. リアルタイムプレビュー: コードを変更すると、自動的にアプリが更新され、リアルタイムで変更を確認できます。これにより、素早いプロトタイピングが可能になります。
  3. データ可視化: データを簡単に可視化できるコンポーネントを提供しており、グラフやチャートを作成し、データを直感的に理解できます。
  4. 対話的なコンポーネント: テキストボックス、スライダー、チェックボックスなどの対話的なコンポーネントを簡単に組み込むことができます。ユーザーとの対話型アプリケーションを構築するのに役立ちます。
  5. データの表示と操作: データテーブルの表示、フィルタリング、ソートなどのデータ操作も簡単に実現できます。
  6. カスタマイズ: Streamlitの外観や動作をカスタマイズできます。カスタムCSSの適用やテーマの設定も可能です。
  7. デプロイメント: Streamlitアプリケーションは、ローカルサーバーまたはクラウドホスティングプラットフォームにデプロイできます。これにより、他のユーザーと共有できるウェブアプリケーションとして公開できます。

Streamlitはデータサイエンティスト、機械学習エンジニア、データエンジニアなどのデータ関連のプロジェクトで幅広く使用されており、迅速なプロトタイピングとデータの可視化に役立ちます。

https://chat.openai.com/

だいたい認識はあってそうです。

完成形

今回作ったダッシュボードは以下になります。

内容は以下を行っています。

  • 気象庁のデータを取得して天気予報の表示
  • 気象庁のサイトでダウンロードできるcsvを使って、
    • csvのアップロード
    • csvのデータをもとにグラフの作成とデータの表示

ダッシュボード作成

まずはローカル環境の構築です。

今回はDocker上で動作する環境を作りました。

任意の空のディレクトリでdocker initします。


$ docker init

Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  - .dockerignore
  - Dockerfile
  - compose.yaml
  - README.Docker.md

Let's get started!

? What application platform does your project use?  [Use arrows to move, type to filter]
  Go - suitable for a Go server application
> Python - suitable for a Python server application
  Node - suitable for a Node server application
  Rust - suitable for a Rust server application
  ASP.NET Core - suitable for an ASP.NET Core application
  PHP with Apache - suitable for a PHP web application
  Other - general purpose starting point for containerizing your application
  Don't see something you need? Let us know!
  Quit

言語にPythonを選択し、


? What application platform does your project use? Python
? What version of Python do you want to use? 3.12
? What port do you want your app to listen on? 8501
? What is the command to run your app (e.g., gunicorn 'myapp.example:app' --bind=0.0.0.0:8501)? streamlit run app.py

今回はバージョンに3.12、ポートをStreamlit標準の8501、起動コマンドにstreamlit run app.pyをセットしました。

完了するとファイルが作成されます。


$ ls
Dockerfile		README.Docker.md	compose.yaml

エディターでcompose.yamlを開きvolumesだけ追加しておきます。(下記の最後の2行)

services:
  server:
    build:
      context: .
    ports:
      - 8501:8501
    volumes:
      - .:/app

次に必要なライブラリを記述したrequirements.txtを追加します。中身は以下です。


streamlit
pandas
requests
matplotlib
seaborn
japanize-matplotlib

データサイエンス周りでよく使うライブラリですね。

現在のファイル


$ ls
Dockerfile		README.Docker.md	compose.yaml		requirements.txt

そうしたらアプリケーションを実装していきます。

app.pyを追加


$ ls
Dockerfile		README.Docker.md	app.py			compose.yaml		requirements.txt

一旦以下を記述


import streamlit as st

st.title('ダッシュボード')

この状態でdocker compose upを実行し起動してみます。

起動を確認して、ブラウザでhttp://localhost:8501にアクセスします。

表示されました。

※このあとの実装は細かい箇所は省略します。最後に今回のソースコードをpushしたGitHubリポジトリのリンクを貼っておきます。

次にページの設定サイドバーを追加します。


### Page Configuration ###
title = "気象データダッシュボード"
st.set_page_config(
    page_title=title,
    page_icon="🌈",
    layout="wide",
)
st.title(title)

### Page Content ###
## sidebar
st.sidebar.markdown('''
# MENU
- [weather](#weather)
- [csv upload](#csv-upload)
- [graph](#graph)
- [data sheet](#data-sheet)
''', unsafe_allow_html=True)

## main
st.header("weather news")
st.markdown("---")
st.header("csv upload")
st.markdown("---")
st.header("graph")
st.markdown("---")
st.header("data sheet")

保存してリロードすると以下になります。

次に天気予報の箇所を実装します。(いろいろゴニョゴニョしてるのでかいつまんで)


st.header("weather news")
with st.container(border=True):
    st.dataframe(df_weather(), use_container_width=True, column_config={
        "天気予報icon": st.column_config.ImageColumn()
    })

枠線をつけて見やすくするようにレイアウトを設定しました。

天気予報のデータフレームを取得(df_weather())して、Streamlitのdataframeにセットするだけで表を作れます。(iconを画像にしたかったのでconfigでセットしています)

リロードすると以下が表示されます。

次にcsvアップロードフォームを追加します。


st.header("csv upload")
with st.container(border=True):
    uploaded_file = st.file_uploader("CSVファイルをアップロードしてください", type="csv")

リロードすると以下が表示されます。

次にcsvを読み込んでグラフを表示します。

グラフの書き方はいろいろあると思いますが、今回はレイアウトを弄りたかったのもあり1つずつグラフ化する形で実装しました。


st.header("graph")

if uploaded_file is not None:
    # CSVファイルの読み込み
    df = pd.read_csv(uploaded_file, index_col="年月日時", parse_dates=True)
    df.index = df.index.strftime("%H:%M")

    with st.container(border=True):
        # 2カラムを用意
        l_col, r_col = st.columns(2)

        # 気温(℃)(左カラム)
        df_temp = df.copy().iloc[:, :1]
        lineplot(l_col, df_temp, "気温(℃)", "年月日時", "気温(℃)")

        # 相対湿度(%)(右カラム)
        df_hum = df.copy().iloc[:, 1:2]
        lineplot(r_col, df_hum, "相対湿度(%)", "年月日時", "相対湿度(%)", 100)

    with st.container(border=True):
        # 2カラムを用意
        l_col, r_col = st.columns(2)

        # 降水量(mm)(左カラム)
        df_preci = df.copy().iloc[:, 2:3]
        lineplot(l_col, df_preci, "降水量(mm)", "年月日時", "降水量(mm)")

        # 日射量(MJ/㎡)(右カラム)
        df_sol = df.copy().iloc[:, 3:4]
        lineplot(r_col, df_sol, "日射量(MJ/㎡)", "年月日時", "日射量(MJ/㎡)")

気温と湿度を左右に並べ、降水量と日射量をその下に左右に並べています。

グラフの描画は共通関数(lineplot)で行っています。

グラフ体裁を整えるのにseabornを使うのでその設定も記述します。


sns.set_style(style="darkgrid")
sns.set_context("paper")
sns.set_color_codes("pastel")
sns.set(font='IPAexGothic')

def lineplot(_st, _df, _title: str, xlabel: str, ylabel: str, ylim: int = None):
    """線グラフを描画"""
    _st.markdown(f"### {_title}")
    plot = sns.lineplot(_df, x=xlabel, y=ylabel, markers=True)
    plot.set_xticks([x for x in _df.index[::3]])
    plot.set_xticklabels([x for x in _df.index[::3]], rotation=90)
    plot.set_ylim(-0.01, ylim)
    _st.pyplot(plot.figure, clear_figure=True)

リロードしてcsvをアップロードするとグラフが表示されます。

最後にcsvのデータを表示します。


st.header("data sheet")

if uploaded_file is not None:
    with st.container(border=True):
        st.write(df)

リロードしてcsvをアップロードすると表が表示されます。

今回は2023-12-18の東京の1日のデータを使用しました。

最終的に最初の完成形に貼った画面になります。

ちなみに、今回はその都度csvをアップロードするなどロジックがあまり汎用的になっていませんが、データ量を変えると(例えば半日分)、ちゃんとその内容でグラフが表示されます。

まとめ

Streamlitを使ってダッシュボードを作ってみました。

データサイエンスなどでNotebookでグラフ化などをおこなったロジックをそのままダッシュボード化できるのはとても便利だと思いました。

ちゃんとWebフレームワークとして他にもフォーム用のライブラリなどもいろいろ用意されているので、使い込むととても便利に使えそうです。

今回のソースコードは以下で公開しています。

https://github.com/msakasai/streamlit-test

  • B!

おすすめ記事リンク