📣 Multiple outputs in Dash - Now Available!

Long time waiting for this! Lots of thanks :smiley: !

Take the state of the props you want to keep the same, e.g.:

@app.callback([
    Output('graph', 'figure'),
    Output('data-table', 'data'),
    Output('data-table', 'columns'),
    Output('container', 'style')
], [Input('data-dropdown', 'value')],
   [State('graph', 'figure'),
    State('data-table', 'data'),
    State('data-table', 'columns'),
    State('container', 'style')])
def multi_output(value, graph_figure, dt_data, dt_columns, container_style):
    if condition_1:
        ...
        return [graph_figure, b, c, d]
    elif condition_2:
        ...
        return [a, dt_data, c, d]
    else:
        ...
        return [a, b, c, container_style]
2 Likes

The app is running on local host but is showing error when I uploaded on AWS. I have attached the jupyter notebook logs for reference. I have also attached the output on Local host and output on AWS. Output on AWS should be similar to the output on Local host

app.layout = html.Div([
    html.H1('Smoothie Fixed Benefit Prices'),
    html.P("These prices are common for all routes in India."),
    html.P("Peak months are:-Jan,June, July, August, November, December."),
    html.P("Peak Hours ( During Peak Months ):-9 A.M. to Midnight"),
    html.P("Peak Hours ( During Non Peak Months ):-12 P.M. - 12 A.M."),
    html.H3('Select Airline'),
    dcc.Dropdown(
        id='datasource-1',
        options=[
            {'label': i, 'value': i} for i in ['Low Delay Airlines (6E, UK)','High Delay Airlines (9W,AI,SG,G8)']
        ],
    ),
    html.H3('Select Peak/Non-Peak Month'),
    dcc.Dropdown(
        id='datasource-2',
        options=[
            {'label': i, 'value': i} for i in ['Peak Month','Non Peak Month']
        ]

    ),   
    html.Hr(),
    html.Div('Select Peak/Non Peak Hour and Threshold Delay'),
    html.Div(
        id='controls-container'
    ),
    html.Hr(),
    html.Div('Output'),
    html.Div(
        id='output-container'
    )
])

def generate_control_id(value):
    return 'Control {}'.format(value)

DYNAMIC_CONTROLS = {
    'Low Delay Airlines (6E, UK)': dcc.Dropdown(
        id=generate_control_id('Low Delay Airlines (6E, UK)'),
        options=[{'label': '{}'.format(i), 'value': i} for i in list(price['Hour Peaks'][price['Airlines']=='Low Delay Airlines (6E, UK)'].unique())]
    ),
    'High Delay Airlines (9W,AI,SG,G8)': dcc.Dropdown(
        id=generate_control_id('High Delay Airlines (9W,AI,SG,G8)'),
        options=[{'label': '{}'.format(i), 'value': i} for i in list(price['Hour Peaks'][price['Airlines']=='High Delay Airlines (9W,AI,SG,G8)'].unique())]
    ),
    'Peak Month': dcc.Dropdown(
        id=generate_control_id('Peak Month'),
        options=[{'label': '{}'.format(i), 'value': i} for i in [60,90,120,150,180]]
    ),
    'Non Peak Month': dcc.Dropdown(
        id=generate_control_id('Non Peak Month'),
        options=[{'label': '{}'.format(i), 'value': i} for i in [60,90,120,150,180]]
    )
}

@app.callback(
    Output('controls-container', 'children'),
    [Input('datasource-1', 'value'),
     Input('datasource-2', 'value')])
def display_controls(datasource_1_value, datasource_2_value):
    # generate 2 dynamic controls based off of the datasource selections
    return html.Div([
        DYNAMIC_CONTROLS[datasource_1_value],
        DYNAMIC_CONTROLS[datasource_2_value],
    ])

def generate_output_id(value1, value2):
    return '{} {} container'.format(value1, value2)

@app.callback(
    Output('output-container', 'children'),
    [Input('datasource-1', 'value'),
     Input('datasource-2', 'value')])
def display_controls(datasource_1_value, datasource_2_value):
    # create a unique output container for each pair of dyanmic controls
    return html.Div(id=generate_output_id(
        datasource_1_value,
        datasource_2_value
    ))
def prem(a,b,c,d):
    return (price['Office Premium ( INR )'][(price['Hour Peaks']==a)&(price['Threshold Delay ( Min )']==b)&(price['Airlines']==c)&(price['Month Peaks']==d)])
def incidence(a,b,c,d):
    return (price['Incidence Rate (%)'][(price['Hour Peaks']==a)&(price['Threshold Delay ( Min )']==b)&(price['Airlines']==c)&(price['Month Peaks']==d)])

def generate_output_callback(datasource_1_value, datasource_2_value):
    def output_callback(control_1_value, control_2_value):
        # This function can display different outputs depending on
        # the values of the dynamic controls
        premium=prem(control_1_value,control_2_value,datasource_1_value,datasource_2_value)
        incidence_rate=incidence(control_1_value,control_2_value,datasource_1_value,datasource_2_value)
        return '''
            For the selected values, premium in INR is {} and incidence rate is {} %
        '''.format(
            list(premium)[0],
            list(incidence_rate)[0]
            )
    return output_callback

