Have been using Streamlit for a few weeks and am really loving it.
Iāve built an app that performs 10-20s of computation, displaying output as it goes. Once it comes to the end, I would like it to ask the user if they want to see additional information.
The idea is that this would be a button which, upon being clicked, would proceed to load more information and display it. Think something like this:
st.write("Doing stuff on every page load")
...
st.write("Finished doing stuff")
if st.button("Do you want to see more?"):
st.write("Doing more optional stuff")
My issue right now is that when the user presses the button, the entire page reloads. I understand why this is the case given Streamlitās execution flow, and I understand why it makes sense.
My question is if thereās a way around this? I have seen sporadic mentions of the session_state but I donāt see how that answer applies to this case, since Iām not interested in saving information between runs. Sure, I could memoize the entire rest of the page but thatās not ideal either, as Iād have to make an artbitrary decision on the TTL. Also, there are definitely things in the app that cannot be pickled right now.
Although session state seems like it might not apply in this case it does. What you want to do is use the button to add or change a value that you hold in state, and you will use this value to display your optional information!!!
(another work around for this is actually the expander, I will mock up an example of each)
import streamlit as st
col1,buff, col2 =st.columns([2,.3,2])
with col1:
st.subheader("Expander example")
st.write("""Doing stuff on every page load
...
Finished doing stuff""")
with st.expander("Do you want to see more?"):
st.write("Doing more optional stuff")
with col2:
if "more_stuff" not in st.session_state:
st.session_state.more_stuff = False
st.subheader("Button example")
st.write("""Doing stuff on every page load
...
Finished doing stuff""")
click = st.button("Do you want to see more?")
if click:
st.session_state.more_stuff = True
if st.session_state.more_stuff:
st.write("Doing more optional stuff")
Hi Marisa - thanks for getting back to me. Unfortunately, your example isnāt a solution to my problem - I took your code, added a spinner with a sleep to it at the top of the page and found that clicking the āDo you want to see more?ā button did indeed re-trigger that spinner.
The expander isnāt a solution either, since that requires the content within the expander to be run regardless of whether youāve expanded it or not.
So, let me be clear, the Streamlit execution flow will always work like this. Each time you interact with a widget on the page the entire Streamlit script will be re-run from top to bottom.
The button solution I provided allows you to āhideā additional widgets behind a button click. Normally, when you have a button it returns True on only one run-through of the app and then changes back to its default (False). But the method I coded for you above, allows you to link a value in st.session_state that you can use instead of the return value of the button itself to run additional āstuffā in your app that will persist past the buttonās natural true-only-once behaviour.
To get this method execution to work with your spinner you will likely need to add some logic to your spinner for various conditions for your app. But I wonāt be able to code any examples for you until I see a minimum working example of the execution flow youāre trying to achieve.
But could you give me a few more details about what you are doing in your app (i.e. the ā10-20s of computation, displaying output as it goesā)? We are currently looking at how we can improve caching, so this would be really useful feedback for me!! If you canāt share publicly, we can also write via DM or jump on a short call if you like
Re-running the application on each button click is pretty much unavoidable. If that is making your application slow, the solution is caching, either using cache primitives or session_state.