Advanced Callbacks

Catching errors with PreventUpdate

In certain situations, you don’t want to update the callback output. You can
achieve this by raising a PreventUpdate exception in the callback function.

import dash
import dash_html_components as html
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.Button('Click here to see the content', id='show-secret'),
    html.Div(id='body-div')
])

@app.callback(
    Output(component_id='body-div', component_property='children'),
    [Input(component_id='show-secret', component_property='n_clicks')]
)
def update_output(n_clicks):
    if n_clicks is None:
        raise PreventUpdate
    else:
        return "Elephants are the only animal that can't jump"

if __name__ == '__main__':
    app.run_server(debug=True)

Displaying errors with dash.no_update

This example illustrates how you can show an error while keeping the previous
input, using dash.no_update to update the output partially.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.P('Enter a composite number to see its prime factors'),
    dcc.Input(id='num', type='number', debounce=True, min=1, step=1),
    html.P(id='err', style={'color': 'red'}),
    html.P(id='out')
])

@app.callback(
    [Output('out', 'children'), Output('err', 'children')],
    [Input('num', 'value')]
)
def show_factors(num):
    if num is None:
        # PreventUpdate prevents ALL outputs updating
        raise dash.exceptions.PreventUpdate

    factors = prime_factors(num)
    if len(factors) == 1:
        # dash.no_update prevents any single output updating
        # (note: it's OK to use for a single-output callback too)
        return dash.no_update, '{} is prime!'.format(num)

    return '{} is {}'.format(num, ' * '.join(str(n) for n in factors)), ''

def prime_factors(num):
    n, i, out = num, 2, []
    while i * i <= n:
        if n % i == 0:
            n = int(n / i)
            out.append(i)
        else:
            i += 1 if i == 2 else 2
    out.append(n)
    return out

if __name__ == '__main__':
    app.run_server(debug=True)

Enter a composite number to see its prime factors

Determining which Input has fired with dash.callback_context

In addition to event properties like n_clicks
that change whenever an event happens (in this case a click), there is a
global variable dash.callback_context, available only inside a callback.
It has properties:
- triggered: list of changed properties. This will be empty on initial
load, unless an Input prop got its value from another initial callback.
After a user action it is a length-1 list, unless two properties of a
single component update simultaneously, such as a value and a timestamp
or event counter.
- inputs and states: allow you to access the callback params
by id and prop instead of through the function args. These have the form
of dictionaries { 'component_id.prop_name': value }

Here’s an example of how this can be done:

import json

import dash
import dash_html_components as html
from dash.dependencies import Input, Output

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button('Button 1', id='btn-1'),
    html.Button('Button 2', id='btn-2'),
    html.Button('Button 3', id='btn-3'),
    html.Div(id='container')
])


@app.callback(Output('container', 'children'),
              [Input('btn-1', 'n_clicks'),
               Input('btn-2', 'n_clicks'),
               Input('btn-3', 'n_clicks')])
def display(btn1, btn2, btn3):
    ctx = dash.callback_context

    if not ctx.triggered:
        button_id = 'No clicks yet'
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    ctx_msg = json.dumps({
        'states': ctx.states,
        'triggered': ctx.triggered,
        'inputs': ctx.inputs
    }, indent=2)

    return html.Div([
        html.Table([
            html.Tr([html.Th('Button 1'),
                     html.Th('Button 2'),
                     html.Th('Button 3'),
                     html.Th('Most Recent Click')]),
            html.Tr([html.Td(btn1 or 0),
                     html.Td(btn2 or 0),
                     html.Td(btn3 or 0),
                     html.Td(button_id)])
        ]),
        html.Pre(ctx_msg)
    ])


if __name__ == '__main__':
    app.run_server(debug=True)

Legacy behaviour: using timestamps

Prior to v0.38.0, you needed to compare timestamp properties like
n_clicks_timestamp to find the most recent click. While existing uses of
*_timestamp continue to work for now, this approach is deprecated, and
may be removed in a future update. The one exception is
modified_timestamp from dcc.Store, which is safe to use, it is NOT
deprecated.


Improving performance with memoization

Memoization allows you to bypass long computations by storing the
results of function calls.

To better understand how memoization works, let’s start with a simple example.

import time
import functools32

@functools32.lru_cache(maxsize=32)
def slow_function(input):
    time.sleep(10)
    return 'Input was {}'.format(input)

Calling slow_function('test') the first time will take 10 seconds.
Calling it a second time with the same argument will take almost no time
since the previously computed result was saved in memory and reused.

The Performance section of the Dash docs delves a
little deeper into leveraging multiple processes and threads in
conjunction with memoization to further improve performance.