Clientside_callback use graph's extendData with multiple traces

Hi,

I’m running a live graph that updates a trace every 100ms via a combination of a dcc.Store and and different dcc.interval(s). I would like to have multiple traces in my graph, but I’m not able to get the right ‘extendData return’ in the javascript callback.

I’m currently returning this for a single trace and that works fine. Does anyone know how to modify the return line in order to work with multiple traces?

app.clientside_callback(
    """
    function (...) {
        return [[{x: [data.x.slice(offset, end)], y: [data.y.slice(offset, end)]}, [0], 250], end, data.x[offset], value_first];
    }
    """,
    [
        Output("graph", "extendData"), # dcc.graph item
        Output("offset", "data"), # dcc.Store items below
        Output("time-offset", "data"),
        Output("first-value", "data"),
    ],
)

Hi,

There are two modifications to be made in your extendData array:

  1. Both x and y should be an array of arrays with length equals to the number of traces to be updated. The inner arrays are the coordinates of the points added to each trace.

  2. The second element of extendedData has the indexes of traces you would like to update, following the same order as in x and y on the object in the first element.

The third element (250 in your case) is the maximum number of points being updated, which can be omitted for simplicity.

You can find more information here, on extendTraces.

1 Like

Hi junior,

Thanks for the reply. I changed the return statement following your directions. But there still seems to be something wrong. When I refresh the dashboard, the graph is not shown at all. Any ideas where I’m going wrong?

My current return line looks like this:

return [[{x: [data.x.slice(offset, end), data.x.slice(offset, end)], y: [data.y.slice(offset, end), data.yb.slice(offset, end)]}, [0, 1], 250], end, data.x[offset], value_first];

data.yb contains the y-coordinates of my second trace, they share the same x-coordinates.

Could you share your entire callback? Are there any errors on the browser console?

This is the entire callback:

app.clientside_callback(
    """
    function (n_intervals, data, offset, first_value) {
        if (data.x[0] === first_value) {
            value_first = first_value;
        } else {
            value_first = data.x[0];
            offset = 0;
        };
        offset = offset % data.x.length;
        const end = Math.min((offset + 1), data.x.length);
        return [[{x: [data.x.slice(offset, end), data.x.slice(offset, end)], y: [data.y.slice(offset, end), data.yb.slice(offset, end)]}, [0, 1], 250], end, data.x[offset], value_first];
    }
    """,
    [
        Output("graph", "extendData"),
        Output("offset", "data"),
        Output("time-offset", "data"),
        Output("first-value", "data"),
    ],
    [Input("interval", "n_intervals")],
    [State("store", "data"), State("offset", "data"), State("first-value", "data")],
)

There is nothing in my terminal but there is in the chrome console (they seem to repeat infintely):

Error: indices must be valid indices for gd.data.
    at P (async-plotlyjs.js:2)
    at async-plotlyjs.js:2
    at O (async-plotlyjs.js:2)
    at Object.t [as extendTraces] (async-plotlyjs.js:2)
    at Graph.react.js:223
    at Array.forEach (<anonymous>)
    at u.value (Graph.react.js:203)
    at u.value (Graph.react.js:435)
    at callComponentWillReceiveProps (react-dom@16.v2_0_0m1635790425.14.0.js:13111)
    at updateClassInstance (react-dom@16.v2_0_0m1635790425.14.0.js:13313)
error @ error.js:38
combination @ redux.js:538
eval @ reducer.js:126
eval @ reducer.js:172
dispatch @ redux.js:298
eval @ index.js:12
componentDidCatch @ ComponentErrorBoundary.react.js:56
callback @ react-dom@16.v2_0_0m1635790425.14.0.js:20884
callCallback @ react-dom@16.v2_0_0m1635790425.14.0.js:12625
commitUpdateQueue @ react-dom@16.v2_0_0m1635790425.14.0.js:12646
commitLifeCycles @ react-dom@16.v2_0_0m1635790425.14.0.js:19993
commitLayoutEffects @ react-dom@16.v2_0_0m1635790425.14.0.js:22938
callCallback @ react-dom@16.v2_0_0m1635790425.14.0.js:182
invokeGuardedCallbackDev @ react-dom@16.v2_0_0m1635790425.14.0.js:231
invokeGuardedCallback @ react-dom@16.v2_0_0m1635790425.14.0.js:286
commitRootImpl @ react-dom@16.v2_0_0m1635790425.14.0.js:22676
unstable_runWithPriority @ react@16.v2_0_0m1635790425.14.0.js:2685
runWithPriority$1 @ react-dom@16.v2_0_0m1635790425.14.0.js:11174
commitRoot @ react-dom@16.v2_0_0m1635790425.14.0.js:22516
finishSyncRender @ react-dom@16.v2_0_0m1635790425.14.0.js:21942
performSyncWorkOnRoot @ react-dom@16.v2_0_0m1635790425.14.0.js:21928
(anonymous) @ react-dom@16.v2_0_0m1635790425.14.0.js:11224
unstable_runWithPriority @ react@16.v2_0_0m1635790425.14.0.js:2685
runWithPriority$1 @ react-dom@16.v2_0_0m1635790425.14.0.js:11174
flushSyncCallbackQueueImpl @ react-dom@16.v2_0_0m1635790425.14.0.js:11219
workLoop @ react@16.v2_0_0m1635790425.14.0.js:2629
flushWork @ react@16.v2_0_0m1635790425.14.0.js:2584
performWorkUntilDeadline @ react@16.v2_0_0m1635790425.14.0.js:2196
async-plotlyjs.js:2 Uncaught Error: indices must be valid indices for gd.data.
    at P (async-plotlyjs.js:2)
    at async-plotlyjs.js:2
    at O (async-plotlyjs.js:2)
    at Object.t [as extendTraces] (async-plotlyjs.js:2)
    at Graph.react.js:223
    at Array.forEach (<anonymous>)
    at u.value (Graph.react.js:203)
    at u.value (Graph.react.js:435)
    at callComponentWillReceiveProps (react-dom@16.v2_0_0m1635790425.14.0.js:13111)
    at updateClassInstance (react-dom@16.v2_0_0m1635790425.14.0.js:13313)
