Callback output array of graphs to a single Div in layout?

I’d like to create multiple similar histograms in my Dash layout with a single callback output to a single div instead of repetitively copying and pasting code. Below is an example of my current code:

# In app.layout
html.Div([
    html.H3('Plots'),
    html.Div(dcc.Graph(id='A')),
    html.Div(dcc.Graph(id='B')),
    html.Div(dcc.Graph(id='C'))
])

# Callback
@app.callback(
    [Output('A', 'figure'),
     Output('B', 'figure'),
     Output('C', 'figure')]
    [Input('filtered-data-hidden', 'children')]
)
def plot_data(df):
    dff = pd.read_json(df, orient='split')
    figure_a = px.histogram(dff, x="A", nbins=20)
    figure_b = px.histogram(dff, x="B", nbins=20)
    figure_c = px.histogram(dff, x="C", nbins=20)
    return figure_a, figure_b, figure_c

I tried the following:

# In app.layout
html.Div([
    html.H3('Plots'),
    html.Div(dcc.Graph(id='figures'))
])

# Callback
@app.callback(
    Output('figures', 'figure'),
    [Input('filtered-data-hidden', 'children')]
)
def plot_data(df):
    dff = pd.read_json(df, orient='split')
    figures = []
    for feature in FEATURES.keys():
        figures.append(px.histogram(dff, x=features, nbins=20))
    return figures

But got an error:

Invalid argument `figure` passed into Graph with ID "figures".
Expected `object`.
Was supplied type `array`.

Hi @jko0401
The figures id belongs to dcc.graph, which means it’s expecting one figure or an object, not a list of figures that you’re feeding it.

1 Like

I understand that. I was hoping to convey my intention and what I want to achieve. What is the correct syntax for passing a bunch of plotly express graphs to a single div in layout? Is it possible?

Solution #1: Create a bunch of dcc.Graph and output into a div

# In app.layout
html.Div([
    html.H3('Plots'),
    html.Div(id='div-figures')
])

# Callback
@app.callback(
    Output('div-figures', 'children'),
    [Input('filtered-data-hidden', 'children')]
)
def plot_data(df):
    dff = pd.read_json(df, orient='split')
    figures = []
    for feature in FEATURES.keys():
        figures.append(dcc.Graph(figure=px.histogram(dff, x=features, nbins=20)))
    return figures

Solution #2: Pattern matching callbacks

from dash.dependencies import Input, Output, ALL
# In app.layout
html.Div([
    html.H3('Plots'),
    html.Div([
        dcc.Graph(id={"index": i, "name": "graph"})
        for i in range(len(FEATURES))
    ])
])

# Callback
@app.callback(
    Output({"name": "graph", "index": ALL}, 'figure'),
    [Input('filtered-data-hidden', 'children')]
)
def plot_data(df):
    dff = pd.read_json(df, orient='split')
    figures = []
    for feature in FEATURES.keys():
        figures.append(px.histogram(dff, x=features, nbins=20))
    return figures

I haven’t tested the code but it should follow the general pattern for this type of I/Os.

1 Like

solution 1 is straightforward and easy to understand. I never knew about pattern matching callbacks so thank you for introducing and providing it as a solution as well!

1 Like

@xhlu @jko0401
can you please explain to me where FEATURES is coming from. What is that object?

It is a dictionary that is imported separately that matches the values to labels to display in dropdowns and graphs.