0

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`.
2
  • So what is wrong with the first code snippet? Seems all right to me. Commented Feb 24, 2021 at 6:53
  • @pavel it works fine but it gets clunky when I have to add a lot of graphs. I'm looking for a cleaner, more efficient way of plotting multiple graphs. Commented Feb 24, 2021 at 8:26

1 Answer 1

2

You've left out some implementation details in your question so I will give more general examples here to highlight an approach you could take.


An idea is to dynamically create lists of elements based on your keys something like this:

graphs_from_keys = [dcc.Graph(id=key) for key in keys]
outputs_from_keys = [Output(key, "figure") for key in keys]
figures_from_keys = [px.histogram(df, x=key, nbins=20) for key in keys]

This allows us to pass each graph in the graphs_from_keys list to the layout like this:

app.layout = html.Div(
    [
        html.H3("Plots"),
        *graphs_from_keys,
        # ...
    ]
)

and then the callback could look something like this:

@app.callback(
    outputs_from_keys,
    [Input('filtered-data-hidden', 'children')],
)
def plot_data(df):
    # ...
    return figures_from_keys
Sign up to request clarification or add additional context in comments.

1 Comment

seems straightforward and simple enough, thank you! I would just like to note that there is another solution involving pattern matching callbacks, if anyone else looking at this and is interested in learning about it. dash.plotly.com/pattern-matching-callbacks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.