I’m not sure if this has been figured out and posted elsewhere, but I’ve looked for a solution and haven’t found exactly what I was looking for.
I’ve been building a dashboard for drilling down into data and I wanted to sync the options for all the multiselect components such that you don’t see options that aren’t available. Meaning, when you select value from one multiselect, the options for the other multiselects update.
I found this post: Dynamic multiselect options tied to presence in a list/dataframe, which handles syncing options, but only downstream.
I made a solution that seems to work pretty well. It’s not exactly simple, but it does what I need to do.
Basically, you store each component’s value in session state and use that to generate new options each time the app refreshes.
import streamlit as st import pandas as pd from vega_datasets import data df = data.cars() df['Year'] = df['Year'].dt.year # The components like to update and choose new values when you apply these methods. # Each time the dashboard updates, you need to set the reset the value and options for each component. # To do that, store each components value in st.session_state. # if there is a value in st.session_state for years if "years" in st.session_state and st.session_state['years']: # get the selected value. Use this to set the value of the year slider later years = st.session_state['years'] # filter the dataframe for the selected years and grab the indices year_idx = df[(df['Year'] >= years) & (df['Year'] <= years)].index # if no value is selected or "years" hasn't been added to the session_state yet, set default values else: years = [min(df['Year']), max(df['Year'])] year_idx = df['Year'].index # Do the same for names if 'name' in st.session_state and st.session_state['name']: names = st.session_state['name'] name_value = names name_idx = df[df['Name'].isin(names)].index.unique() else: name_value =  name_idx = df.index # Do the same for Origin if 'origin' in st.session_state and st.session_state['origin']: origins = st.session_state['origin'] origin_value = origins origin_idx = df[df['Origin'].isin(origins)].index.unique() else: origin_value =  origin_idx = df.index # Find the interseciton of all the filtered indices. idx = list(set(year_idx).intersection(set(name_idx), set(origin_idx))) # Filter the dataframe dff = df.loc[idx] # Make the year slider years = st.slider("Years", min_value=min(df['Year']), max_value=max(df['Year']), value=years, key="years") # Get the filtered origin options origin_options = df.loc[list(set(year_idx).intersection(set(name_idx)))]['Origin'].sort_values().unique() # Make the origin multiselect origins = st.multiselect("Origin", origin_options, default=origin_value, key="origin") # Show the number of Origin options (just sanity check that it updated) st.write(len(dff['Origin'].unique())) # Get the filtered name options name_options = df.loc[list(set(year_idx).intersection(set(origin_idx)))]['Name'].sort_values().unique() # Make the name multiselect names = st.multiselect("Name", name_options, default=name_value, key="name") # Show the number of Name options (just sanity check that it updated) st.write(len(dff['Name'].unique())) # Show the filtered dataframe st.write(dff)
I don’t know if this is the easiest or fastest way to do this, but it’s a solution that seems to work. It’s a bit cumbersome if you have a lot of components you want synced, but worth it in my opinion.