Extend (or append) data instead of update


#1

I´m writting a live app that loads a large amount of data into the grahp. Currently I´m using the same method as in the examples.

app = dash.Dash(__name__)

app.layout = html.Div(
    html.Div([
        html.H4('Title'),
        html.Div(id='update-text'),
        dcc.Graph(id='update-plot'),
        dcc.Interval(
            id='interval-component',
            interval=10*1000,  # in milliseconds
            n_intervals=0
        )
    ])
)

@app.callback(Output('update-plot', 'figure'),
              [Input('interval-component', 'n_intervals')])
def update_plot(n):
    # load data from db
    # create the taces
    
    return Figure(data= traces, layout = SOME_LAYOUT)

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

The problem here is that every 10 seconds all the data have to be reloaded and redraw and it takes some time. Another issue is that if have some zoomed area or some trace hidden I loose it after the update.

I there any way to just add the latest data to the traces? Something as Plotly.extendTraces.
i´m gessing something like this

@app.callback(Output('update-plot', 'figure'),
              [Input('interval-component', 'n_intervals')])
def update_plot(n):
    if n==0: # First update
        # load data from db
        # create the taces
       # return the Figure
    else:
       # append new data to the Figure

Thanks


#2

You could add a State to the callback that captures the figure property:

@app.callback(Output('update-plot', 'figure'), [Input('interval-component', 'n_intervals')], [State('update-plot', 'figure')])

This will give you access to the current value of figure, which you can get the traces data out of.


#3

Great, this works. Now I have to figure out how to keep the same zoom after the update…

Thank you!

[EDIT] Here is solved


#4

Is there a best practice for how to use the fileopt='extend' argument? I am currently using the figure state in my callback, but maybe not in the most efficient manner.

What I did was basically something like:
x_new = fig['data'][0]['x'].extend(new_x_values)
y_new = fig['data'][0]['y'].extend(new_y_values)

and then creating a brand new Scatter trace with x=x_new, y=y_new. This works, but on the network side I’m still sending the complete dataset to the client on every interval.


#5

Do it this way surely save time in retrieving old data from the database, but it still redraws everything on the plot by
return {‘data’: traces, ‘layout’: layout}

is there a way to only draw the new trace and keep existing traces on the plot without redrawing them.

Thanks


#6

There is not. You have to use the method suggested above: Extend (or append) data instead of update.

It might be nice to have some “extend” option for the dcc.Graph component so that we don’t have to send the data back and forth to the client. I haven’t really thought this through, but if you want to play around with the dcc.Graph JS source code here: https://github.com/plotly/dash-core-components/blob/master/src/components/Graph.react.js