Comments (8)
@nathancooperjones this is unfortunately less of a "bug" and more an intended but unexpected consequence of the way the streamlit execution model and widget system works. Any time you change the input value of an argument to a widget, streamlit sort of perceived that widget as an entirely new widget, and doesn't guarantee that the old widget value will carry over. There are a couple of technical reasons why it has to be this way, but that's partly what's causing the problem here. There's a "careful dance of information" (for lack of a better term) going on between the frontend webpage and the python backend each run and "new" widgets are treated slightly differently from ones that existed during the last script run. See https://docs.streamlit.io/develop/concepts/architecture/widget-behavior for a little more info.
The other issue I see here is that you're modifying the order of the list after the widget is rendered, which means it doesn't take effect until the next time the script reruns.
Try placing your if statement that reorders the list inside a function that is called by st.selectbox on_change and see if you get more reliable results.
from streamlit.
@nathancooperjones thanks for reporting this 👍 I reproduced it here. As @Asaurus1 explained correctly, its a behaviour that's currently expected (-> changing this to a feature request). But we are aware that it is causing trouble in some usecases.
Related issues for other widgets are:
from streamlit.
@nathancooperjones hmm, I think that might be a bit overkill. This should be what you want
import streamlit as st
# set up some dummy session state variables
st.session_state.setdefault("options", ['D', 'C', 'B', 'A', 'F', 'E'])
def update_options():
# move the selected option to the front of the list if it is not already
if st.session_state.selected_option != st.session_state.options[0]:
st.session_state.options.remove(st.session_state.selected_option)
st.session_state.options.insert(0, st.session_state.selected_option)
st.selectbox(
label='Select an option',
options=st.session_state.options,
key="selected_option",
on_change=update_options,
)
st.markdown(f'You selected: {st.session_state.selected_option}')
Here's what's happening:
- You create the options list in session_state
- You create a selectbox that is tied to the selected_option key
- When the selection changes, the update_options function is run before your script code and updates the list in session state, causing the order to change.
from streamlit.
from streamlit.
If this issue affects you, please react with a 👍 (thumbs up emoji) to the initial post.
Your feedback helps us prioritize which bugs to investigate and address first.
from streamlit.
is there any workaround to fix this issue
from streamlit.
@Asaurus1 @LukasMasuch thanks for the reply and linking some similar issues, I appreciate the response! I tried moving the option sorting logic into a function called by the selectbox
's on_change
but the issue still happens :(
As a workaround in the meantime, I've been caching the options sent into the selectbox
so the widget doesn't reset each time until the set of options actually change. It's a SUPER hacky, but it works well-enough for my use case:
import streamlit as st
# set up some dummy session state variables
if 'options' not in st.session_state:
st.session_state.options = ['D', 'C', 'B', 'A', 'F', 'E']
# cache the options to the ``st.selectbox`` doesn't reset and ignore a user's input if the order of
# the options changes
if set(st.session_state.get('_cached_options', [])) != set(st.session_state.options):
st.session_state._cached_options = sorted(st.session_state.options)
if 'selected_option' in st.session_state:
st.session_state._selectbox_index = (
st.session_state._cached_options.index(st.session_state.selected_option)
)
else:
st.session_state._selectbox_index = 0
st.session_state.selected_option = st.selectbox(
label='Select an option',
options=st.session_state._cached_options,
index=st.session_state._selectbox_index,
)
st.markdown(f'You selected: {st.session_state.selected_option}')
# move the selected option to the front of the list if it is not already
if st.session_state.selected_option != st.session_state.options[0]:
st.session_state.options.remove(st.session_state.selected_option)
st.session_state.options.insert(0, st.session_state.selected_option)
# dummy logic to add an option just to see how ``st.session_state.options`` changes
if st.button('Add an option'):
option_to_add = 1
while True:
if str(option_to_add) not in st.session_state.options:
st.session_state.options.append(str(option_to_add))
st.rerun()
option_to_add += 1
from streamlit.
@nathancooperjones hmm, I think that might be a bit overkill. This should be what you want
OMG this is SO much better than the solution I had, thank you so much!!
I realized that it didn't work for me because I was assigning the output of selectbox
to the variable. This does not work:
import streamlit as st
# set up some dummy session state variables
if 'options' not in st.session_state:
st.session_state.options = ['D', 'C', 'B', 'A', 'F', 'E']
def update_options():
# move the selected option to the front of the list if it is not already
if st.session_state.selected_option != st.session_state.options[0]:
st.session_state.options.remove(st.session_state.selected_option)
st.session_state.options.insert(0, st.session_state.selected_option)
st.session_state.selected_option = st.selectbox(
label='Select an option',
options=st.session_state.options,
on_change=update_options,
)
st.markdown(f'You selected: {st.session_state.selected_option}')
But this does:
import streamlit as st
# set up some dummy session state variables
if 'options' not in st.session_state:
st.session_state.options = ['D', 'C', 'B', 'A', 'F', 'E']
def update_options():
# move the selected option to the front of the list if it is not already
if st.session_state.selected_option != st.session_state.options[0]:
st.session_state.options.remove(st.session_state.selected_option)
st.session_state.options.insert(0, st.session_state.selected_option)
st.selectbox(
label='Select an option',
options=st.session_state.options,
key='selected_option', # change here
on_change=update_options,
)
st.markdown(f'You selected: {st.session_state.selected_option}')
This is super good to know going forward, thank you!!
from streamlit.
Related Issues (20)
- StrEnum doesn't work with st.selectbox, st.multiselect options HOT 6
- pytest raises error in doc-string HOT 1
- Prevent layout shift caused by scrollbars HOT 2
- Rerun when dismissing `st.dialog` by clicking on X or pressing Escape HOT 9
- rerun fragment only programatically with `st.experimental_fragment` instead of `run_every` HOT 5
- Support chart selections (with `on_select`) for Altair v4 HOT 1
- [Feedback requested!] Proposal - Native authentication support for Streamlit HOT 6
- Multiprocessing failing with `concurrent.futures.ProcessPoolExecutor` HOT 1
- iframed Streamlit with CSP frame-src breaks when using st.download_button HOT 1
- Dataframe toolbar download button does not work when Streamlit app is iframed cross-origin HOT 3
- Nested Grids for Grouping Rows - Feature Request HOT 2
- Altair Grouped Barchart with st.altair_chart(use_container_width=True) creates multiple charts instead of one single grouped chart HOT 1
- Unable to upload >980 files using file_uploader HOT 2
- reload function HOT 2
- Not handled DecodeError on the server side on file upload with double extension HOT 1
- Shut down the session after closing the browser tab by the user HOT 4
- Allow ignoring markdown rendering in `st.markdown`, `st.info`, `st.warning`,... HOT 7
- Add `border` to `st.columns` HOT 2
- st.date_input not working in the sidebar on mobile devices or very narrow windows HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from streamlit.