Update : version 2.7.0 has been released since this was posted.
We’re excited to announce that Dash 2.6.0 & 2.6.1 have been released 2.6.1 contains a small bug fix for one of the features in 2.6.0. These are a backwards compatible releases and we recommend going straight to
2.6.1
.
pip install dash==2.6.1
Official Changelog Dash v2.6.0 and Dash v2.6.1
Highlights 
Background Callbacks
Background Callbacks are a rewrite of the
long_callback
feature launched in Dash 2.0. To preserve backwards compatibility withlong_callback
, we updated the syntax tocallback(..., background=True)
. If your app already useslong_callback
then you don’t need to change anything.background=True
resolves several outstanding limitations oflong_callback
including incompatibility with pattern-matching callbacks. Many thanks to everybody’s feedback on this!
Background callbacks run your callbacks in a background queue, enabling your apps to scale to more concurrent users and preventing your apps from running into network timeout issues.
Consider an app that has a callback that takes 10 seconds to run. Every time that callback is fired, a worker (CPU) is allocated to crunch the numbers. If your app is deployed with 4 CPU workers and if 4 people visit your app and execute the same callback at the same time, your app will have no more workers to serve the 5th app visitor. As a result, the 5th visitor will see a blank page for up to 10 seconds until the first worker becomes available.
Background callbacks offer a scalable solution for using long-running callbacks by running them in a separate background queue. In the background queue, the callbacks are executed one-by-one in the order that they came in by dedicated queue worker(s). The web workers remain available to load the dash app, return results of the background callback, and run non-background callbacks.
To run a callback in the background, set background=True
inside your callback decorator and pass a background callback manager
to the dash.Dash
app constructor.
app.py
import time
import dash
from dash import DiskcacheManager, CeleryManager, Input, Output, html
import os
if 'REDIS_URL' in os.environ:
# Use Redis & Celery if REDIS_URL set as an env variable
from celery import Celery
celery_app = Celery(__name__, broker=os.environ['REDIS_URL'], backend=os.environ['REDIS_URL'])
background_callback_manager = CeleryManager(celery_app)
else:
# Diskcache for non-production apps when developing locally
import diskcache
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)
app = dash.Dash(__name__, background_callback_manager=background_callback_manager)
app.layout = html.Div([
html.Div([html.P(id="paragraph_id", children=["Button not clicked"])]),
html.Button(id="button_id", children="Run Job!"),
])
@dash.callback(
output=Output("paragraph_id", "children"),
inputs=Input("button_id", "n_clicks"),
background=True,
)
def update_clicks(n_clicks):
time.sleep(2.0)
return [f"Clicked {n_clicks} times"]
if __name__ == "__main__":
app.run_server(debug=True)
Background callbacks leverage the open source Celery library and the open source Redis database under the hood. In Dash, we’ve abstracted away the complexity of stitching together these technologies into the simple background=True
API
Deploying Apps with Background Callbacks
To deploy an app with background callbacks, you’ll need:
- A deployment platform that can run two commands:
gunicorn app:server --workers 4
- For running the Dash app and “regular” callbacks. In this case, 4 CPU are serving these requests.celery app:server --concurrency=2
- For running the background job workers. In this case, 2 CPU will be running the background callbacks in the order that they are submitted.
- A Redis database available with network access available to both of those commands. Dash will submit and read jobs to and from Redis.
If you’re using Dash Enterprise (or Heroku), then run these two commands by creating a Procfile
with the commands:
web: gunicorn app:server --workers 4
queue: celery app:server --concurrency=2
and add Redis to your app and workspace development environment by clicking the “Add Redis” button in the UI:
DiskCache in Development
If you don’t have Redis available in your local development or testing environment, then you can use Dash’s DiskCache
manager instead of Redis. This manager won’t actually run the callbacks in a queue but it will enable you to use the background=True
syntax for development.
If you’re using Dash Enterprise, then Redis is available for development within a Dash Enterprise workspace.
Progress Bar & Start/Stop Buttons
Background callbacks provide some additional features to callbacks like progress bars that can be updated programmatically (instead of the generic dcc.Loading
component) and start/stop/disabled buttons.
Caching
Additionally, background callbacks provide a cache_by
argument to store the results of the background callback and return it immediately upon subsequent calls:
callback(..., background=True, cache_by=True)
Docs
Deep dive into Background Callbacks with myself & @chriddyp
Dropdown Search & Height
Search
The new search
keyword can be used to provide richer results in the dcc.Dropdown
. @prokie, thank you for reporting the bug that led us to create this new feature
In Dash v2.5.0 we introduced components as option labels. By default, the value
will be used when a user would search for a dropdown option.
With Dash v2.6, you can assign a string to the search
keyword for each option. For example, in the first option, the search string is equal to the label (“Montreal”), and in the second option the search string (“The Big Apple”) is completely different from the value and label .
dcc.Dropdown([
{
"label": html.Div(['Montreal']),
"value": "MTL",
"search": "Montreal"
},
{
"label": html.Div(['New York City']),
"value": "NYC",
"search": "The Big Apple"
}
],
value='Montreal'
)
Max Height
We’ve added the maxHeight
prop for the Dropdown
options menu. Thank you @AnnMarieW
Prior to Dash v2.6, the dropdown options would automatically display inside a vertical scrollbar if you had more than 6 options since the default height of the dropdown menu is 200px.
Now, you can assign an integer (representing pixels) to the new maxHeight
prop to show a larger number of select options, without any vertical scroll bar appearing. For example, let’s make the options area 800px instead of the default 200px.
from dash import Dash, html, dcc
import plotly.express as px
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(
[
'Option-1', 'Option-2', 'Option-3', 'Option-4', 'Option-5', 'Option-6', 'Option-7', 'Option-8', 'Option-9'
],
value='Option-2',
maxHeight=800
)
])
if __name__ == "__main__":
app.run_server(debug=True)
Docs
Unit Testing of Callbacks
Testing is an essential component of production-grade software development. In Dash 2.6, we’ve made it easier for you to write unit tests of callbacks. Unit tests are used to test individual functions of your Dash app whereas end-to-end tests spin up a real browser session and click through the UI. Many robust software projects will have a combination of unit and end-to-end tests. Unit tests are easier to set up and quicker to run than end-to-end tests.
Unit testing in Dash now looks like:
app.py
# ...
@callback(Output('div', 'children'), Input('input', 'value'))
def update(value):
return f'You have entered {value}'
test.py
from app import update
def test_update_callback():
output = update('hello world')
assert output =='You have entered hello world'
and then run the test in your terminal with:
$ pytest
Docs
Persistent Selections
With Dash 2.6.0, we’ve made two improvements to the Box Select and Lasso Select tools in the mode bar:
Persistent Selections: Previously, the selection outline would disappear after you’ve made the selection. Now the selection box or lasso will persist. This makes it easier to view the currently selected region and adjust the selection.
Pre-select: Selections can be added to a dcc.Graph
that displays to the app user when it loads. These can also be moved or resized.
In the example below, we use add_selection
to pre-populate a rectangle type="rect"
within a set of points on the graph:
from dash import Dash, dcc, html
import plotly.express as px
app = Dash(__name__)
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color='petal_length')
fig.add_selection(type="rect", x0=3.0, y0=6.5, x1=3.5, y1=5.5)
fig.update_layout(dragmode='select',
newselection=dict(line=dict(color='blue')))
app.layout = html.Div([
dcc.Graph(figure=fig)
])
if __name__ == '__main__':
app.run_server(debug=True)
In the example, we add the second Box selection by holding SHIFT + Left click
Docs
Plotly.py
The version of Plotly.js that is built in here is the same one that is bundled with the recently released Plotly.py 5.10.0, so we recommend that you upgrade to Plotly 5.10.0 to get the full benefit of all of these libraries working together.
pip install plotly==5.10.0
Official Changelog Plotly v5.10.0
Notable Bug Fixes & Minor Changes
- Update
dcc.Graph
to use Plotly.js to v2.13.3 (from v2.12.)- Fix
sankey
select error - Add unselected line styling to
parcoords
traces. - Add more quartile algorithms to
violin
traces. - More flexible axis
automargin
behavior. - And several other enhancements and bug fixes.
- Fix
- #2126 Fix bug where it was not possible to redirect from root when using pages. Thank you @AnnMarieW
- #2114 Fix bug #1978 where text could not be copied from cells in tables with
cell_selectable=False
. Thank you Benedikt - #2102 Fix bug as reported in dash-labs #113 where files starting with
.
were not excluded when buildingdash.page_registry
. Thank you Charmeem for reporting and thank you @AnnMarieW Ann for the PR - #2100 Fixes bug where module name in for a custom
not_found_404
page is incorrect in thedash.page_registry
when not using thepages
folder. Thank you Jacobs - #2098 Accept HTTP code 400 as well as 401 for JWT expiry
- #2097 Fix bug #2095 with TypeScript compiler and
React.FC
empty valueDeclaration error & support empty props components. Thank you Junsung for reporting - #2104 Fix bug #2099 with Dropdown clearing search value when a value is selected. Thank you Sergiy for reporting
- #2039 Fix bugs in long callbacks: Thank you sazzamac, kiwifoxtrot, and Samuel
- #2110 Fix
dcc.Dropdown
search with component as prop for option label. - #2131 Fix bug #2127 - Add encoding to file open calls. Thank you Luca for reporting
- #2116 Rename long callbacks to background callbacks
- Deprecated
dash.long_callback.managers.CeleryLongCallbackManager
, usedash.CeleryManager
instead. - Deprecated
dash.long_callback.managers.DiskcacheLongCallbackManager
, usedash.DiskcacheManager
instead. - Deprecated dash constructor argument
long_callback_manager
in favor ofbackground_callback_manager
.
- Deprecated
Previous Releases
Dash 2.5 Released - Easier Multi-Page Apps, Component Properties
Dash 2.4 Released - Improved Callback Context, Clientside Callback Promises, Typescript Components, Minor Ticks, and More!
Dash 2.3.0 Release - MathJax and fillpattern option in scatter trace
Dash 2.2.0 Release - Adds
ticklabelstep
to axes, and added dash.get_asset_url
Dash 2.1.0 Release - Autogenerated IDs and reärranged keyword arguments in Dash components