質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Streamlit

Streamlitは、Pythonでフロントエンドアプリケーションを構築できるフレームワーク。HTML/CSSの知識が不要で、描画ライブラリで作成したグラフを埋め込むことが可能です。機械学習のレポート作成やデータ分析にも応用できます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

6422閲覧

streamlitで、ボタンを押したときにデータを更新したいが、session_stateの中身の通り更新されないときがある。

H.K2

総合スコア88

Streamlit

Streamlitは、Pythonでフロントエンドアプリケーションを構築できるフレームワーク。HTML/CSSの知識が不要で、描画ライブラリで作成したグラフを埋め込むことが可能です。機械学習のレポート作成やデータ分析にも応用できます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/07/07 04:36

前提

multiselectで選択した内容を、ボタンを押すことで、ファイルから読み込んだデータで
更新する、という機能をstreamlitで実現したいと考えています。

実現したいこと

上記を実現するため、下記イメージのように、streamlitでmulti_selectの入力結果を「除外ID対象を更新」ボタンを押すことで固定値で更新するという機能を作ってみました。
(簡単化のため、シンプルにしました。実際はもう少し複雑ですが)
ボタンを押下した時の情報を保存するには、st.session_stateを使うとよいとのことでしたので、session_stateにて実現しています。

イメージ説明

発生している問題・エラーメッセージ

エラーは特に発生しないのですが、下記問題が発生しています。
①multi_selectで選択肢を増やしたときはきちんと増加するのですが、multi_selectで、
「×」を押下してすでに追加された項目を除去した場合、きちんと除去されない
(反映されない)時があります。
②multi_selectでいくつか選択した状態(ボタンを押下で更新される内容と違う状態)で、ボタン押下した場合に、ボタン押下の内容が更新されない「ことがある」状態になります。
上記2点を解決したいのですが、原因がわからず、原因及び解決方法について
ご教示いただけましたら幸甚です。(「前提」に書かれた内容を実現したい、というのが
もともとですので、下記に示すソースコードでは実現方法として適切でない、より良い方法があるということであれば、合わせてご提示いただけましたら非常にありがたいです)

該当のソースコード

Python3

1import streamlit as st 2from pathlib import Path 3import sys 4import numpy as np 5import pandas as pd 6 7 8def main(): 9 st.title("multi_select更新テスト") 10 if "omit_list" not in st.session_state: 11 st.session_state["omit_list"] = [] 12 13 reflesh = st.button("除外ID対象を更新") 14 omit_default_list = st.session_state["omit_list"] 15 if reflesh: 16 # 本当はファイルから読み込んだデータセットで更新 17 omit_default_list = [1,2,3] 18 else: 19 # omit_default_list = st.session_state["omit_list"] 20 pass 21 22 omit_list = st.multiselect( 23 "除外するIDを選択ください", 24 [1,2,3,4], 25 default=omit_default_list, 26 key="omit_multi", 27 ) 28 st.session_state["omit_list"] = omit_list 29 30 st.text(omit_list) 31 32 33if __name__ == "__main__": 34 main()

試したこと

ネットで調べて、streamlitでの、「前提」の実現方法を検討した。
streamlit公式で、st.multi_selectの内容を確認した。

補足情報(FW/ツールのバージョンなど)

python 3.9.6
streamlit 1.1.0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

defaultを変更することで実現しようとしているのが、あまりよくないように思います。
推測なのですが、defaultが変更されたときに、今選択されているものを残すか、それを破棄してdefaultで上書きするかというところを、streamlitが中でどう判断して処理しているのかに依っているように思います。

ウィジェットでkeyを設定すると、ウィジェットの状態が session_state のそのkeyと紐づけされるので、それを使うのがいいと思います。

https://docs.streamlit.io/library/api-reference/session-state

python

1import streamlit as st 2 3def main(): 4 st.title("multi_select更新テスト") 5 6 reflesh = st.button("除外ID対象を更新") 7 if reflesh: 8 # 本当はファイルから読み込んだデータセットで更新 9 st.session_state["omit_multi"] = [1,2,3] 10 11 omit_list = st.multiselect( 12 "除外するIDを選択ください", 13 [1,2,3,4], 14 key="omit_multi", 15 ) 16 17 st.text(omit_list) 18 19if __name__ == "__main__": 20 main()

上のプログラムでは、ボタンが押されたときに、multiselect の session_state に値を代入することで、リセットするようにしています。

ただし、下記リンク先にあるように、ウィジェットが表示された後に値を変更することはできません。
https://docs.streamlit.io/library/api-reference/session-state#caveats-and-limitations
今回はボタンが上にあるので、ボタン操作でsession_stateの値を変更したあと、multiselectを表示しているため、問題ありませんが、ボタンを下に表示したい場合は on_click でイベント実行するようなことが必要です。
(参考 https://discuss.streamlit.io/t/22987)

投稿2022/07/07 08:36

bsdfan

総合スコア4560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H.K2

2022/07/07 22:42 編集

早速のご回答ありがとうございます! なるほど、keyのオプションは、実際に作成したsession_stateと同一にしないといけない(keyに、明示的に割り当ててないものをいれても、session_stateを割り当てて紐づけてくれるわけではない)ということですね。 ちょっと実際の問題に適用して治るかどうかみてみます! ちなみに、on_clickのイベント実行というのは、コールバックになるのでしょうか。サイドバーにボタンを用意した状態で実施するなど、複雑な画面になってきたときに、処理順が必ずしもウィジェットの描画のほうが先になるかもしれない(順番が保証できない)ような場合は、とりあえずon_click()処理の中にウィジェットのsession_stateに割り当てたものに対しての更新処理を記載するほうが良い、と理解しました。
bsdfan

2022/07/08 00:01

> keyのオプションは、実際に作成したsession_stateと同一にしないといけない 「しないといけない」ということはないです。ウィジェットと紐づかないsession_stateの使い方も普通にあります。 > ちなみに、on_clickのイベント実行というのは、コールバックになるのでしょうか。 コールバックです。コールバックを実行したあと、全体を最初から実行する、という流れになるようです。 streamlitは複雑な構成でも、基本的には上から順番に実行していっていると思うのですが、コールバックにすれば悩まなくていいかもしれませんね。
H.K2

2022/07/08 01:47

ありがとうございます。 >ウィジェットと紐づかないsession_stateの使い方 これはkeyに、st.session_state[hogehoge]=aaa のように、明示的に代入しておかなくても、keyに適当な文字列を入れておけば問題ない、ということではないですよね? 確かに適用対象でも動作しました。ただ、1点気になる動きをしているのですが、st.sidebar.button()で、 on_clickオプションに、更新処理(さきほどでいう、「st.session_state["omit_multi"] = [1,2,3]」に相当) を入れたところ、ボタンを押さなくても、アプリ起動時に必ず一回呼ばれるような挙動になっています。 これって抑制できるのでしょうか。(on_clickはあったほうがいいと思うのですが、押してなくても呼ばれるのは 気持ち悪い気がして…何度もすみません。)
H.K2

2022/07/08 03:24

とりあえず本件については、一旦解決なので閉じておきます、ありがとうございました! 別件っぽい感じもするので、一旦別項目で整理して別途質問投稿させていただくかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問