Pattern-Matching Callbacks in Dash
Tags: share it with the community, Open Source, Machine Learning, Data Visualization, Python

A Todo app made with Dash’s Pattern-Matching Callbacks

Written by: Alex Johnson, Plotly CTO

Before we start, I’d like to thank codefour for generously sponsoring this open-source feature and providing excellent feedback throughout its development. Collaborating with talented teams like codefour is one of the most rewarding parts of my job as Plotly’s CTO. Cornerstone, open-source features like Pattern-Matching Callbacks will ultimately be used by 100’s of millions of Dash applications editors and viewers — so these collaborations are special. If you’d like to discuss your idea for accelerating Dash’s open-source roadmap, please get in touch.

Now let’s dive in.

Dash is a rich, customizable, and dynamic framework for building browser-based analytics apps in Python, R, and Julia. From the moment we introduced it, our users have been making apps that not only display information but also interact, explore, edit, annotate, and let each user create their own view. Our newest release, Dash v1.11, takes this to a whole new level with a feature we’re calling Pattern-Matching Callbacks.

Dash already allows you to change the contents of the page dynamically. This is used extensively in the Dash Docs — the hundreds of pages of content we use to document Dash are just one big Dash app, loading different content depending on the links you visit. But, complex apps like this had a significant limitation: any given callback needed to know exactly which inputs and outputs it connected to ahead of time, and every callback needed to have either all or none of its inputs and outputs on the page at any given time.

A while back, I reviewed all of the web apps I worked on before Plotly, asking the question of whether or not they could have been made in Dash. These were data-heavy applications for industries like materials engineering, manufacturing, or geological prospecting. Technicians used these apps to enter data and record events in the lab. Engineers, scientists, and managers used different parts of the apps to analyze the results and plan the next steps. In most cases, I concluded that Dash would be able to perform, as it was both far quicker to write and more interactive than the one-off web development we were doing at the time. But, for the ones that Dash would have struggled with, the universal blocker was dynamically adding sections to the page and still needing them to interact with each other.

Dash’s new Pattern-Matching Callbacks solve this problem.

A callback can now connect an arbitrary collection of components, determined by a pattern of wildcard selectors within the ID field of the Input, Output, and State objects.

Here are some situations where Pattern-Matching Callbacks save the day:

Do you want 5 (or 10, or 20) dropdown selectors, each one updating its own output field like a graph? With Pattern-Matching Callbacks, that’s now just one callback function, with MATCH wildcards connecting each dropdown just to its own output.

wildcards connecting each dropdown just to its own output. How about having each dropdown’s options depend on the values of all the previous dropdowns, like a filtering UI that becomes progressively more specific? With Pattern-Matching Callbacks, that’s now also a single callback, using the ALLSMALLER wildcard.

wildcard. What about combining all of these choices into one final output? One more callback will do it, using the ALL wildcard.

wildcard. What if you could let your users add or remove items depending on their needs? Pattern-Matching Callbacks adapt to whatever changes you make to the components on the page.

Pattern-Matching Callbacks let you write complex Dash apps with minimal code.

To enable Pattern-Matching Callbacks, we added just a few pieces to the Dash interface: component IDs can now be dictionaries as well as strings; and callback definitions can match patterns in these dictionary IDs, using the MATCH , ALL , and ALLSMALLER wildcards in place of the explicit values used in the component IDs.

As an example, say you create two inputs:

dcc.Input(id={'role': 'name', 'index': 0})

dcc.Input(id={'role': 'name', 'index': 1})

Along with these inputs you make two outputs:

html.Div(id={'role': 'response', 'index': 0})

html.Div(id={'role': 'response', 'index': 1})

You can make Pattern-Matching Callbacks with MATCH in the index field:

@app.callback(

Output({'role': 'response', 'index': MATCH}, 'children'),

[Input('role': 'name', 'index': MATCH}, 'value')]

)

def response(name):

return 'Hello ' + name

This function will be called when name 0 changes, its return value used for response 0; the same function is called when name 1 changes, but now its return value is used for response 1.

Now, you can combine all the inputs in a single callback with ALL :

@app.callback(

Output('final', 'children'),

[Input({'role': 'name', 'index': ALL}, 'value')]

)

def final(names):

return 'Today I met ' + ', '.join(names)

Here’s an example of a dynamic Dash app that is now possible to build with Patten-Matching Callbacks:

A dynamic Dash app example that is now possible to build with Patten-Matching Callbacks.

In the app above, filters and charts can be dynamically added to the page with the “Add Filter” and “Add Graph” buttons. With Pattern-Matching Callbacks, the progressive display of filter results (e.g. “683 records”) would be described with an ALLSMALLER callback. The dynamic collection of graphs would be updated by their associated controls with a MATCH callback. The filters would update the data for all of the charts with an ALL callback.

That’s just a taste of what you can do. For full documentation, including complete examples, ALLSMALLER , and tips about how to know which inputs or outputs are which, head on over to our Dash site.

We can’t wait to see what you’ll make! If you use Pattern-Matching Callbacks to create something, share it with the community. ✨

Pattern-Matching Callbacks was a sponsored feature. If you have an idea for an open-source Dash feature that your company could sponsor, please get in touch.