Output a graph and table from a single dash callback

Question:

I would like to generate a graph and table from a dash callback, but the code outputs one or the other.

Below is the final part of the code. The data is filtered by chained callbacks (two drop-downs – LGA and SMA) and a radio button (standard deviation picker).

Is there a simple way to generate the two outputs or do I need to add in another callback and define additional functions?

html.Div(
    id='graph-container', 
     children=[]),


dash_table.DataTable(
    id='table-container',
    columns = [{"name": i, "id": i} for i in df],
    data=df.to_dict('records'),
        ),
])

Populate the SMA’s dropdown with options and values

   @app.callback(
     Output('SMA-dpdn', 'options'),
     Output('SMA-dpdn', 'value'),
     Input('LGA-dpdn', 'value'),

)
def set_LGA_options(chosen_LGA):
    dff = df[df.LGA==chosen_LGA]
    SMAs_of_LGAs = [{'label': c, 'value': c} for c in sorted(dff.SMA.unique())]
    values_selected = [x['value'] for x in  SMAs_of_LGAs]
    return  SMAs_of_LGAs, values_selected

@app.callback(
    Output('graph-container', 'children'),
    Output('table-container', 'data'),
    Input('radio_items', 'value'),   
    Input('SMA-dpdn', 'value'), 
    Input('LGA-dpdn', 'value'),

    prevent_initial_call=True
 )

Create graph/table component and populate

 def graph(max_deviations, selected_SMA, selected_LGA):

    if len(selected_SMA) == 0:
        return dash.no_update
    else: 
        dff = df[(df.LGA==selected_LGA) & (df.SMA.isin(selected_SMA))]
        data = pd.DataFrame(data=dff)
        x = dff.TIME
        y = dff.CHANGE
        mean = np.mean(y)
        standard_deviation = np.std(y)
        distance_from_mean = abs(y - mean)
        not_outlier = distance_from_mean < max_deviations * standard_deviation
        no_outliers = y[not_outlier]
        trim_outliers = pd.DataFrame(data=no_outliers)
        dfd = pd.merge(trim_outliers, dff, left_index=True, right_index=True)
        dfd['CHANGE'] = dfd['CHANGE_x']

      fig = px.scatter(dfd, x='TIME', y='CHANGE', color ='SMA', trendline='ols', size='PV', height=500, width=800, hover_name='SMA')    
   
      return dfd.to_dict('records')

      return dcc.Graph(id='display-map', figure=fig)


 if __name__ == '__main__':
     app.run_server(debug=False)
Asked By: Colin Clark

||

Answers:

Your have correctly defined two Outputs on your callback, but then you are only returning a single value which is incorrect.

The code below is your example stripped down and demonstrates the correct way to return multiple values. I have also switched the no_update logic around to demonstrate a cleaner way to structure the code which reduces the risk of introducing a bug on return:

@app.callback(
    Output('graph-container', 'children'),
    Output('table-container', 'data'),
    Input('radio_items', 'value'),   
    Input('SMA-dpdn', 'value'), 
    Input('LGA-dpdn', 'value'),

    prevent_initial_call=True
 )
def graph(max_deviations, selected_SMA, selected_LGA):
    if len(selected_SMA) > 0: 
        # Do processing to create a dfd record and the figure for the Graph
        return dcc.Graph(id='display-map', figure=fig), dfd.to_dict('records')

    # No update if length was zero.
    return dash.no_update, dash.no_update
Answered By: Ian Ash
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.