TLDR: Bug with saving radio button when changing filters. Reproduction steps: Change a filter (like year). Click on a radio button (state). It will switch in one click. Click on another state, it will jump to the first state in the list. All future clicks will work until another filter change where the bug repeats.
https://2020-overvote.streamlit.app/
In Depth Problem:
I am having trouble keeping the selected st.sidebar.radio button persistent. I have filters the user can change which updates my list and changes the index of the radio buttons. Because of this, I save my button with st.session_state and retrieve it each time, getting the new index of the object and using that in the st.sidebar.radio so it retains the selection.
This works perfect except when the user goes to click on a new radio button. It instead does this rubber band thing where it briefly highlights what was clicked then reverts back to the previous button. Another click, on any radio button (not selected) will select that radio button. This rubber banding continues and only stops if you first change the filter options. Then clicking a new radio button switches it immediately.
If I don’t use the st.session_state for the radio buttons, then they switch normally with one click. But then changing my filters will destroy my currently selected radio button option, putting me at the top of the list.
So being clever, I attempted to split the problem in half, only restoring the st.session_state if the filters were changed (which I also stored). This almost works. The changing of the filters keeps my selected button and changing buttons only takes one click. However, when I change a filter then attempt to change the button, it jumps to the first button. Afterwards, all future clicks work just fine for selection radio buttons until I do the filter change and try to click a new one again.
So being extra clever, I attempted to add more logic to get rid of this transition period, which also worked….by delaying it one more switch of the radio button. So now I click whatever radio buttons I want perfectly fine. I change my filters as much as I want and it retains my selected button, then I click on a new button and it switches to the new radio button fine. At this point, I could change more filters and change the button again, and that would work perfectly, forever. However, if I don’t make a filter change and instead click on another new radio button, it will jump to the top. At this point I am just kicking the can down the road rather than actually fixing the problem……
I’ve attempted to print everything that is going on inside the program to better understand what these st.sidebar.radio buttons are doing and I’ve come to the conclusion that it makes no sense. It appears it doesn’t like to be given the location index of where it is currently selected when you are attempting to change its selection with a click. It gives the rubber banding effect. But if you give it an index that isn’t currently selected and then click something else, it switches fine in one click.
print('Getting current filter params.')
# Store current filter parameters as a list
current_filter_params = [start_year, end_year, mode, sorted(parties)] # sorted(parties) to maintain order
# Retrieve previous filter parameters (if available)
if 'filter_params2' in st.session_state:
previous_filter_params = st.session_state['filter_params2']
else:
previous_filter_params = []
if 'old_state' in st.session_state:
old_state = st.session_state['old_state']
else:
print("Problem with setting old_state")
old_state = sorted_states[0]
if 'flag2' in st.session_state:
flag2 = st.session_state['flag2']
else:
flag2 = 0
# Debug: Print both current and previous filter parameters
print(f"Current filter parameters: {current_filter_params}")
print(f"Previous filter parameters: {previous_filter_params}")
print(f"Old State: {old_state}")
#selected_state = old_state
# Compare the current filter params to the previous ones
if current_filter_params != previous_filter_params:
print("Filters have changed.")
flag = 2
flag2 = 1
# Retrieve the selected state from session state or use the first state
selected_state = old_state
#print(selected_state)
else:
print("Filters have not changed.")
flag = 1
if flag2 == 1:
selected_state = old_state
flag2 = 0
# Save the current filter parameters in session_state for later comparison
st.session_state['filter_params2'] = current_filter_params
print(f"Saving flag2 to: {flag2}")
st.session_state['flag2'] = flag2
# Save the selected_state
if flag == 2:
print(f"Saving old_state EARLY to: {selected_state}")
st.session_state['old_state'] = selected_state
# Check if the selected_state is valid
if selected_state not in sorted_states:
print(f"Selected state {selected_state} is not in the list of available states. Resetting to {sorted_states[0]}.")
selected_state = sorted_states[0]
# Streamlit sidebar to select a state (scrollable list box)
print(f"Selected State: {selected_state}")
selected_state_index = sorted_states.index(selected_state)
print(f"Selected State Index: {selected_state_index}")
selected_state = st.sidebar.radio("Select a State", sorted_states, index=selected_state_index)
print(f"Selected State New: {selected_state}")
# Save the selected_state
if flag == 1:
print(f"Saving old_state LATER to: {selected_state}")
st.session_state['old_state'] = selected_state