When choosing from the multiselectbox below, I find that I have to click the options twice in order for it to register in the streamlit application.
By default the select shows the years 2017-2019.
If I then click â2016â it shows 2016-2019, correctly.
If I then click â2015â it show 2016-2019 once again.
If I then click â2015â once again, it shows 2015-2019, which is correct.
I want the multiselect to default to the latest y1-input always, since the application has multiple pages, which the user navigates in between.
This is some bugginess around the SessionState implementation, and how it interacts with Streamlitâs rerun logic. As a workaround, you can do something like this:
import streamlit as st
from streamlit.ScriptRequestQueue import RerunData
from streamlit.ScriptRunner import RerunException
last_y1 = session_state.y1
session_state.y1 = st.multiselect(
"Select year(s)",
['2013', '2014', '2015', '2016', '2017', '2018', '2019'],
session_state.y1)
if last_y1 != session_state.y1:
raise RerunException(RerunData(widget_state=None))
That RerunException will force Streamlit to re-execute your script whenever the session_state is updated.
(This is a temporary solution; we intend to âofficiallyâ implement SessionState in an upcoming release.)
Thank you Tim, that worked out exactly as intended!
I will look forward to the âofficialâ implementation of SessionState in the future, but this will do for now
I seem to have the same problem with a text area. The solution proposed here does not work for me, I guess as I am doing other things with âsessionâ variables here as well.
My current solution is that I present users the message that their next edit will be ignored, which works for a while but is not a really viable route for the future.
Just FYI to make clear that it does not only affect Multiselect widgets.
This still seems to be a problem. I have a st.number_input in my script, and it only works correctly on every second press of the step buttons. Every other time it will just reset to the previously displayed value.
I am using my own implementation of something like SessionState, however mine saves the state to the host machine as a .yaml file, because I donât intend on using the server via the network. Maybe I made the same mistakes as the SessionState creators, or it is a bug in streamlit itself?
Is there a way to adapt @tim 's workaround with the RerunException in such a way that it only reruns the widgets after the thing that was changed? For me it seems to rerun the entire script every time, even if I only change something at the bottom of the page.
I am using the official SessionState but I still encounter this issue for both selectboxes and text_input (version 0.84.1).
The flow is that I load a data set and the first row. The sidebar widgets get populated with the features from the row and the main area shows the observed label and the prediction. The user can change the features and see how it affects the prediction. But if the user tries to change the same feature multiple times then the 2nd, 4th, 6th [âŚ] time doesnât change the feature . Only in a row though. Change feature1, then feature2, then feature1 is fine.
When I load a row I put the features into dictionary in st.session_state['data'] (if it doesnât already exist). Then I point the widgets at the dictionary:
for cat in categorical:
cat_values = sorted(df[cat].unique())
st.session_state['data'][cat] = st.sidebar.selectbox(cat,
options=cat_values,
index=cat_values.index(st.session_state['data'][cat]))
for txt in text:
st.session_state['data'][txt] = st.sidebar.text_input(txt,
value=st.session_state['data'][txt])
That way changing a value doesnât revert the value in another field. I have buttons for Next, Previous, Random and clicking any of them deletes st.session_state['data'] and it gets recreated with the features from the new row. I see that I could use keys on the widgets but this is code-wise really clean. And I donât see why it should prevent me from changing the same widget twice in a row (maybe something with hashing?).
Thank you. I see what you mean about using keys for widgets but I donât know how I would repopulate all the widgets with the new data when I load a new lineâŚ
EDIT: Oh wait, I think I see it. I can write directly into the state for that key without damaging anything, right? So if I have a function that goes st.session_state['feature'] = new_value then I should be good. I think. Hope.
EDIT2: I anyone has an example app I would be grateful. This doesnât feel like Iâm writing the code as intended.
import streamlit as st
if 'sel_key' in st.session_state : # do not run this the first time
st.write(f'the selected item is: {st.session_state["sel_key"]}')
st.selectbox('test me',(1,2,3),index=1,key='sel_key') # no explicit session_state here!
Quick update: I gave up on this. Using widget keys I couldnât figure out how to get the widgets populated correctly when I loaded a new line (I would get the first index in a selectbox and Iâm pretty sure that the text_input widgets would just never change).
I decided that writing a caveat and moving on was a better use of my time. Itâs more important to see the predictions, observed labels, and features than changing the feature values a bunch of times.
Thank you for your time and input ksxx and sorry I couldnât get it to work (and sorry I donât have time to write a minimal reproducible example that I could share).
Iâve faced the same issue in several multiselect inputs: I have to change available lists for the next one based on previous select and moreover keep all selections after rerun. I was trying to keep everything in st.sessions_state[âmy_own_dictâ][âsome_filter_keyâ] but it worked not each time. Keeping all in form with submit button also did nothing to problem. But after Iâve just generated keys for each form and asked for value in session_state to load as default value. Everything seems to be ok, even within submit form.
Nevertheless session_state with not key values still has problems.
I have a similar problem, namely I have an app which consists of several pages and I want to save the defaults for the multiselect widget in session state so that it is always up to date.
I have to click the options in the multiselect widget 2 times so that it is transferred to the session state.
I have already tried it via callback functions, but I must also pass the current value of the widget, which is not possible as far as I know.
for columns in st.session_state['cardinal']:
for column in columns:
st.session_state.default[column]
st.session_state.default[column] = st.multiselect(f'{column}', options_cardinal, default=st.session_state.default[column])
Is there any way to use session state in the default options in widgets and keeping it up to date?
Thanks in advance!