What is a correct usage of extendData property to achieve adding data to existing graph instead of constantly updating it?

Hi all,

I’m trying to update already created graph’s data instead of constantly redrawing the whole diagram. I found this extendData property however I have some issues with properly using it.
I found this information on plotly github page:

with sample use case, however it doesn’t work correctly on my side. I’m getting those errors:

I would be very grateful for your help and all the explanations for the proper usage of this property.
I’m new in this library so I’m hoping for some easy treatment if this is a trivial issue :).

Thanks!

1 Like

Hi @manius.cezar welcome to the forum! It’s hard to know what’s going on just from the screenshot, could you please:

  • click to see the full trace, which will give more information
  • and share here the callback modifying extendData ?

One thing maybe is that when you pass new x and y data, they must be arrays as in the example you linked to [dict(x=[x_new], y=[y_new])] and can’t be just scalar values. Maybe you forgot to add brackets around your new values?

Hi @Emmanuelle, thanks for writing me back!

The thing is that this example I’ve linked generates this issue (I copy pasted it to make sure i didn’t made any typo). Maybe you could check this code on your side - I think it will generate also the same error.

Anyway, here’s the full trace:

#1:

Error: attribute x must be an array of length equal to indices array length

    at http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2300478

    at D (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2300788)

    at Object.t [as extendTraces] (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2327505)

    at http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:13088

    at Array.forEach (<anonymous>)

    at t.value (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:12848)

    at t.value (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:15796)

    at callComponentWillReceiveProps (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:13133:16)

    at updateClassInstance (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:13335:9)

    at updateClassComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:17266:22)

#2:

Error: attribute: x index: 0 must be an array

    at http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2301037

    at D (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2301394)

    at Object.t [as extendTraces] (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-plotlyjs.v1_10_0m1588696753.js:2:2327505)

    at http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:13088

    at Array.forEach (<anonymous>)

    at t.value (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:12848)

    at t.value (http://127.0.0.1:8050/_dash-component-suites/dash_core_components/async-graph.v1_10_0m1588696753.js:1:15796)

    at callComponentWillReceiveProps (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:13133:16)

    at updateClassInstance (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:13335:9)

    at updateClassComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_4_1m1589641938.13.0.js:17266:22)

Hi @manius.cezar indeed the syntax proposed in the pull request you found has changed since it was first proposed. The correct code is now

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

app = dash.Dash(__name__)


app.layout = html.Div([
    html.Div([
        html.H3('Extend a specific trace'),
        dcc.Dropdown(
            id='trace-selection',
            options=[
                {'label': 'extend trace 0', 'value': 0},
                {'label': 'extend trace 1', 'value': 1},
            ],
            value=0
        ),
        dcc.Graph(
            id='graph-extendable',
            figure=dict(
                data=[{'x': [0, 1, 2, 3, 4],
                       'y': [0, .5, 1, .5, 0],
                       'mode':'lines+markers'
                       },
                      {'x': [0, 1, 2, 3, 4],
                       'y': [1, 1, 1, 1, 1],
                       'mode':'lines+markers'
                       }],
            )
        ),
    ]),
    html.Div([
        html.H3('Extend multiple traces at once'),
        dcc.Graph(
            id='graph-extendable-2',
            figure=dict(
                data=[{'x': [0, 1, 2, 3, 4],
                       'y': [0, .5, 1, .5, 0],
                       'mode':'lines+markers'
                       },
                      {'x': [0],
                       'y': [0],
                       'mode':'lines'
                       },
                      {'x': [0, .1, .2, .3, .4],
                       'y': [0, 0, 0, 0, 0],
                       'mode':'markers'
                       }],
            )
        ),
    ]),
    dcc.Interval(
        id='interval-graph-update',
        interval=1000,
        n_intervals=0),
])


@app.callback(Output('graph-extendable', 'extendData'),
              [Input('interval-graph-update', 'n_intervals')],
              [State('graph-extendable', 'figure'),
               State('trace-selection', 'value')])
def update_extend_traces_traceselect(n_intervals, existing, trace_selection):
    x_new = existing['data'][trace_selection]['x'][-1] + 1
    y_new = random.random()
    return dict(x=[[x_new]], y=[[y_new]]), [trace_selection]


@app.callback(Output('graph-extendable-2', 'extendData'),
              [Input('interval-graph-update', 'n_intervals')],
              [State('graph-extendable-2', 'figure')])
def update_extend_traces_simult(n_intervals, existing):
    return (dict(x=[
        [existing['data'][0]['x'][-1] + 1],
        [existing['data'][1]['x'][-1] - .5, existing['data'][1]['x'][-1] + 1],
        [existing['data'][2]['x'][-1] + .1]
    ],
        y=[
        [random.random()],
        [0, random.random()],
        [random.random()]
    ]),
        [0, 1, 2]
    )


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

Hi @Emmanuelle, thank you very much for your feedback. Indeed ,there was a mistake in the format. Thank you for your reply, it was very helpful!

Hi Emmanuelle, Is it possible to not only extend the x and y values, but also marker options (e.g. for a bubble chart)?

I got very similar question, can attributes such as ‘marker’ and its ‘color’ be extended?

                       {'x': [0, 1, 2, 3, 4],
                       'y': [0, .5, 1, .5, 0],
                       'marker':{'color':['red','brown','blue','gold']},
                       'mode':'lines+markers'
                       },

how to pass the color for the new extended point?

Can we change the marker? like color or symbol?

Hi Emmanuelle, how to update axis range? can I use Output(‘graph-extendable-2’, ‘layout’) to update layout with new axis range? Thanks