A component/property pair can only be the Output
of one callback. A component property pair means the id
of the component and the property
. In this html.H1
component, it’s 'app-heading', 'children'
:
html.H1(children='Analytics app', id='app-heading')
If you add 'app-heading', 'children'
as an Output
on two callbacks in your app you’ll get a “Duplicate callback outputs” error when running in debug mode.
<img>
This is a complete example demonstrating an app that throws a “Duplicate callback outputs” error. Here we have two html.Button
components and a dcc.Graph
component in our app.layout
:
app.layout = html.Div([
html.Button('Draw Graph', id='draw'),
html.Button('Reset Graph', id='reset'),
dcc.Graph(id='our-graph')
])
If we try to update the graph component’s ('our-graph'
) 'fig'
property differently depending on which button is clicked, we cannot do this by adding 'our-graph'
, 'fig'
as an Output
on two callbacks:
@app.callback(
Output('our-graph', 'figure'),
Input('draw', 'n_clicks'),
prevent_initial_call=True
)
def draw_graph(_):
df = px.data.iris()
return px.scatter(df, x=df.columns[0], y=df.columns[1])
@app.callback(
Output('our-graph', 'figure'),
Input('reset', 'n_clicks'),
prevent_initial_call=True
)
def reset_graph(_):
return go.Figure()
We can update our graph in the above example differently based on the inputs by combining the inputs into one callback and using dash.callback_context
to determine which input triggered the callback.
Here is the same example rewritten. Our new callback has the two inputs. It gets the ID of the component that triggered the callback using ctx.triggered_id
. This will return either draw
or reset
. If it is draw
, the callback returns draw_graph()
. If it is reset
it returns reset_graph()
:
from dash import Dash, Input, Output, ctx, html, dcc
import plotly.express as px
import plotly.graph_objects as go
app = Dash(__name__)
app.layout = html.Div([
html.Button('Draw Graph', id='draw'),
html.Button('Reset Graph', id='reset'),
dcc.Graph(id='graph')
])
@app.callback(
Output('graph', 'figure'),
Input('reset', 'n_clicks'),
Input('draw', 'n_clicks'),
prevent_initial_call=True
)
def update_graph(b1, b2):
triggered_id = ctx.triggered_id
print(triggered_id)
if triggered_id == 'reset':
return reset_graph()
elif triggered_id == 'draw':
return draw_graph()
def draw_graph():
df = px.data.iris()
return px.scatter(df, x=df.columns[0], y=df.columns[1])
def reset_graph():
return go.Figure()
app.run_server(debug=True)
See Determining Which Callback Input Changed for more on dash.callback_context
and understanding which input triggered a callback.