Can't update markers via `extendData`

Hello everyone!
It seems like comments asking about this issue are scattered across other posts, so I’ve decided to make a dedicated post for it.
I am trying to build a live-updating bubble chart, and I can’t find a way to use extendData features to update markers of the corresponding scatter plot.
I would appreciate any help on this issue. Code below is the minimal example.
@brad, @Emmanuelle you might know the answer.

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import plotly.graph_objects as go
from dash.dependencies import Input, Output


if __name__ == "__main__":
    app = dash.Dash()

    fig = go.Figure(data=go.Scatter(
        y=np.random.randn(500),
        mode='markers',
        marker=dict(
            size=10*np.abs(np.random.randn(500)),
            color=["red", "green"] * 250,
            showscale=True
        )
    ))

    app.layout = html.Div([
        html.Div([
            dcc.Graph(
                id='graph-extendable',
                figure=fig
            ),
        ]),
        dcc.Interval(
            id='interval-graph-update',
            interval=50,
            n_intervals=0),
    ])


    @app.callback(Output('graph-extendable', 'extendData'),
                  [Input('interval-graph-update', 'n_intervals')]
                  )
    def extend_scatter_trace(n_intervals):
        # how to update markers here?
        return (dict(y=[np.random.randn(5)]), [0])

    app.run_server(debug=True)

pip install dash-extendable-graph

As far as I know this library doesn’t solve the issue. Care to elaborate?

First thing to mention is that the way your code is written, marker styling is only defined for the first 500 values. The plot is actually extending the points (you can check by hovering over the “empty” plot, or change mode='line+markers'), they just aren’t visible. So, if you were to change your code in the following manner you would see the markers showing up as expected.

...
    fig = go.Figure(data=go.Scatter(
        y=np.random.randn(500),
        mode='markers',
        marker=dict(
            size=10,
            color="red",
            showscale=True
        )
    ))

I’m assuming that doesn’t help … your example implies that there’s information you need to communicate through marker color/size. The short answer is that neither dcc.Graph nor deg.ExtendableGraph can do what you’re asking.

  • I think you’ll need to make a feature request to the underlying javascript plotting library (PlotlyJS). The APIs support new trace data in the splice/extend/prependTraces functions but does not handle trace styling. I’m not sure how best to implement those changes.
  • In the interim, you could update figure.data on each update.

Hi Brad, thanks for the reply.

I’m assuming that doesn’t help … your example implies that there’s information you need to communicate through marker color/size

Yes, the point is that I need to update markers somehow as well. My current workaround is adding a trace on each callback using deg.ExtendableGraph but I was hoping for a more principled approach. Will updating figure.data cause re-rendering of the whole chart?

Yes, it will. One approach could be to extend the trace and then execute Plotly.restyle() with the updated marker information. You could accomplish this with a clientside callback, but that’s pretty hacky.

In terms of enhancements to the components themselves…

  • could add a restyle property to the ExtendableGraph component which would allow you to send restyle commands in a callback
  • could modify the ExtendableGraph extendData API to natively attempt to restyle the trace (e.g. any property of the provided dict that isn’t of type array)

I will think about this a bit more. It would be much cleaner if the JS api could handle restyling on its own, but that might not be a priority (could present some perf issues as well).

2 Likes