Summary
Hi everybody!
I am using Streamlit to combine plotly visualisations with a survey using st.form.
Some users that accessed the app on their phones reported that the app froze after they hit the submit button. Unfortunately, I am unable to reproduce their error. I only have a vague idea that my handling of session state might be part of the problem. I describe my suspicion in more detail below.
Steps to reproduce
The app has three pages. The first, main page only holds an image. The second page loads and displays data and holds a st.form. Submitted st.form’s are sent to a private google sheet using the shillelagh package. This is the page where the error occurred. The third page loads the data from the same google sheet, and filters and displays todays submissions.
Here’s why I assume that session state might be the reason for the bug:
The order in which the graphs(“scenarios”) are displayed on page 2 is randomised. To randomise within a st.form and not lose widget values after submitting, I thought it’s clever to set random.seed(st.session_state.rs) with rs being a random state initialized earlier. However, when I display st.session_state.rs in multiple tabs of the app, I realised that the app only generates three random numbers as rs, namely 37, 81 and 95. This is independent from device or browser.
I tried submitting forms with the same session_state from multiple devices and multiple browsers at the same time, and it always worked for me. Do you have any ideas how I could reproduce the error, ie. the freezing of the app? Is it related to the fact that multiple users having the same session_state at the same time?
Code snippets
I used this code in the second page to initialize the session state and randomise the order of graphs/ scenarios:
#set random session state
if 'rs' not in st.session_state:
st.session_state['rs'] = random.randint(1, 100)
st.write(st.session_state.rs)
#randomly order scenarios/ graphs, based on random.seed that takes session_state.rs as input
def random_scenario_order():
random.seed(st.session_state.rs)
scenario_list = ["Scenario \u25B2", "Scenario \u25A0", "Scenario \u25C6"]
scenario_list_nutr = random.sample(scenario_list, len(scenario_list))
scenario_list_tran = random.sample(scenario_list, len(scenario_list))
scenario_list_buil = random.sample(scenario_list, len(scenario_list))
scenario_list_gdp = random.sample(scenario_list, len(scenario_list))
return scenario_list_nutr, scenario_list_tran, scenario_list_buil, scenario_list_gdp
scenario_list_nutr, scenario_list_tran, scenario_list_buil, scenario_list_gdp = random_scenario_order()
and this code to load the form to the google sheets:
#prepare google sheet connection
sheet_url = st.secrets["private_gsheets_url"]
#@st.cache_data
def create_connection():
credentials = service_account.Credentials.from_service_account_info(
st.secrets["gcp_service_account"],
scopes=["https://www.googleapis.com/auth/spreadsheets",],)
connection = connect(":memory:", adapter_kwargs={
"gsheetsapi" : {
"service_account_info" : {
"type" : st.secrets["gcp_service_account"]["type"],
"project_id" : st.secrets["gcp_service_account"]["project_id"],
"private_key_id" : st.secrets["gcp_service_account"]["private_key_id"],
"private_key" : st.secrets["gcp_service_account"]["private_key"],
"client_email" : st.secrets["gcp_service_account"]["client_email"],
"client_id" : st.secrets["gcp_service_account"]["client_id"],
"auth_uri" : st.secrets["gcp_service_account"]["auth_uri"],
"token_uri" : st.secrets["gcp_service_account"]["token_uri"],
"auth_provider_x509_cert_url" : st.secrets["gcp_service_account"]["auth_provider_x509_cert_url"],
"client_x509_cert_url" : st.secrets["gcp_service_account"]["client_x509_cert_url"],
}
},
})
return connection.cursor()
##
##
# I am skipping the lines of the st.form. It's basically 22 widgets (q1 - q22)
##
##
#submitting form
submitted = st.form_submit_button("Click here to submit!")
if submitted:
cursor = create_connection()
query = f'INSERT INTO "{sheet_url}" VALUES ("{q1}", "{q2}", "{q3}", "{q4}", "{q5}", "{q6}", "{q7}", "{q8}", "{q9}", "{q10}","{q11}","{q12}","{q13}","{q14}","{q15}","{q16}","{q17}","{q18}","{q19}","{q20}","{q21}","{q22}", "{timestamp}")'
cursor.execute(query)
st.write("**:green[Submission successful. Thank you for your input!]**")
If applicable, please provide the steps we should take to reproduce the error or specified behavior.
Expected behavior:
I would have expected that each tab has it’s own unique session_state.
Actual behavior:
Random session state is repeating itself after three tabs.
However, I want to mention again that the app and the form submission works perfectly fine within my tests. The bug I want to fix and which I cannot reproduce is that the app seems to freeze when some users hit the submit button on their phones.
Debug info
conda version : 23.3.1
conda-build version : 3.24.0
python version : 3.10.11.final.0
streamlit: 1.23.1
Requirements file
pyam-iamc==1.8.0
pillow==9.5.0
plotly==5.14.1
streamlit_survey==0.1.0
shillelagh
google-auth>=1.23.0,<2
gspread
google
pydrive
gspread_dataframe
gsheetsdb
Links
- Link to your GitHub repo: GitHub - zyankarli/INCLISA
- Link to your deployed app: https://zyankarli-inclisa-climate-justice-r7mrym.streamlit.app/Mitigation_Scenarios