7
6

More than 1 year has passed since last update.

【Streamlit】アプリのページ切り替えの流れとページ再読み込みについて

Last updated at Posted at 2021-12-05

Streamlitでアプリを作る際にページ切り替えを入れ込む際の作り方と、能動的にページを再読み込み(=アプリ再起動)させたいけどどうやるんだ!という時のための記事です。

streamlitの挙動と状態保持変数の説明

streamlitではボタンなどのウィジェットの値が変更される度に全てのコードが再実行されます。
なので、ページ遷移を行うためにはページ管理用の変数を作成し、実行の最初でその値により処理を分岐させるという方法を取るのが一般的かと思います。

イメージとしては下記のようなコードになります。

streamlit_page_change.py
import streamlit as st

def main():
    # 1ページ目表示
    st.sidebar.title("test_streamlit")
    st.markdown("## ボタンでページを変えましょう")
    st.sidebar.button("ページ切り替えボタン", on_click=change_page)

def change_page():
    # ページ切り替えボタンコールバック
    st.session_state["page_control"]=1

def next_page():
    # 2ページ目表示
    st.sidebar.title("ページが切り替わりました")
    st.markdown("## 次のページです")

# 状態保持する変数を作成して確認
if ("page_control" in st.session_state and
   st.session_state["page_control"] == 1):
    next_page()
else:
    st.session_state["page_control"] = 0
    main()

※ st.session_state[変数名]でコード再実行が行われても値を保持する変数を定義出来ます

各ウィジェットの引数にあるon_clickやon_changeなどのコールバックを設定した場合、コールバック関数を実行→アプリが再実行という順番で動作します。
上記コードはコールバック関数内で変数の値を更新することでページ遷移を行っています。

※ この時、最初のページから次のページに持ち越したい値がある場合は、同様にst.session_stateで定義しておくか、コールバック関数にargs,kwargsなどのキーワード引数として持ち越すという方法があります

ページ再読み込みのユースケース

あまり実用的ではないかもしれませんが、例えばファイルのアップロードを契機に解析用のページに移動させたい場合などに使えます。

まずは下記のコードを見てみましょう。

streamlit_file_upload.py
import streamlit as st

def main():
    # 1ページ目表示
    st.sidebar.title("test_streamlit")
    st.session_state["file"]=st.sidebar.file_uploader("upload", on_change=change_page)

def change_page():
    # ページ遷移ボタンコールバック
    st.session_state["page_control"]=1

def next_page():
    # 2ページ目表示
    st.sidebar.title("ページが切り替わりました")
    st.markdown("## 次のページです")

# 状態保持する変数を作成して確認
if ("page_control" in st.session_state and
   st.session_state["page_control"] == 1):
    next_page()
else:
    st.session_state["page_control"] = 0

ページ遷移後の関数内でst.session_state["file"]の中身を確認するとわかるのですが、値はNoneとなってしまっています。
sukusyo.gif

ページ遷移をさせずに下記のような形でファイルの中身を読むと、ちゃんと値が格納されています。

streamlit_file_upload.py
st.session_state["file"]=st.sidebar.file_uploader("upload")
if st.session_state["file"] != None:
    st.markdown("ファイルの中身")
    st.markdown(st.session_state["file"])

sukusyo.gif

関数の中身を追えていないのでどのような仕様でこうなっているのかわかりませんが、兎にも角にもページ遷移+ファイルアップロード情報を持ち越しをしたい場合は、コールバックのon_changeを使わずになんとかするしかありません。

ここで表題にもあるページ再読み込みの機能が役に立ちます。

解決法

1行加えるだけです。

streamlit_file_upload.py
import streamlit as st

def main():
    # 1ページ目表示
    st.sidebar.title("test_streamlit")
    st.session_state["file"]=st.sidebar.file_uploader("upload")
    if st.session_state["file"] != None:
        st.session_state["page_control"] = 1
        raise st.experimental_rerun()

def next_page():
    # 2ページ目表示
    st.sidebar.title("ページが切り替わりました")
    st.markdown("## 次のページです")
    st.markdown("ファイルの中身")
    st.markdown(st.session_state["file"])

# 状態保持する変数を作成して確認
if ("page_control" in st.session_state and
   st.session_state["page_control"] == 1):
    next_page()
else:
    st.session_state["page_control"] = 0
    main()

sukusyo.gif
無事に遷移後のページにアップロードファイルの情報を持ち越すことが出来ました。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6