Multiple st.selectbox with value depending on each one

Hi, i am blocked inside streamlit.
I would like to get an app with multiple level of st.selectbox with each one depending on the other.
I did something like this but it seems not to work. How can I do to make each level of st.selectbox depends on each other results.
I mean I would like to have an app where we can input the number of funds and select on of them depending on filter.
I hope it is clear
Help appreciate
thx.

nombre_fonds = st.number_input('Nombre de fonds pour analyse:', 
                               min_value=1,
                               max_value=15,
                               step=1
                               )

col1, col2, col3, col4, col5 = st.columns(5)
with col1:
    selected_am = [st.selectbox("Choix de la société de gestion",
                                desc['FUND_MGMT_COMPANY'].sort_values().unique(),
                                index=3,
                                key='selected_am'+str(i)
                                ) 
                   for i in np.arange(nombre_fonds)]

with col2:
    type_fonds = [st.selectbox("Nature du fonds",
                                desc.query("FUND_MGMT_COMPANY==@i")['FUND_TYP'].sort_values().unique(),
                                key='type_fonds'+str(i)
                                ) 
                  for i in selected_am]

    if not type_fonds:
        type_fonds = desc.query("FUND_MGMT_COMPANY==@selected_am")['FUND_TYP'].sort_values().unique()

    classes = [['Toutes classes' , 
                *desc.query("FUND_MGMT_COMPANY==@selec_am & FUND_TYP in @type")['FUND_ASSET_CLASS_FOCUS'].sort_values().unique()
            ] for selec_am in selected_am for type in type_fonds]

with col3:
    selected_classe = [st.selectbox("Choix de la classe d'actif",
                                    classes, 
                                    key='selected_classe'+str(i)
                                    ) 
                       for i in np.arange(nombre_fonds)]

if selected_classe == 'Toutes classes':
    fonds_sgp = desc.query("FUND_MGMT_COMPANY == @selected_am & FUND_TYP in @type_fonds")['LONG_COMP_NAME']
else:
    fonds_sgp = desc.query("FUND_ASSET_CLASS_FOCUS==@selected_classe & FUND_MGMT_COMPANY == @selected_am & FUND_TYP in @type_fonds")['LONG_COMP_NAME']    

with col4:
    selected_fonds = [st.selectbox("Choix du fonds",
                                        vl[fonds_sgp].columns.sort_values(),
                                        key='selected_fonds'+str(i)
                                        )
                      for i in np.arange(nombre_fonds)]
     
with col5:
    weights = [st.number_input("Poids:", 
                                    min_value=0.0,
                                    max_value=100.0,
                                    value=100/nombre_fonds,
                                    key='poids'+str(i)
                                )
               for i in np.arange(nombre_fonds)]

Hi @Jacques2101

Thanks for sharing the code snippet. I tried your code and it seems that the desc was not included in the code. Do you think you can share a few rows from this data.

Best regards,
Chanin

here is the first 10 lines of desc data:

	FUND_MGMT_COMPANY	LONG_COMP_NAME	FUND_TYP	FUND_ASSET_CLASS_FOCUS	FUND_TYP	FUND_ASSET_CLASS_FOCUS
