Streamlitで作ったダッシュボードを自動でスライドショーさせる
今回作ったもの
Streamlitで作ったダッシュボードを自動でスライドショーできるか試してみました。
↓が完成したものです。
※スライドバーやチェックボックスを操作するたびに再描画され、乱数で作っているグラフが変化しているのはご愛嬌です。
一応イメージしていたものはできました。
作成した背景
複数のダッシュボードを自動でスライドショーで回しながら常設ディスプレイで表示しておきたいことがあり、今まではStreamlitではできなかったのでGrafanaを使ってやっていたのですが、Grafanaはそれなりの知識や設定が必要ですし、DBからGrafana表示用にPythonで加工してDBに戻して・・・みたいな面倒なことをやっていたので、なかなか辛くなってきていました。
Streamlitが1.30.0
に更新されてst.switch_page
が追加され、マルチページアプリのページ遷移がプログラム上から可能になったので、やりたいことができるか試してみました。
実装手順
Streamlit開発環境の準備
まずこの前作ったテンプレートを使って、Streamlitのプロジェクトを作ります。
GithubにてUse this template
を押してリポジトリを作って、
ローカルにクローンして必要な個所のtemplate
をslide-show
に置き換えたら開発の準備は完了です。
(面倒なのでコメント含めて一括置き換えしてます)
< "name": "template-container", // "template"を任意の名前にする
< "service": "template-dev", // "template"をcompose-dev.ymlと同じにする
---
> "name": "slide-show-container", // "slide-show"を任意の名前にする
> "service": "slide-show-dev", // "slide-show"をcompose-dev.ymlと同じにする
< template-dev: # "template"を任意の名称に変更
< container_name: template-dev # "template"を任意の名称に変更
---
> slide-show-dev: # "slide-show"を任意の名称に変更
> container_name: slide-show-dev # "slide-show"を任意の名称に変更
< template: # "template"を任意の名前に変更
< container_name: template # "template"を任意の名前に変更
---
> slide-show: # "slide-show"を任意の名前に変更
> container_name: slide-show # "slide-show"を任意の名前に変更
準備が整ったら、VSCodeでdevcontainerを起動します。
ダッシュボードの作成
適当なデータでグラフのあるページを3つほど作ります。
こだわっても仕方ないので、Streamlitのドキュメントにあるサンプルコードをコピペします。
import streamlit as st
import pandas as pd
import numpy as np
st.title("ダッシュボード1")
chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
st.area_chart(chart_data)
import streamlit as st
import pandas as pd
import numpy as np
st.title("ダッシュボード2")
chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
st.bar_chart(chart_data)
import streamlit as st
import pandas as pd
import numpy as np
st.title("ダッシュボード3")
chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
st.line_chart(chart_data)
ページ遷移の実装
st.switch_page
を使って、ページ遷移を実装します。
ドキュメントをみたところ、単純にst.switch_page
に遷移先のページを渡せばいいようです。
各ページに3秒で次のページに遷移するように実装します。
+ import time
+
+ time.sleep(3)
+ st.switch_page("pages/page2.py")
+ import time
+
+ time.sleep(3)
+ st.switch_page("pages/page3.py")
+ import time
+
+ time.sleep(3)
+ st.switch_page("pages/page1.py")
↓すんなりと動きました🎉
やりたいことが実現できることが分かったので、もう少し使いやすい形にしてみます。
最終的な実装
slide_show.py
を作成して、そこにページ遷移の処理をまとめました。
スライドバーでスライドの表示時間を変更できるようにし、チェックボックスでスライドショーの開始/停止を切り替えられるようにしました。
おまけとして、スライドショー中は進捗バーを表示してますが、これは冗長なので必要なければ削除してください。
前のページの設定を引き継ぐために、st.session_state
を使っていますが、
スライドバーとチェックボックスの初期値の渡し方によってはうまく動作しないパターンがあり、若干複雑になってしまいました。
import streamlit as st
import time
import datetime
def slide_show(page):
# 前のページで設定したスライドショーの設定が無ければ、初期値を設定
if "slide_enable_previous" not in st.session_state:
st.session_state.slide_enable_previous = False
if "slide_time_previous" not in st.session_state:
st.session_state.slide_time_previous = 20
# スライダーをサイドバーに表示し、スライドの表示時間を変更できるようにする
st.sidebar.slider(
label="スライドの表示時間(秒)",
min_value=5,
max_value=60,
value=st.session_state.slide_time_previous,
step=5,
key="slide_time",
)
# チェックボックスをサイドバーに表示し、スライドショーの開始/停止を切り替えられるようにする
st.sidebar.checkbox(
label="スライドショーを開始する",
value=st.session_state.slide_enable_previous,
key="slide_enable",
)
# スライドショーが有効な場合は指定された時間だけページを表示し、進捗バーを更新
if st.session_state.slide_enable:
endtime = datetime.datetime.now() + datetime.timedelta(
seconds=int(st.session_state.slide_time)
)
progress_bar = st.progress(
0, f"スライドショー中... 0 / {st.session_state.slide_time} 秒"
)
while datetime.datetime.now() < endtime:
time.sleep(1)
progress_time = int(
st.session_state.slide_time
- (endtime - datetime.datetime.now()).total_seconds()
)
progress_value = progress_time / st.session_state.slide_time
progress_bar.progress(
progress_value,
text=f"スライドショー中... {progress_time} / {st.session_state.slide_time} 秒",
)
# 設定時間が経過したら、指定されたページに切り替える
# 次ページでスライドショーを継続するために、スライドショーの設定を保存
st.session_state.slide_enable_previous = True
st.session_state.slide_time_previous = st.session_state.slide_time
st.switch_page(page)
else:
# スライドショーを止めて別ページに移動した場合に、スライドショーが勝手に再開しないようにする
st.session_state.slide_enable_previous = False
各ページは、slide_show
をインポートして、slide_show
に遷移先のページを渡すだけになりました。
気を付けるのは、slide_show
の呼び出しはページの末尾に置くことです。
- import time
-
- time.sleep(3)
- st.switch_page("pages/page2.py")
---
+ from slide_show import slide_show
+
+ slide_show("pages/page2.py")
- import time
-
- time.sleep(3)
- st.switch_page("pages/page3.py")
---
+ from slide_show import slide_show
+
+ slide_show("pages/page3.py")
- import time
-
- time.sleep(3)
- st.switch_page("pages/page1.py")
---
+ from slide_show import slide_show
+
+ slide_show("pages/page1.py")
完成
まとめ
今回確認した通り、Streamlitのダッシュボードを自動でスライドショーできるようになりました。
GrafanaはGrafanaでいいところが有るので完全置き換えができるかはわかりませんが、
選択肢が増えたのは嬉しいですね。
Discussion