Giter VIP home page Giter VIP logo

Comments (8)

Asaurus1 avatar Asaurus1 commented on May 8, 2024 2

@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.

LukasMasuch avatar LukasMasuch commented on May 8, 2024 1

@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.

Asaurus1 avatar Asaurus1 commented on May 8, 2024 1

@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:

  1. You create the options list in session_state
  2. You create a selectbox that is tied to the selected_option key
  3. 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.

Asaurus1 avatar Asaurus1 commented on May 8, 2024 1

from streamlit.

github-actions avatar github-actions commented on May 8, 2024

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.

Visits

from streamlit.

ameen7626 avatar ameen7626 commented on May 8, 2024

is there any workaround to fix this issue

from streamlit.

nathancooperjones avatar nathancooperjones commented on May 8, 2024

@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

Untitled-ezgif com-video-to-gif-converter

from streamlit.

nathancooperjones avatar nathancooperjones commented on May 8, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.