Hello!
I am new to streamlit. I was wondering if there was a way to nest 3+ buttons, not only 2? I have only seen examples for 2. Thank you! If someone could make a simple example that would also be great. Thank you!
Hello!
I am new to streamlit. I was wondering if there was a way to nest 3+ buttons, not only 2? I have only seen examples for 2. Thank you! If someone could make a simple example that would also be great. Thank you!
Hello, @GriffinF, welcome to the forum!
Here’s one way to work it, by using session state as the source of truth, and treating each button as a toggle for the session state.
Code:
import streamlit as st
# This doesn't work, because button "pressed" state doesn't survive rerun, and pressing
# any button triggers a rerun.
st.write("# This doesn't work:")
if st.button("Button1_take1"):
if st.button("Button2_take1"):
if st.button("Button3_take1"):
st.write("Button3")
# So, instead, we use session state to store the "pressed" state of each button, and
# make each button press toggle that entry in the session state.
st.write("# This works:")
if "button1" not in st.session_state:
st.session_state["button1"] = False
if "button2" not in st.session_state:
st.session_state["button2"] = False
if "button3" not in st.session_state:
st.session_state["button3"] = False
if st.button("Button1"):
st.session_state["button1"] = not st.session_state["button1"]
if st.session_state["button1"]:
if st.button("Button2"):
st.session_state["button2"] = not st.session_state["button2"]
if st.session_state["button1"] and st.session_state["button2"]:
if st.button("Button3"):
# toggle button3 session state
st.session_state["button3"] = not st.session_state["button3"]
if st.session_state["button3"]:
st.write("**Button3!!!**")
# Print the session state to make it easier to see what's happening
st.write(
f"""
## Session state:
{st.session_state["button1"]=}
{st.session_state["button2"]=}
{st.session_state["button3"]=}
"""
)
To see it in action:
https://playground.streamlitapp.com/?q=triple-button
Hey, this is super awesome, thank you!!
Hey, I was also wondering if there was a way for example: if you click button 1, x = ‘hi’, to carry that to button 2 and if button 2 was clicked you can st.write(x). Something along those lines.
That works exactly like you’d expect. Pseudocode:
x = “”
if button 1 clicked:
x = “hi”
if button 2 clicked:
st.write(x)
That should work just as you expect it to. In general, other than cases of using st.session_state or st.experimental_cache, you can think of a streamlit app as a script that just runs from top to button, but also is affected by the widget states.
Hopefully that’s helpful.
Please how can i do that for this?
if st.button("Upload CSV with DateTime Column"):
st.write("IMPORT DATA")
st.write(
"Import the time series CSV file. It should have one column labelled as 'DateTime'")
data = st.file_uploader('Upload here', type='csv')
st.session_state.counter = 0
if data is not None:
dataset = pd.read_csv(data)
dataset['DateTime'] = pd.to_datetime(dataset['DateTime'])
dataset = dataset.sort_values('DateTime')
junction = st.number_input(
'Which Junction:', min_value=1, max_value=4, value=1, step=1, format='%d')
results = predict_traffic(junction, dataset['DateTime'])
st.write('Upload Sucessful')
st.session_state.counter += 1
if st.button("Predict Dataset"):
result = results
result = pd.concat([dataset, result], axis=1)
st.success('Successful!!!')
st.write('Predicting for Junction', 1)
st.write(result)
def convert_df(df):
# IMPORTANT: Cache the conversion to prevent computation on every rerun
return df.to_csv().encode('utf-8')
csv = convert_df(result)
st.download_button(
label="Download Traffic Predictions as CSV",
data=csv,
file_name='Traffic Predictions.csv',
mime='text/csv',
)
st.session_state.counter += 1
Do you have a particular reason for using a button to show the upload dialog? You could certainly do that, but it seems more natural to using something like st.expander, like so:
with st.expander("Upload CSV with DateTime Column"):
st.write("IMPORT DATA")
st.write(
"Import the time series CSV file. It should have one column labelled as 'DateTime'"
)
data = st.file_uploader("Upload here", type="csv")
st.session_state.counter = 0
if data is not None:
dataset = pd.read_csv(data)
dataset["DateTime"] = pd.to_datetime(dataset["DateTime"])
dataset = dataset.sort_values("DateTime")
junction = st.number_input(
"Which Junction:", min_value=1, max_value=4, value=1, step=1, format="%d"
)
results = predict_traffic(junction, dataset["DateTime"])
st.write("Upload Sucessful")
st.session_state.counter += 1
if st.button("Predict Dataset"):
result = results
result = pd.concat([dataset, result], axis=1)
st.success("Successful!!!")
st.write("Predicting for Junction", 1)
st.write(result)
def convert_df(df):
# IMPORTANT: Cache the conversion to prevent computation on every rerun
return df.to_csv().encode("utf-8")
csv = convert_df(result)
st.download_button(
label="Download Traffic Predictions as CSV",
data=csv,
file_name="Traffic Predictions.csv",
mime="text/csv",
)
st.session_state.counter += 1
Hi @blackary , I seem to have encountered another small problem, anytime I click on the download button, the file is downloaded and the site refreshes immediately as well
In general that’s just how streamlit inputs work, including buttons – when you change them/click on them/etc it causes the app to rerender. Other widgets should keep their state (e.g. dropdowns should stay expanded, uploaded files should stay uploaded, etc.), but sometimes this can be a problem because there is some slow/expensive calculation that you don’t want to rerun often. In that case, st.experimental_memo may be the solution. Is it causing other problems that you are trying to avoid?
It’s not really causing any problem I’m trying to avoid. So I guess I can live with it.
Once again, Thank you so much for your help.
How can I do this with st.experimental_data_editor ? In editable table version ?
I’m not sure what you mean. This topic is about nesting buttons so I’m unclear how you want to relate that to the editable dataframe. I think you can go ahead and create a new topic with a more complete explanation of what you are trying to accomplish and what you have tried that isn’t working.