Update figure (subplots) without creating a new one

Hi,

Updating a chart with subplots is basically the same as updating a chart with multiple traces. From the documentation:

extendData ( list | dict ; optional): Data that should be appended to existing traces. Has the form [updateData, traceIndices, maxPoints] , where updateData is an object containing the data to extend, traceIndices (optional) is an array of trace indices that should be extended, and maxPoints (optional) is either an integer defining the maximum number of points allowed or an object with key:value pairs matching updateData

In most cases, updateData is basically a dictionary with the x and y coordinates of the new points. They should be a list of lists when updating multiple traces, where each inner list contains the new points for each respective trace.
If traceIndices is not provided, then each list will be given in ascending order to the traces. As an example, if you want to update the 1st and 3rd traces only, extendData should be:

extend_data = [
    {
        "x": [
            [0, 1], # x coord, 1st trace
            [10, 11, 12]
         ],
        "y": [
            [1.212, 2.212], # y coord, 1st trace
            [100, 200, 300]
         ], 
     },  # this is updateData
     [0, 2] # this are traceIndices, if missing, traces 0 and 1 would be updated
]

Note that the trace order in the Figure object depends on the order that you added each trace to each subplot and in principle you can have multiple traces in a single subplot. Therefore it is a good idea to take a look in figure["data"] and perhaps implement the update logic based on it.

Here’s an adaptation of an example I had for subplots:

from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots

app = Dash(__name__)

fig = make_subplots(cols=3, rows=1)

fig.add_scatter(
    x = [1,2,3],
    y = [100, 200, 150],
    col=1,
    row=1
)

fig.add_scatter(
    x = [1,2,3],
    y = [20, 10, 15],
    col=2,
    row=1
)
    
fig.add_scatter(
    x = [1,2,3],
    y = [20, 10, 15],
    col=3,
    row=1
)

app.layout = html.Div(
    [
        dcc.Interval(id="interval", interval=2000),
        dcc.Graph(id="graph", figure=fig)
    ]
)

@app.callback(
    Output("graph", "extendData"),
    Input("interval", "n_intervals"),
    State("graph", "figure")
)
def update(n_intervals, figure):
    print(figure)  # figure["data"] is where the traces are defined

    return [
        {
            "x": [
                [figure["data"][0]["x"][-1] + i for i in range(1, 3)],
                [figure["data"][2]["x"][-1] + i for i in range(1, 3)]
            ],
            "y": [
                [figure["data"][0]["y"][-1] + i * 50 for i in range(1, 3)],
                [figure["data"][2]["y"][-1] + i * 5 for i in range(1, 3)]
            ]
        },
        [0, 2], 
        10 # last 10 points will be kept in each trace
    ]


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

Hope that this helps!

2 Likes