P @ async-plotlyjs.js:2
(anonymous) @ async-plotlyjs.js:2
O @ async-plotlyjs.js:2
t @ async-plotlyjs.js:2
(anonymous) @ Graph.react.js:223
value @ Graph.react.js:203
value @ Graph.react.js:435
callComponentWillReceiveProps @ react-dom@16.v2_0_0m1635790425.14.0.js:13111
updateClassInstance @ react-dom@16.v2_0_0m1635790425.14.0.js:13313
updateClassComponent @ react-dom@16.v2_0_0m1635790425.14.0.js:17242
beginWork @ react-dom@16.v2_0_0m1635790425.14.0.js:18755
callCallback @ react-dom@16.v2_0_0m1635790425.14.0.js:182
invokeGuardedCallbackDev @ react-dom@16.v2_0_0m1635790425.14.0.js:231
invokeGuardedCallback @ react-dom@16.v2_0_0m1635790425.14.0.js:286
beginWork$1 @ react-dom@16.v2_0_0m1635790425.14.0.js:23338
performUnitOfWork @ react-dom@16.v2_0_0m1635790425.14.0.js:22292
workLoopSync @ react-dom@16.v2_0_0m1635790425.14.0.js:22265
performSyncWorkOnRoot @ react-dom@16.v2_0_0m1635790425.14.0.js:21891
(anonymous) @ react-dom@16.v2_0_0m1635790425.14.0.js:11224
unstable_runWithPriority @ react@16.v2_0_0m1635790425.14.0.js:2685
runWithPriority$1 @ react-dom@16.v2_0_0m1635790425.14.0.js:11174
flushSyncCallbackQueueImpl @ react-dom@16.v2_0_0m1635790425.14.0.js:11219
workLoop @ react@16.v2_0_0m1635790425.14.0.js:2629
flushWork @ react@16.v2_0_0m1635790425.14.0.js:2584
performWorkUntilDeadline @ react@16.v2_0_0m1635790425.14.0.js:2196
react-dom@16.v2_0_0m1635790425.14.0.js:19662 The above error occurred in the <u> component:
    in u
    in Suspense
    in Unknown (created by s)
    in s (created by CheckedComponent)
    in CheckedComponent (created by BaseTreeContainer)
    in ComponentErrorBoundary (created by BaseTreeContainer)
    in BaseTreeContainer (created by Context.Consumer)
    in Unknown (created by BaseTreeContainer)
    in div (created by it)
    in it (created by CheckedComponent)
    in CheckedComponent (created by BaseTreeContainer)
    in ComponentErrorBoundary (created by BaseTreeContainer)
    in BaseTreeContainer (created by Context.Consumer)
    in Unknown (created by UnconnectedContainer)
    in div (created by UnconnectedGlobalErrorContainer)
    in div (created by GlobalErrorOverlay)
    in div (created by GlobalErrorOverlay)
    in GlobalErrorOverlay (created by DebugMenu)
    in div (created by DebugMenu)
    in DebugMenu (created by UnconnectedGlobalErrorContainer)
    in div (created by UnconnectedGlobalErrorContainer)
    in UnconnectedGlobalErrorContainer (created by withRadiumContexts(UnconnectedGlobalErrorContainer))
    in withRadiumContexts(UnconnectedGlobalErrorContainer) (created by Connect(withRadiumContexts(UnconnectedGlobalErrorContainer)))
    in Connect(withRadiumContexts(UnconnectedGlobalErrorContainer)) (created by UnconnectedContainer)
    in UnconnectedContainer (created by Connect(UnconnectedContainer))
    in Connect(UnconnectedContainer) (created by UnconnectedAppContainer)
    in UnconnectedAppContainer (created by Connect(UnconnectedAppContainer))
    in Connect(UnconnectedAppContainer) (created by AppProvider)
    in Provider (created by AppProvider)
    in AppProvider

React will try to recreate this component tree from scratch using the error boundary you provided, ComponentErrorBoundary.

I can’t see any immediate errors from your js code, however it does not handle the cases where Input and State values are undefined, including when the app starts…

The best approach for that is to console.log each variable inside the function and debug on the chrome console.

Thanks for the pointers!

This is a log of the return statement:

This seems correct right?

Not sure where to go from here :confused:

Yes, the return looks correct. Looking back at the error, it seems that the issue is not on your callback, but when the dcc.Graph component uses extendTraces to update it.

There is a similar issue reported on SO, but no answer for that.

One thing you can take a look is to see if there is any mismatch between the timestamp formats currently in the array and in extendData. You can do it by passing the graph “figure” prop as state to the callback and console.log it in Js. Other than that, I don’t know what else to try to be honest.

On the other hand, if it worked for a single trace with this format, then it should work for two…. :slightly_frowning_face: