💸 Reduce costs by consolidating proprietary analytics & reporting software to open-source & Dash.
Challenge us to replace your analytics with Dash and reduce costs.

Can't use ALL to create dynamic number of outputs

I have created a dynamic number of dropdowns based on the columns of a dataframe selected by the user. Then I need to modify the options of every dropdown based on the input change of any of then.
When using ALL in the output I was hopping to match all the dropdowns and return a list of new options to all items, however the output doesn’t update any of then.
Here is a summarized version of the code:

Define the layout


app.layout = html.Div([  

    html.Div([
        html.Div( [

            html.Label('Simulation'),
            dcc.Dropdown(
                id='simulation',
                options=[{'label': i, 'value': i} for i in hm.lib.list_symbols()],
                placeholder="Select a dataframe",
            ),
            html.Div(
                id='both_axis',
                children = [],
            ),
        html.Button('Reset',id='reset_button', n_clicks=0),
        ],
        style={'width': '49%', 'display': 'inline-block'})
    ]), 
        html.Div(id = 'features', children = []),
    
        html.Div([dcc.Graph(id= 'heatmap')
             
         ], style={'width': '80%'}), ]) 

Populate the id=features with dropdowns, after receving the dataframe name from id = simulation


@app.callback(
    dash.dependencies.Output('features', 'children'),
    [dash.dependencies.Input('simulation', 'value')],
    
    [dash.dependencies.State('features', 'children')])
def display_dropdowns(simulation, children):
    if simulation != None:
        df = dict_of_df[simulation].copy()
        cat_name, not_cat_name = _is_cat(df) #Function to identify categorical variables 
        dropdowns = []
        for col in cat_name:
            values_to_display = df[col].value_counts().index        
            dropdowns.append(dcc.Dropdown(id= {'type': 'features',
                                               'index': col},
                                options=[{'label': i, 'value': i} if i not in [True, False] else {'label': str(i), 'value': str(i)} for i in values_to_display],
                                value = None,
                                placeholder=col))
        return dropdowns
    else:
        raise dash.exceptions.PreventUpdate

Here is the problem:

For any change in dropdown value the callback is called and should return 2 lists (options and disabled) modifying every dropdown.


@app.callback([dash.dependencies.Output({'type': 'features', 'index': ALL}, 'options'),
               dash.dependencies.Output({'type': 'features', 'index': ALL}, 'disabled')],
              
              [dash.dependencies.Input({'type': 'features', 'index': ALL}, 'value'),
               dash.dependencies.Input({'type': 'both_axis', 'index': 'y_axis'}, 'value'),
              dash.dependencies.Input({'type': 'both_axis', 'index': 'x_axis'}, 'value')], 
              
             [dash.dependencies.State('simulation', 'value'),
             dash.dependencies.State('reset_button', 'n_clicks')])
         
def _modify_df(features, y_axis, x_axis, simulation, reset_button):
    ctx = dash.callback_context
    
    if all(v is None for v in features):
        raise dash.exceptions.PreventUpdate
    else:     
        dl = dict_of_df[simulation].copy() 
        cat_name, not_cat_name = _is_cat(dl)

        input_ = ctx.triggered[0]['value']

        try:
            trigger_loaded = json.loads((ctx.triggered[0]['prop_id']).split('.')[0])['index']

        except:
            trigger_loaded = ctx.triggered[0]['prop_id'].split('.')[0]

        if input_ == 'False':
            input_ = False
        elif input_ == 'True':
            input_ == True

        if trigger_loaded not in ['x_axis', 'y_axis', 'reset_button', 'simulation']:
            names_and_values.append([trigger_loaded, input_])

        if trigger_loaded == 'reset_button':
            names_and_values.clear()

        for tupla in names_and_values:
            if (tupla[0] != None) and (tupla[1] != None):
                dl = dl[dl[tupla[0]] == tupla[1]]            
        for col in cat_name:
            values_to_display_final = dl[col].value_counts().index  
            all_columns.append([{'label': i, 'value': i} if i not in [True, False] else {'label': str(i), 'value': str(i)} for i in values_to_display_final])
            if col not in [y_axis, x_axis, reset_button, simulation]: 
                disabled.append(False)
            elif col in [y_axis,x_axis]: 
                disabled.append(True)

        return all_columns+disabled

Questions:
Does the ALL method works in the output, and if so, how the return should be?
I could create a list of outputs [dash.dependencies.Output(id1, ‘options’), dash.dependencies.Output(id2, ‘options’),…] inside a different callback using the columns of the selected dataframe, how can I share this list to be used as output?