app.config.supress_callback_exceptions = True

# create a callback for all possible combinations of dynamic controls
# each unique dynamic control pairing is linked to a dynamic output component
for value1, value2 in itertools.product(
        [o['value'] for o in app.layout['datasource-1'].options],
        [o['value'] for o in app.layout['datasource-2'].options]):
    app.callback(
        Output(generate_output_id(value1, value2), 'children'),
        [Input(generate_control_id(value1), 'value'),
         Input(generate_control_id(value2), 'value')])(
        generate_output_callback(value1, value2)
    )

if __name__ == '__main__':
    application.run(port=8080)


The error is very clear, DYNAMIC_CONTROLS has no key None.

This code here is not catching on initial load that the Inputs could have a null value.

@app.callback(
    Output('controls-container', 'children'),
    [Input('datasource-1', 'value'),
     Input('datasource-2', 'value')])
def display_controls(datasource_1_value, datasource_2_value):
    # generate 2 dynamic controls based off of the datasource selections
    return html.Div([
        DYNAMIC_CONTROLS[datasource_1_value],
        DYNAMIC_CONTROLS[datasource_2_value],
    ])

Put some checks in the function, e.g.:

@app.callback(
    Output('controls-container', 'children'),
    [Input('datasource-1', 'value'),
     Input('datasource-2', 'value')])
def display_controls(datasource_1_value, datasource_2_value):
    if datasource_1_value is None or datasource_2_value is None:
         raise dash.exceptions.PreventUpdate

    # generate 2 dynamic controls based off of the datasource selections
    return html.Div([
        DYNAMIC_CONTROLS[datasource_1_value],
        DYNAMIC_CONTROLS[datasource_2_value],
    ])

I tried this. Although there are no logs error. It is still not working when I upload it on AWS.
What should I do ?

Ask a new question about deploying to AWS, explain what your setup is, and try and come up with a minimal set of code that produces the problem. Most people aren’t reading announcement threads to help solve problems.

I have this:

app.callback([
    Output('SeqR', 'children'),
    Output('Plat', 'children')],
    [Input('submit-button','n_clicks')],
    [State('ID_selector', 'value')])

def update_output(n_clicks, input_ID):

    if input_ID:
        seqR = "12312"
        plat = "12356"
        return html.Div(seqR), html.Div(plat)

But I get error when trying this code

@lcalcagni
could you post the error code

Consider yourself lucky that the solution to this has come out not too long ago: just put in dash.no_update on the output line for variables you want to leave unchanged.

2 Likes

Very useful!
Is it possible to return only one value and use this as the Output to multiple objects?

For example:
I have multiple dropdown menus to select which column of a data table should be used for what.
Like: Select the column of x values, select the column of y values etc.
These dropdown menus need to be updated when data is uploaded, and they of course should all have the same options.
So when I have a function that returns me the names of the columns like:

@app.callback([Output('classifier_choice', 'options'),
               Output('identifier_selector', 'options'),
               Output('timepoint_selector', 'options')],
              [Input('output-data-upload', 'children')])

def update_dropdown(contents):
    columns=df.columns
    print(columns)
    return [{'label' :k, 'value' :k} for k in columns].

Is it possible to use this return value for all the outputs?

This is truly a gamechanger, thank you!

you can just return that 4 times - ie a list of length 4, with that value as each element.

A post was split to a new topic: Multiple output when enable multiple select option in dropdown

A post was split to a new topic: Looking for help with multiple outputs

Hier is my function,with multiple output,why i receive a dash.exceptions.InvalidCallbackReturnValue??

data_dict = {‘lasso_selection’: }

@app.callback([
Output(‘graph’, ‘figure’),
Output(‘polygon_lan_lot-value’, ‘data’)],
[Input(‘graph’, ‘selectedData’)])
def display_data(selectedData):

if type(selectedData) is dict:
    if 'lassoPoints' in selectedData.keys():
        l = []           
        for i in range(len(selectedData["points"])):
            l.append(selectedData["points"][i]['lon'])
            data_set = pd.DataFrame(data=selectedData['lassoPoints']['mapbox'],
                                columns=['lon', 'lat'])           
      
        data_dict['lasso_selection'] = [data_set]
       

figure = {
    'data': [
        go.Scattermapbox(
            lat=[51.48165],
            lon=[7.21648],
            text='time',
            mode='markers',
            opacity=0.7,
            marker={
                'size': 10},
            name='Others'),

    ],
    'layout': go.Layout(
        autosize=False,
        width=1400,
        height=700,
        hovermode='closest',
        dragmode='zoom',

        mapbox=dict(
            style='basic',
            accesstoken=mapbox_access_token,
            bearing=0,
            center=dict(
                lat=51.48165,
                lon=7.21648
            ),
            zoom=13
        ), )}
return figure, data_dict