Dynamic multiselect options tied to presence in a list/dataframe

Hi everyone. I had some fun today making streamlit’s multiselect options behave together in a co-dependent manner. This post here isn’t an issue but rather an observation of how to get something extra out of the system (with scope for change in the future? Or at least a guide on something other people may find interesting).

I’ve set up a system where a user selects an option from one multiselect box and, based upon their selection, the options for a second multiselect will be changed according to values in a pre-existing data structure.

Let’s say we have a dataframe called df:

    | 'A' | 'B' | 'C' |
1     4     6     1
2     6     4     2
3     6     9     3

And I set up some columns:
col1, col2, col3 = st.beta_columns(3)

Right now, if I want to use a dependent chain of multiselects whose options depended on what I chose for a previous multiselect, here’s what I can do:

with col1:
    option1 = st.multiselect("Option 1", list(set(df.iloc[:, 0])))
with col2:
    option2 = st.multiselect("Option 2", list(set(df.loc[(df.iloc[:, 0].isin(option1))][df.columns[1]])))
with col3:
    option3 = st.multiselect("Option 3", list(set(df.loc[(df.iloc[:, 0].isin(option1)) & (df.iloc[:, 1].isin(option2))][df.columns[2]])))
user_choice = list(product(*[option1, option2, option3]))

If the user chooses 6 for option 1, option2 will present options 4 and 9, whereas if the user chooses 4 for option 1, option2 will present only 6. So far so good. Now image you have six chained dependent options, each requiring more and more lines of code to whittle down the choices of the dataframe (because option3 would need to do an iloc of both option 1 and 2, and so on). Gets a bit heavy with 6 in total, but it gets the job done.

Note: invalid combinations may be present in user_choice, so they need to be parsed manually.

I’m wondering if there would be a possible cleaner solution to this issue? Incorporating linked keys so that multiselect widgets could operate in a hierarchy is a potential option (and potential nightmare). Or maybe this is more an issue of cleaner coding in python to not abuse the limitations of streamlit?

Seems to be a bit of interest in this topic elsewhere

1 Like

Hey @Cells,

First, Welcome to the Streamlit Community! :tada: :tada: :tada: :partying_face: :tada: :tada: :tada:

This solution is the same as I would have implemented for this, in fact I made a similar solution for a user who was looking to filter the whole dataframe (slightly different but linking here just in case it’s helpful!)

It does begin to get long if your looking to filter many options, but I haven’t yet come up with a more clever/cleaner solution!

Happy Streamlit-ing!
Marisa

1 Like

Hi Marisa, thanks for the welcome!

I like the simplicity of the other solution too; seems like this is the way to go for chaining together options between selectboxes or multiselects.

Looking forward to using streamlit more in the future

2 Likes

How to achieve the very same functionality in the reversed way?
Let’s assume two multiselects A & B, B is below A.
How to update the options for multiselect A based on selections made in multiselect B.
@Marisa_Smith the code you shared, the chaining works only in a downward fashion…it doesn’t work in an upward direction. Or maybe I am missing something.

Thanks.

Hi @ganesh_singh,

First, welcome to the Streamlit community! :tada: :star2: :partying_face: :tada: :tada: :partying_face: :star2:

You are right, this chaining only works in a downward fashion. There may be some clever way to use pandas and Streamlit to create this kind of functionality, but I suspect that it requires session state to do it properly.

There is a bit of a hack for session state on this github link: A possible design for doing per-session persistent state in Streamlit · GitHub

However, this is a much-anticipated update that our engineers are working on now to implement! The exact date for the launch of this new feature we aren’t sure yet. But I believe it’s scheduled to come out in Q2!!

Happy Streamlit-ing!
Marisa