ディーメイクAdvent Calendar 2023 12/19の記事です。
こんにちは、CTOのsakasaiです。
最近とある事情でUS配列のキーボードを使ってるんですが、なかなか慣れずにtypoが捗ってます。
今回はずっといじろうと思っていじれてなかったStreamlitをやっといじってみたので、超入門的に簡単なダッシュボードを作ってみました。
Streamlitとは
もう出てからはだいぶ経ちますが、機械学習・ディープラーニングなどをJupyter Notebook上で実行するのが当たり前になってきた頃に、ほぼそのままの記述でブラウザで見れるダッシュボードが作れるみたいな感じで出てきたように記憶してます。
データサイエンス周りの人達とかによく使われているイメージです。(自分の勝手な印象なので間違っている可能性はあります)
ChatGPTに聞いてみたところ
Streamlitは、データ分析や機械学習のプロトタイピング、データ可視化などのアプリケーションを簡単に作成するためのPythonライブラリおよびフレームワークです。Streamlitを使用すると、Pythonのコードを書くだけでウェブアプリケーションを迅速に構築できます。
Streamlitの主な特徴と用途には以下のようなものがあります:
- シンプルな構文: StreamlitはPythonスクリプトに追加するだけでウェブアプリケーションを作成できます。HTMLやCSSの知識は不要で、Pythonの知識だけでアプリを構築できます。
- リアルタイムプレビュー: コードを変更すると、自動的にアプリが更新され、リアルタイムで変更を確認できます。これにより、素早いプロトタイピングが可能になります。
- データ可視化: データを簡単に可視化できるコンポーネントを提供しており、グラフやチャートを作成し、データを直感的に理解できます。
- 対話的なコンポーネント: テキストボックス、スライダー、チェックボックスなどの対話的なコンポーネントを簡単に組み込むことができます。ユーザーとの対話型アプリケーションを構築するのに役立ちます。
- データの表示と操作: データテーブルの表示、フィルタリング、ソートなどのデータ操作も簡単に実現できます。
- カスタマイズ: Streamlitの外観や動作をカスタマイズできます。カスタムCSSの適用やテーマの設定も可能です。
- デプロイメント: 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フレームワークとして他にもフォーム用のライブラリなどもいろいろ用意されているので、使い込むととても便利に使えそうです。
今回のソースコードは以下で公開しています。