2

I am trying to create a real-time dash graph using plotly. I am following this tutorial link with the difference that I would like to update the data from another part of the script. In other words, I would like to have my script running and collecting data and then in real time it should be shown on the graph.

This is what I have so far

import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import random
import plotly.graph_objs as go
from collections import deque
import pandas as pd


class Plot:

    def __init__(self):
        self.points=[]
        self.app = dash.Dash(__name__)
        self.app.layout = html.Div(
            [
                dcc.Graph(id='live-graph', animate=True),
                dcc.Interval(
                    id='graph-update',
                    interval=500
                ),
            ]
        )
        self. app.callback(Output('live-graph', 'figure'),
        [Input('graph-update', 'n_intervals')])(self.update_graph_scatter)
        
    def start_server(self):
        self.app.run_server(debug=True,host='127.0.0.1', port=8011)

    def update_graph_scatter(self):
        
        pos = pd.DataFrame(data=self.points, columns=['x', 'y'])

        data = plotly.graph_objs.Scatter(
                x=pos['x'],
                y=pos['y'],
                name='Scatter',
                mode= 'lines+markers'
                )

        return {'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(pos['x']),max(pos['x'])]),
                                                    yaxis=dict(range=[min(pos['y']),max(pos['y'])]),)}

    def add_point(self,point):
        self.points.append(point)
    

What I want is doing something like :

plot=Plot()
plot.start_server()

for i in data_from_my_sensor_callback:
    plot.add_point(i)

But after start_server() the script is not executed. I also tried to run it in a separate thread but the result is the same.

1 Answer 1

2

To my knowledge, there are presently no official Dash components that support real-time updates initiated from the server, which seems to be what you are after (the Interval component initiates the update from the client). One possible solution would be to use a websocket, which is the approach used by the WebSocket component from dash-extensions. Here is a small example,

import json
import dash_html_components as html
import random
from gevent import sleep
from dash import Dash
from dash.dependencies import Input, Output
from dash_extensions import WebSocket
from dash_extensions.websockets import SocketPool, run_server


# Generator to simulate continuous readings from sensor.
def query_sensor():
    while True:
        sleep(random.uniform(0, 20))  # delay between sensor readings
        yield random.uniform(0, 1)  # the sensor value


# This block runs asynchronously.
def ws_handler(ws):
    for i in query_sensor():
        ws.send(json.dumps(i))  # send data


# Create example app.
app = Dash(prevent_initial_callbacks=True)
socket_pool = SocketPool(app, handler=ws_handler)
app.layout = html.Div([html.Div(id="data"), WebSocket(id="ws")])


@app.callback(Output("data", "children"), [Input("ws", "message")])
def update_data(msg):
    return json.dumps(msg["data"])


if __name__ == '__main__':
    run_server(app, port=5000)  # 5000 if the default port

tested with dash-extensions==0.0.41. Disclaimer: I am the author of dash-extensions.

Sign up to request clarification or add additional context in comments.

3 Comments

the example you wrote I think does almost the same thing of the example I am following (see the link in the question). I don't know why but when I run the script nothing happen. Anyway what I would like to do is execute something after the run_server. I also tried to create a separate thread but the server block the execution of the script.
If you go to localhost:5000 (the default port), you should see a number (representing the data) updating. As you note, you can’t just put code after run_server. However, the ws_handler is executed asynchronously, and should thus yield the desired behavior if you put the data collection code there.
Great! I have updated the code to better fit your use case (according to the question update).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.