I’m having a hard time understanding your question, but I totally get that UI behavior is really hard to describe in words
So for example, if I use a slider to choose a value that then multiplies a column in a dataframe when I press a button to submit that calculation, if I go to submit using a button somewhere else that gets reset. I would like the results of that button press to persist. In other words, I want that button value to stay True.
We’ve actually been thinking about the “submit button” scenario lately, and considering whether we should provide a new API just for this case. For example, maybe there should be a way to specify a “widget group” whose values only get set to the server when “submit” is pressed.
But to better design this API, it would be great to get a bunch of “toy examples” of what people would like to do with it. So if you can come up with a tiny script that exemplifies what you need, that would be amazing!
I’m assuming what you’re working on with SessionState fixes this issue?
Streamlit reruns your script fresh from the top every time you change the value of a widget. But sometimes you want to keep some values around in between runs (for example, when incrementing a variable, when doing incremental manipulations of a dataset, etc.).
That’s where SessionState comes in. It lets you persist data across reruns.
If I hit the button 5 times x will always be 1 if it started by 0.
Hmmm… that’s not supposed to happen with the code snippet I pasted above. Did you try running it? Or perhaps you’re reacting to the API used for the SessionState prototype? In case it’s the latter, here’s a quick explanation of how the prototype API works:
When you do this:
state = SessionState.get(x = 100)
if st.button('Increment x'):
state.x += 1
st.write("Current value of x:", state.x)
Here’s what happens behind the scenes:
- When a user opens a new browser tab with your Streamlit app, Streamlit runs the script above from top to bottom. When it reaches the
SessionState.get() statement, it checks whether that given user already has a “session” object associated with it. If not, then it initializes the
state value of
100. Note that this only happens once per user!
- When the user clicks the “Increment x” button, Streamlit reruns your script from top to bottom. This time, the
SessionState.get() statement will return that user’s existing SessionState object.
- Since the user clicked the button, the
if condition will be
state.x will increment by
st.write() will write “Current value of x: 1” to the app.
- If the user clicks “Increment x” again, Streamlit will rerun your script from top to bottom. Now
SessionState.get() will return a state object where
state.x is set to
1. So this time the code inside the
if condition will increment it to
And so on!
I’ve thought of it two ways, either the initialization step could be performed once, or the updated variable could be cached. I too am looking for this functionality.
As described above, your first idea is exactly what we do: the initialization step is only performed once
This discussion is super valuable, by the way! It makes it clear that API of the
SessionState prototype is not very clear. One way to improve it would be to rename the
get() method to something like
get_existing or something like that.
Also: with respect to buttons in general, in addition to the “widget group” API I mentioned at the top, we’re also considering another API where buttons are allowed to run small callback functions before a script executes — among other ideas. For more on this, check out this thread: How to evolve complex state (e.g., annotate data)?