Hi Streamlit Community,
Iām encountering an issue with a Streamlit app Iām developing. The problem is that my āSimulateā button requires two clicks to trigger its associated first action, but not for the rest. The expected behavior is that upon a single click, the button should execute a function that updates the state of the app and displays a predicted value.
Hereās a simplified version of the problematic part of my code:
import streamlit as st
# Assume necessary imports and setup are done here
# In the actual app, these are filled with user input
input_values = {"example": 1}
selected_datetime = "2023-01-01 00:00:00"
if 'simulated' not in st.session_state:
st.session_state.simulated = False
if 'input_df' not in st.session_state:
st.session_state.input_df = pd.DataFrame()
st.write('State of input_df before simulation:')
st.dataframe(st.session_state.input_df)
if st.button("Simulate"):
st.write('Simulate button clicked')
st.session_state.input_df = pd.DataFrame([input_values], index=[selected_datetime])
# Further processing and state updates
st.session_state.simulated = True
if st.session_state.simulated:
st.write('Post-simulation code executed')
# Code to display predictions and other state-dependent elements
- Running localy
- Not deployed
- Newest python and Streamlit versiosn
Iāve already tried the following:
- Ensuring there are no errors in the console
- Simplifying the button action code
- Confirming that Streamlit is up to date
- Restarting the Streamlit server
- Testing in different browsers and in incognito mode
Could anyone suggest why the button isnāt working on the first click and what I might do to resolve this issue?
Also, Iāve realized that the same issue of the button requiring two clicks to work is also happening in another part of my application. This second scenario involves an optimization function triggered by a button. Hereās the relevant part of the code:
import streamlit as st
import pandas as pd
import time
# Assuming necessary imports and setup for the model and optimization functions
# In the actual app, 'selected_day_data' and other variables are set earlier in the code
selected_day_data = {"example_data": 1.23}
input_values = {"example_input": 4.56}
# Initialize progress in session state if not present
if 'progress' not in st.session_state:
st.session_state['progress'] = 0
if st.button('Optimize'):
st.write('Optimize button clicked') # This should appear when the button is clicked
start_time = time.time()
progress_bar = st.progress(0)
progress_bar.progress(st.session_state['progress'])
# Simulating optimization process (replace with actual function call)
best_values = {'optimized_result': 42}
# Additional code for processing best_values and updating session state
# ...
# Complete the progress and display elapsed time
progress_bar.progress(1.0)
elapsed_time = time.time() - start_time
st.write(f"Optimization completed in {elapsed_time:.2f} seconds.")
# Code related to optimization results rendering
# ...
Thank you for your assistance!
Best,
Gabriel Gomes
Hi @Gabriel_Gomes
Ideally, you can implement a callback function to maintain your app stateful and manage the logic of when to run certain functions better. I strongly recommend reading this article about the differences between approaches using buttons.
Hope it helps!
1 Like
Follow-Up on Button Click Issue in Streamlit
Hi CarlosSerrano,
Thank you for your previous advice on implementing a callback function to maintain a stateful app and manage function executions in Streamlit. Iāve read through the provided article and applied the suggested solutions to my application.
Iām happy to report that using a callback function with the button has solved the issue with the first scenario where I had to click the button twice to trigger the function.
However, I encountered some difficulties with the second scenario, which involves more complex state management. Hereās the code template where Iām facing issues:
def update_progress(progress):
st.session_state['progress'] = progress
# Function triggered on button click to run optimization
def on_optimize_button_click():
start_time = time.time()
progress_bar = st.progress(0)
# Check and update progress if already in session state
if 'progress' in st.session_state:
progress_bar.progress(st.session_state['progress'])
# Optimization logic here (simplified for brevity)
# ...
# Record elapsed time and finalize progress
elapsed_time = time.time() - start_time
st.session_state['elapsed_time'] = elapsed_time
st.session_state['progress'] = 100
st.write(f"Otimização concluĆda em {elapsed_time:.2f} segundos.")
# Initialize session state variables if not already present
if 'progress' not in st.session_state:
st.session_state['progress'] = 0
# Additional session state initializations here
# ...
# Button to trigger optimization
if st.button('Otimizar', on_click=on_optimize_button_click):
pass
# UI elements to reflect changes in session state
# ...
The expected behavior is that when the āOtimizarā button is clicked, on_optimize_button_click
should be called, the progress should be updated, and the UI should display the elapsed time. However, the function only seems to execute after the second click.
Any insights on why this might be happening or what I can do to ensure the optimization runs and updates the UI on a single click would be incredibly helpful.
Thank you for your assistance.
Best regards, Gabriel Gomes
Hello.
Please remove the if statement from the button and try again. Just use st.button
Hello Carlos,
Thank you for your previous response. I followed your recommendation and removed the if
statement from the button execution, using directly st.button('Optimize', on_click=on_optimize_button_click)
. However, Iām encountering a situation where the button click doesnāt seem to trigger the on_optimize_button_click
function on the first click. The update to the state is only reflected in the user interface after a second click.
Is there any other aspect of button behavior or session state management that I might be overlooking?
Here is the updated code snippet for reference:
def update_progress(progress):
st.session_state['progress'] = progress
def on_optimize_button_click():
start_time = time.time()
progress_bar = st.progress(0)
# Other treatments
# Update session state with the results
st.session_state['cu_teor'] = cu_teor
st.session_state['best_values'] = best_values
st.session_state['progress'] = 100
st.session_state['elapsed_time'] = time.time() - start_time
st.write(f"Optimization completed in {st.session_state['elapsed_time']:.2f} seconds.")
# Initialize session state variables if they are not already present
if 'progress' not in st.session_state:
st.session_state['progress'] = 0
if 'cu_teor' not in st.session_state:
st.session_state['cu_teor'] = 0
if 'best_values' not in st.session_state:
st.session_state['best_values'] = {}
if 'elapsed_time' not in st.session_state:
st.session_state['elapsed_time'] = None
# Define the button that triggers the optimization process
st.button('Optimize', on_click=on_optimize_button_click)
I appreciate your help in advance!
Best regards,
Gabriel Gomes