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

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