Update Scatter3D graph in realtime

I am trying to write a Dash app that will draw a Scatter3D graph as new data is available. The purpose is to draw the path of a CNC toolhead from simulation data.

I am very new to Plotly and Dash so excuse the lack of virtually any knowledge. I also tried to search for something similar on the forums but failed.

I know that I should use dcc.Interval() in a Div element in order for it to update automatically. What I can’t figure out is how to do the actual update.

All the examples that I have seen seem to just create a new figure in the update callback but that seems overly complicated. Is there a way that I can just update the data in the trace?

I think I need to use Output('<id>', 'extendData') in order to dynamically extend the data set. However, now I am stuck at figuring out how to add the Scatter3D graph to the app initially. The dcc.Graph element seems just like an generic element that holds any graph.

How do I add an empty Scatter3D plot to it and just add data through the callback?

Hey @voidtrance does this help to get you started?

1 Like

Thank you for the reply. In my limited ability to understand Dash, I tried looking at your example but could not figure out what is going on.

One thing that did help is understanding how to get the dcc.Graph element to display an existing figure.

However, I don’t understand how the data is dynamically updated. Here is what I have so far:

   app = Dash("Emulator Trace")

    @app.callback(Output('travel-plot', 'extendData'),
                Input('interval-component', 'n_intervals'))
    def update_dash_data(n):
        pos, temps = get_data(connection, toolhead, *heaters)
        data = {'x':[pos[0]], 'y': [pos[1]], 'z': [pos[2]]}
        return data

    g = go.Scatter3d(name="shape", mode="lines", x=[], y=[], z=[])
    l = go.Layout(autosize=False, width=1800, height=1800,
                    margin=go.layout.Margin(l=50, r=50, b=100, t=100, pad=4))
    fig = go.Figure(g, layout=l)
    
    app.layout = html.Div([
        dcc.Graph(id="travel-plot", figure=fig),
        dcc.Interval(id="interval-component", interval=50, n_intervals=0)
    ])

    app.run_server(debug=True)

The above does start the app and I don’t get any debug errors. However, it also only displays a blank graph, even though, the callback is constantly getting called and getting new values.

I figured it out. Here is the code that works:

    app = Dash("Emulator Trace")

    g = go.Scatter3d(name="shape", mode="lines", x=[], y=[], z=[])
    l = go.Layout(autosize=False, width=1800, height=1800,
                    margin=go.layout.Margin(l=50, r=50, b=100, t=100, pad=4))
    fig = go.Figure(g, layout=l)
    
    app.layout = html.Div([
        dcc.Graph(id="travel-plot", figure=fig),
        dcc.Interval(id="interval-component", interval=500, n_intervals=0)
    ])

    @app.callback(Output('travel-plot', 'extendData'),
                  Input('interval-component', 'n_intervals'))
    def update_dash_data(n):
        pos, temps = get_data(connection, toolhead, *heaters)
        data = {'x':[[pos[0]]], 'y': [[pos[1]]], 'z': [[pos[2]]]}, [0], None
        return data

    app.run_server(debug=True)
1 Like

Nice work! So you answered your own question, right?

If you need help with anything else, just open a new topic :slight_smile: