Summary
I am using a color picker in combination with buttons to allow users to select a color and have an easy color reset. In the simplest form, the unexpected behavior is that the reset button doesn’t always work immediately after choosing a new color with the color picker. However, it does work if some other activity happens in between changing the color picker and using the reset button.
I can work around this in and of itself, but I am more interested in the underlying inconsistency using st.session_state
and how the app refreshes when it reloads with the button click. I’m planning to submit a bug report unless it is revealed I have misused st.session_state
somehow.
Pathological Example: The Setup
UI elements in bold. Variables in monospace.
I have two color pickers. I am storing information in st.session_state.color1
and st.session_state.color2
, both initialized at the beginning of the script with an assignment to variables color1
and color2
, respectively. Note that picker1 outputs directly into st.session_state.color1
, but picker2 outputs to the variable color2
which is then copied into st.session_state.color2
. This difference highlights an extra bit of discrepancy that can occur between color1
and st.session_state.color1
as displayed below the button. picker2 can still exhibit the error, but doesn’t display mismatched information below the button like picker1 does.
Finally, I put a dummy button at the top of the app that outputs all the color information along with a key derived from a timestamp to force it to rebuild the button from scratch with every page load. This is key to my question since I am wondering if there is an issue with how the delta is computed to update the page.
Steps to Reproduce
From a fresh load of the app:
- change picker1,
- click red1 see it work,
- change picker1,
- click red1 see it not work.
- You could instead use blue1, green1, or reset instead of red1 to see the issue. The error affects whatever next button is used if it applies to that same color picker.
- Note the differences between the variable and the session state info, both in the dummy button at top and below the color pickers where it is repeated.
I have included a gif showing other variations and highlighting where the color information does and doesn’t update correctly.
Code snippet:
import streamlit as st
import time
def initialize():
if 'color1' not in st.session_state:
st.session_state.color1 = '#3A5683'
if 'color2' not in st.session_state:
st.session_state.color2 = '#73956F'
return
initialize()
color1 = st.session_state.color1
color2 = st.session_state.color2
st.button(f'time={time.time()%10}, c1={color1}, ss.c1={st.session_state.color1}, c2={color2}, ss.c2={st.session_state.color2}', key=str(time.time()))
def set_color(color, player):
if player == 1:
st.session_state.color1 = color
else:
st.session_state.color2 = color
return
def reset():
set_color('#3A5683',1)
set_color('#73956F',2)
return
st.button('reset', key='reset', on_click = reset)
columns = st.columns(2)
with columns[0]:
st.session_state.color1 = st.color_picker('picker1', value = color1)
st.write(f'color1 is {color1}')
st.write(f'st.session_state.color1 is {st.session_state.color1}')
st.button('red1', key='r1', on_click = set_color, args=('#FF0000',1))
st.button('blue1', key='b1', on_click = set_color, args=('#0000FF',1))
st.button('green1', key='g1', on_click = set_color, args=('#00FF00',1))
with columns[1]:
color2 = st.color_picker('picker2', value = color2)
st.session_state.color2 = color2
st.write(f'color2 is {color2}')
st.write(f'st.session_state.color2 is {st.session_state.color2}')
st.button('red2', key='r2', on_click = set_color, args=('#FF0000',2))
st.button('blue2', key='b2', on_click = set_color, args=('#0000FF',2))
st.button('green2', key='g2', on_click = set_color, args=('#00FF00',2))
Behavior:
I am expecting the color1 == st.session_state.color1
and color2 == st.session_state.color2
and for that to be correctly displayed both in the dummy button above and text below the buttons. I am expecting the buttons to correctly assign color to the picker and for all the displayed data to update in unison to a change of the picker. However, the data gets out of sync as displayed above.
Debug info
- Streamlit version: 1.13.0
- Python version: 3.10.6
- Using Conda environment (also Streamlit Cloud)
- OS version: WIndows 10
- Browser version: Firefox, Edge, Chrome
Requirements file
Just using streamlit and time
Links
- Link to your GitHub repo: GitHub - MathCatsAnd/Streamlit-Color-Picker: Demonstrating unexpected color-picker behavior
- Link to your deployed app: https://mathcatsand-streamlit-color-picker-app-5zc4eb.streamlitapp.com/
Additional information
For context, I came across this issue while playing around with statefulness and making a tic tac toe game. That is here, for completeness: https://mathcatsand-tictactoe.streamlitapp.com/