やりたいこと
Streamlitで要素を削除したい。
画面に表示した要素を消すなんて簡単に出来そうですが、
Streamlitの処理の流れを理解していないとハマるので少しだけ説明におつきあいください。
Strealitの処理の流れを理解する
画面上での動きを確認する
次のコードを実行してみます。
import streamlit as st
st.title('Hello, World!')
if st.button('Say hello'):
st.write('Hello, Streamlit!')
Say hello ボタンを押すと、Hello, Streamlit! が表示されます。
コード自体はとてもシンプルで直感的です。
ログを入れて動きを確認する
と言いつつ、通常のPythonのコードとかに慣れていると
「これは st.button()
でキー入力待ちが発生しているのかな?」
みたいな疑問が出てくるのでちょっとログを入れて動きを見てみます。
いろいろなところに print 入れてみました。
import streamlit as st
import logging
st.title('Hello, World!')
print("Hello, World!") # ★LOGGING
if st.button('Say hello'):
st.write('Hello, Streamlit!')
print("Button - pressed!") # ★LOGGING
else:
print("Button - Not pressed!") # ★LOGGING
これを実行してボタンを押してみると、、、
Hello, World!
Button - Not pressed!
Hello, World!
Button - pressed!
こんなログが出ます。
およ? Hello, World! がなんで2回出たの??
ということでここが要注意ポイントです。
なぜそうなったかを考えてみる
まず初回は Hello, World! と Say hello ボタン を描画しておしまいになります。
ボタンは描画しただけで押されていないので else のルートに行きます。
そして、ブラウザ上でボタンが押されると、このコードが再び動き出します!
今度は Hello, World! と Say hello ボタン を描画してさらにボタンが押された状態なので True のルートに入るので Hello, Streamlit! が描画されます。
この、同じコードが何回も実行されている ≒ 毎回すべての要素を書き直している、という動きを理解することが大事です。
同じ要素を何度も描画しているといっても、StreamlitはReactベースで作られている(らしく)DOMの変化があったところだけ描画されるので画面がチカチカすることはありません!かしこい!
つまり「要素を削除する」方法は?
要素は削除できません!
削除ではなく、描いたり描かなかったりします。
毎回毎回すべての要素を描画しなおすということで、
要素を追加して、削除する ではなく、
要素を追加したり、しなかったりする という方法をとる必要があります!
サンプルコード
こんな感じになります。
- 描画するしない用のフラグを用意する
- フラグは普通の変数だと消えてしまうので
st.session_state
というものを使う - フラグを見て
st.write()
を呼び分ける
という点だけ注意してくれれば普通のコードです。
import streamlit as st
import logging
if 'show_flag' not in st.session_state:
st.session_state.show_flag = True
st.title('Hello, World!')
if st.button('Say hello'):
if st.session_state.show_flag:
st.session_state.show_flag = False
st.write('Hello, Streamlit!')
else:
st.session_state.show_flag = True