Black Lives Matter. Please consider donating to Black Girls Code today.

📣 Dash 1.16.1 Released - dcc.Graph prependData & Bug Fixes

Update: Version 1.16.2 has been released since this was posted.

We’re pleased to announce that Dash 1.16.1 is out :tada:

pip install dash==1.16.1

Dash 1.16.1 is a backwards compatible patch release. Highlights include:

View the Official Changelog


In More Detail

prependData

prependData is a new dcc.Graph property that allows you to prepend new data to the traces of a graph without sending the entire figure back and forth between the client and the Python callbacks. This can be much faster for incremental updates to the graph.

As inspiration, see this community example in the forum that incrementally updates the graph for rapid streaming:

The complement of prependData is the extendData property (used in the GIF above). extendData has existed for a couple of years.

Here’s a complete example demonstrating the syntax taken from our test suite:

import dash
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import json

app = dash.Dash(__name__)

def generate_with_id(id, data=None):
    if data is None:
        data = [{"x": [10, 11, 12, 13, 14], "y": [0, 0.5, 1, 0.5, 0]}]

    return html.Div(
        [
            html.P(id),
            dcc.Graph(id=id, figure=dict(data=data)),
            html.Div(id="output_{}".format(id)),
        ]
    )

figs = [
    "trace_will_prepend",
    "trace_will_prepend_with_no_indices",
    "trace_will_prepend_with_max_points",
]

layout = [generate_with_id(id) for id in figs]

figs.append("trace_will_allow_repeated_prepend")
data = [{"y": [0, 0, 0]}]
layout.append(generate_with_id(figs[-1], data))

figs.append("trace_will_prepend_selectively")
data = [
    {"x": [10, 11, 12, 13, 14], "y": [0, 0.5, 1, 0.5, 0]},
    {"x": [10, 11, 12, 13, 14], "y": [1, 1, 1, 1, 1]},
]
layout.append(generate_with_id(figs[-1], data))

layout.append(
    dcc.Interval(
        id="interval_prependablegraph_update",
        interval=10,
        n_intervals=0,
        max_intervals=1,
    )
)

layout.append(
    dcc.Interval(
        id="interval_prependablegraph_prependtwice",
        interval=500,
        n_intervals=0,
        max_intervals=2,
    )
)

app.layout = html.Div(layout)

@app.callback(
    Output("trace_will_allow_repeated_prepend", "prependData"),
    [Input("interval_prependablegraph_prependtwice", "n_intervals")],
)
def trace_will_allow_repeated_prepend(n_intervals):
    if n_intervals is None or n_intervals < 1:
        raise PreventUpdate

    return dict(y=[[0.1, 0.2, 0.3, 0.4, 0.5]])

@app.callback(
    Output("trace_will_prepend", "prependData"),
    [Input("interval_prependablegraph_update", "n_intervals")],
)
def trace_will_prepend(n_intervals):
    if n_intervals is None or n_intervals < 1:
        raise PreventUpdate

    x_new = [5, 6, 7, 8, 9]
    y_new = [0.1, 0.2, 0.3, 0.4, 0.5]
    return dict(x=[x_new], y=[y_new]), [0]

@app.callback(
    Output("trace_will_prepend_selectively", "prependData"),
    [Input("interval_prependablegraph_update", "n_intervals")],
)
def trace_will_prepend_selectively(n_intervals):
    if n_intervals is None or n_intervals < 1:
        raise PreventUpdate

    x_new = [5, 6, 7, 8, 9]
    y_new = [0.1, 0.2, 0.3, 0.4, 0.5]
    return dict(x=[x_new], y=[y_new]), [1]

@app.callback(
    Output("trace_will_prepend_with_no_indices", "prependData"),
    [Input("interval_prependablegraph_update", "n_intervals")],
)
def trace_will_prepend_with_no_indices(n_intervals):
    if n_intervals is None or n_intervals < 1:
        raise PreventUpdate

    x_new = [5, 6, 7, 8, 9]
    y_new = [0.1, 0.2, 0.3, 0.4, 0.5]
    return dict(x=[x_new], y=[y_new])

@app.callback(
    Output("trace_will_prepend_with_max_points", "prependData"),
    [Input("interval_prependablegraph_update", "n_intervals")],
)
def trace_will_prepend_with_max_points(n_intervals):
    if n_intervals is None or n_intervals < 1:
        raise PreventUpdate

    x_new = [5, 6, 7, 8, 9]
    y_new = [0.1, 0.2, 0.3, 0.4, 0.5]
    return dict(x=[x_new], y=[y_new]), [0], 7

for id in figs:

    @app.callback(
        Output("output_{}".format(id), "children"),
        [Input(id, "prependData")],
        [State(id, "figure")],
    )
    def display_data(trigger, fig):
        return json.dumps(fig["data"])

app.run_server(debug=True)


Previous Releases

Feedback, questions, thoughts? Let us know how it goes!

1 Like

@chriddyp

Can you please see this dash-loading-component issue?

Recently, after reinstalling my python, I am running into an exceptions. I tried dash 1.16.0 - 1.16.2 and I am not sure if it is due to this version but another plotly community user reported that he has not seen it.