How to perform dynamic filtering across multiple columns using st.session_state() or on_change()?

Summary

Hi all, I am trying to create a streamlit app where based on 1 filter selection criteria, I want to populate other filter selections. Then, once the submit button is hit, then I want to proceed ahead with processing the data.

Steps to reproduce

Code snippet:

import streamline as st
import pandas as pd

my_df = pd.DataFrame({
    'Name': ['A', 'A', 'B', 'B', 'C', 'C', 'C', 'D', 'D', 'D', 'D'],
    'Color':['red', 'blue', 'blue', 'black', 'black', 'green', 'blue', 
    'yellow', 'white', 'green', 'purple']
})

col1, col2 = st.columns(2)
name_selection = col1.multiselect('select names ', my_df.name.unique().tolist(), key='names')
color_selection = col2.multiselect('select color ', my_df.color.unique().tolist(), key='color')


Scenario 1
If I select name as A then the color selection should be only a list of red and blue and not others.

Scenario 2
Similarly, when I choose color as Black first, then I should get only a list of B and C in name list. The filter order is dependent on the user.

In general, I have around 5 to 6 filters and once a user selects a filter condition on any one of the multi select columns, then the other filter conditions should automatically update and populate the list.

  1. How can I achieve this using session_state or on_change() functions?
  2. Do I need a st.form() for this?

Here is scenario 1 -

And here is scenario 2 -

1 Like

Hey @pranay_mehta,

Gave it a try in the playground below [original link]. Expand the β€œShow code” expander to see more on the logic. But you were right, the session state helps!

1 Like

Hi @arnaudmiribel ,

This is good starting point towards the solution. But it is still not completely aligned with what I am looking for. In your case - what you do is you auto-select things from other list if user chooses something from current list. I do not want to auto-select everything but rather just filter and keep the list ready.

For instance, when you select color == black, then your names list gets auto selected with names B and C, but I just want the names list to be updated with B and C . Then user can selected either B or C or both of them.

Also, when you I de-select something, there is some strange behavior that I am seeing in your app.

You can change the options of the other widget in a callback.

import streamlit as st
import pandas as pd
from streamlit import session_state as ss


def on_names_change():
    ss.color_options = my_df[my_df.name.isin(ss.names)].color.unique()


def on_colors_change():
    ss.name_options = my_df[my_df.color.isin(ss.colors)].name.unique()


my_df = pd.DataFrame(
    {
        "name": ["A", "A", "B", "B", "C", "C", "C", "D", "D", "D", "D"],
        "color": [
            "red",
            "blue",
            "blue",
            "black",
            "black",
            "green",
            "blue",
            "yellow",
            "white",
            "green",
            "purple",
        ],
    }
)

st.dataframe(my_df.T)

col1, col2 = st.columns(2)

if "name_options" not in ss:
    ss.name_options = my_df.name.unique()
if "color_options" not in ss:
    ss.color_options = my_df.color.unique()

col1.multiselect(
    label="select names",
    options=ss.name_options,
    key="names",
    on_change=on_names_change,
)

color_selection = col2.multiselect(
    label="select colors",
    options=ss.color_options,
    key="colors",
    on_change=on_colors_change,
)

Hi @pranay_mehta I just created a component for dynamic filtering. See more here - https://discuss.streamlit.io/t/new-component-dynamic-multi-select-filters/49595