0	Ossiam SA	OSSIAM EUROPE ESG MACHINE LEARNING	ETF	Equity	ETF	Equity
1	Ossiam SA	OSSIAM Stoxx Europe 600 ESG Broad Market Equal...	ETF	Equity	ETF	Equity
2	Allianz Global Investors GmbH	Brunner Investment Trust PLC/The	Investment Trust	Equity	Investment Trust	Equity
3	Allianz Global Investors GmbH	Allianz Technology Trust PLC	Investment Trust	Equity	Investment Trust	Equity
4	BNP Paribas Asset Management Luxembourg SA	BNP Paribas Easy FTSE EPRA/NAREIT Eurozone Cap...	ETF	Equity	ETF	Equity
5	BNP Paribas Asset Management Luxembourg SA	BNP Paribas Easy Low Carbon 100 PAB	ETF	Equity	ETF	Equity
6	Ossiam SA	OSSIAM RISK WEIGHTED ENHANCED COMMODITY EX GRA...	ETF	Commodity	ETF	Commodity
7	Groupama Asset Management SA/France	Groupama Asset Management Retraite Equilbre	Fund of Fund	Mixed Allocation	Fund of Fund	Mixed Allocation
8	Groupama Asset Management SA/France	Groupama Asset Management Retraite Dynamique	Fund of Fund	Mixed Allocation	Fund of Fund	Mixed Allocation
9	Ecofi Investissements SA	Ecofi Investissements Epargne Ethique Actions	SICAV	Equity	SICAV	Equity```

Maybe to be more explicit about my purpose:
i would like to select multiple data that are filtered at each step ie by:

  1. the asset management company name (FUND_MGMT_COMPANY)

  2. Nature of the fund (FUND_TYP)

  3. choice of the asset class (FUND_ASSET_CLASS_FOCUS)

That gives the name of the funds and the weight which I need to enter.

and do this for I = 1 to n (the number of funds)

I wrote up a dynamic filtering example on Stack Overflow a while ago. This is a little more general since it includes the option to change the order in which filters are selected, and uses multiselect instead of select. Let me know if you need the example simplified.

import streamlit as st
import pandas as pd

if 'df' not in st.session_state:
    df = pd.DataFrame({
        'Col1':['A','B','C','A'],
        'Col2':[1,2,3,3],
        'Col3':['a','a','b','c']
    })
    st.session_state.df = df

df = st.session_state.df
df_filtered = df.copy()

# Create a value in session state to track where the user is in the process of
# filling out the selections for the filters
if 'confirmed' not in st.session_state:
    st.session_state.confirmed = -2
def confirm(index):
    st.session_state.confirmed = index

st.write('Choose filters in the desired order. Reset filter selection to start over.')
filters = st.multiselect('Choose filters', df.columns, on_change=confirm, args=[-2])
if st.session_state.confirmed == -2:
    st.button('Confirm', on_click=confirm, args=[-1], key='start')

if st.session_state.confirmed >= -1:
    for i, col in enumerate(filters):
        select = st.multiselect(col, df_filtered[col].unique(), key=f'col_{col}', on_change=confirm, args=[i-1])
        if select != []:
            df_filtered = df_filtered[df_filtered[col].isin(select)]
        if i > st.session_state.confirmed:
            st.button('Confirm', on_click=confirm, args=[i])
            break

cols = st.columns(2)
cols[0].write(df)
cols[1].write(df_filtered)

Does that help at all? Here’s the original.

it is not precisely what I want…
I would like to have n filter with exactly the same input with n determined by the user.
I would like to proceed as a funnel at each step of the selection process ie I would like multiple level of the line with the multiple option (the number of lines are given in the option ‘Nombre de fonds pour analyse’ and from this process to get a variable with all the name “fonds” that was selected.
I add that I would like also that in certain option I would like to add a new option which are ‘all’ where the choice is deactivated.
I hope it is clearer now.
Thx.

Here is a different example. There are multiple ways to accomplish this. You can pass unique keys instead of unique labels if you want. If you do use keys, you can get at the result directly from session state instead of collecting the selections like I do here. Hopefully, this provides some direction, though.

import streamlit as st
import pandas as pd
import numpy as np

if 'df' not in st.session_state:
    st.session_state.df = pd.DataFrame(np.random.randint(0,10,size=(100,4)), columns = ['A','B','C','D'])

df = st.session_state.df

st.write(df)

n = st.number_input('Number of selections', step=1)

def selection_row(i):
    cols = st.columns(3)
    a = cols[0].selectbox(f'A ({i})',df['A'].unique())
    b = cols[1].selectbox(f'B ({i})',df[df['A']==a]['B'].unique())
    c = cols[2].selectbox(f'C ({i})',df[df['A']==a][df['B']==b]['C'].unique())
    return (a,b,c)

selections = []

for row in range(n):
    selections.append(selection_row(row))

st.write('Result:')
st.dataframe(selections)