To get the most out of this page, make sure you’ve read about Basic Callbacks in the Dash Tutorial.
New in Dash 1.11.0! (requires dash-renderer 1.4.0 or greater)
The pattern-matching callback selectors MATCH
, ALL
, & ALLSMALLER
allow you to write callbacks that respond to or update an arbitrary or dynamic number of components.
ALL
This example renders an arbitrary number of dcc.Dropdown
elements and the callback is fired whenever any of the dcc.Dropdown
elements change. Try adding a few dropdowns and selecting their values to see how the app updates.
from dash import Dash, dcc, html, Input, Output, State, MATCH, ALL
app = Dash(__name__, suppress_callback_exceptions=True)
app.layout = html.Div([
html.Button("Add Filter", id="add-filter", n_clicks=0),
html.Div(id='dropdown-container', children=[]),
html.Div(id='dropdown-container-output')
])
@app.callback(
Output('dropdown-container', 'children'),
Input('add-filter', 'n_clicks'),
State('dropdown-container', 'children'))
def display_dropdowns(n_clicks, children):
new_dropdown = dcc.Dropdown(
['NYC', 'MTL', 'LA', 'TOKYO'],
id={
'type': 'filter-dropdown',
'index': n_clicks
}
)
children.append(new_dropdown)
return children
@app.callback(
Output('dropdown-container-output', 'children'),
Input({'type': 'filter-dropdown', 'index': ALL}, 'value')
)
def display_output(values):
return html.Div([
html.Div('Dropdown {} = {}'.format(i + 1, value))
for (i, value) in enumerate(values)
])
if __name__ == '__main__':
app.run_server(debug=True)
Some notes about this example:
- Notice how the id
in dcc.Dropdown
is a dictionary rather than a string.
This is a new feature that we enabled for pattern-matching callbacks (previously, IDs had to be strings).
- In our second callback, we have Input({'type': 'filter-dropdown', 'index': ALL}, 'value')
. This means “match any input that has an ID dictionary where 'type'
is 'filter-dropdown'
and 'index'
is anything. Whenever the value
property of any of the dropdowns change, send all of their values to the callback.”
- The keys & values of the ID dictionary (type
, index
, filter-dropdown
) are arbitrary. This could’ve be named {'foo': 'bar', 'baz': n_clicks}
.
- However, for readability, we recommend using keys like type
, index
, or id
. type
can be used to refer to the class or set dynamic components and
index
or id
could be used to refer which component you are matching within that set. In this example, we just have a single set of dynamic
components but you may have multiple sets of dynamic components in more complex apps or if you are using MATCH
(see below).
- In fact, in this example, we didn’t actually need 'type': 'filter-dropdown'
. The same callback would have worked with Input({'index': ALL}, 'value')
.
We included 'type': 'filter-dropdown'
as an extra specifier in case you create multiple sets of dynamic components.
- The component properties themselves (e.g. value
) cannot be matched by a pattern, only the IDs are dynamic.
- This example uses a common pattern with State
- the currently displayed set of dropdowns within the dropdown-container
component are passed into
the callback when the button is clicked. Within the callback, the new dropdown is appended to the list and then returned.
- You can also use dash.callback_context
to access the inputs and state and to know which input changed.
Here is what that data might look like with two dropdowns rendered on the page.
dash.callback_context.triggered_prop_ids
(available from Dash 2.4) returns a dictionary of inputs that triggered the callback. Each key is a <component_id>.<component_property>
and the corresponding value is the <component_id>
. In this example, we can see that the id of the component that triggered the callback was {'index': 0, 'type': 'filter-dropdown'}
and the property was value
:
{
'{"index":0,"type":"filter-dropdown"}.value': {
"index": 0,
"type": "filter-dropdown"}
}
dash.callback_context.triggered
. Note that the prop_id
is a stringified dictionary with no whitespace.
python
[
{
'prop_id': '{"index":0,"type":"filter-dropdown"}.value',
'value': 'NYC'
}
]
dash.callback_context.inputs
. Note that the key is a stringified dictionary with no whitespace.
python
{
'{"index":0,"type":"filter-dropdown"}.value': 'NYC',
'{"index":1,"type":"filter-dropdown"}.value': 'LA'
}
dash.callback_context.inputs_list
. Each element of the list corresponds to
one of the input declarations. If one of the input declarations matches a
pattern then it will contain a list of values.
python
[
[
{
'id': {
'index': 0,
'type': 'filter-dropdown'
},
'property': 'value',
'value': 'NYC'
},
{
'id': {
'index': 1,
'type': 'filter-dropdown'
},
'property': 'value',
'value': 'LA'
}
]
]
dash.callback_context.outputs_list
python
{
'id': 'dropdown-container-output',
'property': 'children'
}
MATCH
Like ALL
, MATCH
will fire the callback when any of the component’s properties change. However, instead of passing all of the values into the callback, MATCH
will pass just a single value into the callback. Instead of updating a single output, it will update the dynamic output that is “matched” with.
from dash import Dash, dcc, html, Input, Output, State, MATCH, ALL
app = Dash(__name__, suppress_callback_exceptions=True)
app.layout = html.Div([
html.Button("Add Filter", id="dynamic-add-filter", n_clicks=0),
html.Div(id='dynamic-dropdown-container', children=[]),
])
@app.callback(
Output('dynamic-dropdown-container', 'children'),
Input('dynamic-add-filter', 'n_clicks'),
State('dynamic-dropdown-container', 'children'))
def display_dropdowns(n_clicks, children):
new_element = html.Div([
dcc.Dropdown(
['NYC', 'MTL', 'LA', 'TOKYO'],
id={
'type': 'dynamic-dropdown',
'index': n_clicks
}
),
html.Div(
id={
'type': 'dynamic-output',
'index': n_clicks
}
)
])
children.append(new_element)
return children
@app.callback(
Output({'type': 'dynamic-output', 'index': MATCH}, 'children'),
Input({'type': 'dynamic-dropdown', 'index': MATCH}, 'value'),
State({'type': 'dynamic-dropdown', 'index': MATCH}, 'id'),
)
def display_output(value, id):
return html.Div('Dropdown {} = {}'.format(id['index'], value))
if __name__ == '__main__':
app.run_server(debug=True)
Notes about this example:
- The display_dropdowns
callback returns two elements with the same index
: a dropdown and a div.
- The second callback uses the MATCH
selector. With this selector, we’re asking Dash to:
value
property of any component with the id 'type': 'dynamic-dropdown'
changes:Input({'type': 'dynamic-dropdown', 'index': MATCH}, 'value')
'type': 'dynamic-output'
and the index
that matches the same index
of the input:Output({'type': 'dynamic-output', 'index': MATCH}, 'children')
id
of the dropdown into the callback:State({'type': 'dynamic-dropdown', 'index': MATCH}, 'id')
MATCH
selector, only a single value is passed into the callback for each Input
or State
. This is unlike the previous example with theALL
selector where Dash passed all of the values into the callback.MATCH
contract is that Dash will update whichever output has the same dynamic ID as the id. In this case, the “dynamic ID” is the value of the index
and we’ve designed our layout to return dropdowns & divs with identical values of index
.id
as State
in the callback.dash.callback_context
to access the inputs and state and to know which input changed. outputs_list
is particularly useful withMATCH
because it can tell you which dynamic component this particular invocation of the callback is responsible for updating. Here is what that data might look like with two dropdowns rendered on the page after we change the first dropdown.dash.callback_context.triggered_prop_ids
(available from Dash 2.4) returns a dictionary of inputs that triggered the callback. Each key is a <component_id>.<component_property>
and the corresponding value is the <component_id>
. In this example, we can see that the id of the component that triggered the callback was {'index': 0, 'type': 'dynamic-dropdown'}
and the property was value
:{
'{"index":0,"type":"dynamic-dropdown"}.value': {
"index": 0,
"type": "dynamic-dropdown",
}
}
dash.callback_context.triggered
. Note that the prop_id
is a stringified dictionary with no whitespace.
python
[
{
'prop_id': '{"index":0,"type":"dynamic-dropdown"}.value',
'value': 'NYC'
}
]
dash.callback_context.inputs
. Note that the key is a stringified dictionary with no whitespace.
python
{
'{"index":0,"type":"dynamic-dropdown"}.value': 'NYC'
}
dash.callback_context.inputs_list
. Each element of the list corresponds to one of the input declarations. If one of the input declarations matches a pattern then it will contain a list of values.
python
[
[
{
'id': {
'index': 0,
'type': 'dynamic-dropdown'
},
'property': 'value',
'value': 'NYC'
}
]
]
dash.callback_context.outputs_list
python
{
'id': {
'index': 0,
'type': dynamic-output'
},
'property': 'children'
}
ALLSMALLER
In the example below, ALLSMALLER
is used to pass in the values of all of the dropdowns on the page that have an index smaller than the index corresponding to the div.
The user interface in the example below displays filter results that are increasingly specific in each as we apply each additional dropdown.
ALLSMALLER
can only be used in Input
and State
items, and must be used on a key that has MATCH
in the Output
item(s).
ALLSMALLER
it isn’t always necessary (you can usually use ALL
and filter out the indices in your callback) but it will make your logic simpler.
from dash import Dash, dcc, html, Input, Output, State, MATCH, ALL, ALLSMALLER
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
app = Dash(__name__, suppress_callback_exceptions=True)
app.layout = html.Div([
html.Button('Add Filter', id='add-filter-ex3', n_clicks=0),
html.Div(id='container-ex3', children=[]),
])
@app.callback(
Output('container-ex3', 'children'),
Input('add-filter-ex3', 'n_clicks'),
State('container-ex3', 'children'))
def display_dropdowns(n_clicks, existing_children):
existing_children.append(html.Div([
dcc.Dropdown(
df['country'].unique(),
df['country'].unique()[n_clicks],
id={
'type': 'filter-dropdown-ex3',
'index': n_clicks
}
),
html.Div(id={
'type': 'output-ex3',
'index': n_clicks
})
]))
return existing_children
@app.callback(
Output({'type': 'output-ex3', 'index': MATCH}, 'children'),
Input({'type': 'filter-dropdown-ex3', 'index': MATCH}, 'value'),
Input({'type': 'filter-dropdown-ex3', 'index': ALLSMALLER}, 'value'),
)
def display_output(matching_value, previous_values):
previous_values_in_reversed_order = previous_values[::-1]
all_values = [matching_value] + previous_values_in_reversed_order
dff = df[df['country'].str.contains('|'.join(all_values))]
avgLifeExp = dff['lifeExp'].mean()
# Return a slightly different string depending on number of values
if len(all_values) == 1:
return html.Div('{:.2f} is the life expectancy of {}'.format(
avgLifeExp, matching_value
))
elif len(all_values) == 2:
return html.Div('{:.2f} is the average life expectancy of {}'.format(
avgLifeExp, ' and '.join(all_values)
))
else:
return html.Div('{:.2f} is the average life expectancy of {}, and {}'.format(
avgLifeExp, ', '.join(all_values[:-1]), all_values[-1]
))
if __name__ == '__main__':
app.run_server(debug=True)
html.Div
that has an index that depends on that dropdown.html.Div
will get updated whenever any of the dropdowns with an index
smaller than it has changed.html.Div
that dependsdcc.Dropdown
that changed.As above, you can also use dash.callback_context
to access the inputs and state and to know which input changed. Here is what that data might look like when updating the second div with two dropdowns rendered on the page after we change the first dropdown.
dash.callback_context.triggered_prop_ids
(available from Dash 2.4) returns a dictionary of inputs that triggered the callback. Each key is a <component_id>.<component_property>
and the corresponding value is the <component_id>
. In this example, we can see that the id of the component that triggered the callback was {'index': 0, 'type': 'filter-dropdown-ex3'}
and the property was value
:
```
{
‘{“index”:0,”type”:”filter-dropdown-ex3”}.value’: {
“index”: 0,
“type”: “filter-dropdown-ex3”,
}
}
```
dash.callback_context.triggered
. Note that the prop_id
is a stringified dictionary with no whitespace.
python
[
{
'prop_id': '{"index":0,"type":"filter-dropdown-ex3"}.value',
'value': 'Canada'
}
]
dash.callback_context.inputs
. Note that the key is a stringified dictionary with no whitespace.python
{
'{"index":1,"type":"filter-dropdown-ex3"}.value': 'Albania',
'{"index":0,"type":"filter-dropdown-ex3"}.value': 'Canada'
}
dash.callback_context.inputs_list
. Each element of the list corresponds topython
[
{
'id': {
'index': 1,
'type': 'filter-dropdown-ex3'
},
'property': 'value',
'value': 'Albania'
},
[
{
'id': {
'index': 0,
'type': 'filter-dropdown-ex3'
},
'property': 'value',
'value': 'Canada'
}
]
]
dash.callback_context.outputs_list
python
{
'id': {
'index': 1,
'type': output-ex3'
},
'property': 'children'
}
Creating a Todo App is a classic UI exercise in that demonstrates many features in common “create, read, update and delete” (CRUD) applications.
import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State, MATCH, ALL
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div('Dash To-Do list'),
dcc.Input(id="new-item"),
html.Button("Add", id="add"),
html.Button("Clear Done", id="clear-done"),
html.Div(id="list-container"),
html.Div(id="totals")
])
style_todo = {"display": "inline", "margin": "10px"}
style_done = {"textDecoration": "line-through", "color": "#888"}
style_done.update(style_todo)
@app.callback(
[
Output("list-container", "children"),
Output("new-item", "value")
],
[
Input("add", "n_clicks"),
Input("new-item", "n_submit"),
Input("clear-done", "n_clicks")
],
[
State("new-item", "value"),
State({"index": ALL}, "children"),
State({"index": ALL, "type": "done"}, "value")
]
)
def edit_list(add, add2, clear, new_item, items, items_done):
triggered = [t["prop_id"] for t in dash.callback_context.triggered]
adding = len([1 for i in triggered if i in ("add.n_clicks", "new-item.n_submit")])
clearing = len([1 for i in triggered if i == "clear-done.n_clicks"])
new_spec = [
(text, done) for text, done in zip(items, items_done)
if not (clearing and done)
]
if adding:
new_spec.append((new_item, []))
new_list = [
html.Div([
dcc.Checklist(
id={"index": i, "type": "done"},
options=[{"label": "", "value": "done"}],
value=done,
style={"display": "inline"},
labelStyle={"display": "inline"}
),
html.Div(text, id={"index": i}, style=style_done if done else style_todo)
], style={"clear": "both"})
for i, (text, done) in enumerate(new_spec)
]
return [new_list, "" if adding else new_item]
@app.callback(
Output({"index": MATCH}, "style"),
Input({"index": MATCH, "type": "done"}, "value")
)
def mark_done(done):
return style_done if done else style_todo
@app.callback(
Output("totals", "children"),
Input({"index": ALL, "type": "done"}, "value")
)
def show_totals(done):
count_all = len(done)
count_done = len([d for d in done if d])
result = "{} of {} items completed".format(count_done, count_all)
if count_all:
result += " - {}%".format(int(100 * count_done / count_all))
return result
if __name__ == "__main__":
app.run_server(debug=True)
Pattern-matching callbacks are useful when building reusable components. See the All-in-One components chapter for more information.