Hello,
I am trying to visualize live Data received by a UDP socket in Dash.
The socket runs in a different Thread, but in the same file and constantly updates the lists
time_list = []
light_list = []
temperature_list = []
label_list = []
which are used as input for the graph (id: “box-plot”)
However, the data does not arrive in the Dashboard, i.e. the plot stays blank. When I print the list after 10 seconds of sleeping, I see that the list is not empty (see the end of my code below).
With this post I want to know whether this is due to the general disability of Dash to exchange data between processes or whether it could generally work the way I specified it in the code (and I am missing something else)
I already checked out this post: Populating dash with data from udp thread, but since there is not really an answer, I want to ask again.
before trying to fit everything in one file, I also stored the UDP-received data in a file on the HD and made the callback function read it in every time it updates. This worked, but seemingly at a low performance.
So bottomline question: Is this problem Dash-specific, (i.e. I have to look in the Dash user guide: https://dash.plot.ly/sharing-data-between-callbacks, or am I generally missing something (which would probably lead me to stackexchange).
Edit: I think the socket code can mostly be ignored, the interesting part is the Dashboard and the callback function further below (as specified in code comments).
Thanks in advance!
Below my code:
# packages
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input, Event
import plotly.graph_objs as go
from collections import deque
import datetime as dt
import time
import numpy as np
import threading
import pickle
import socketserver
import pandas as pd
### UDP Socket ### ------------------------------------------------------------
# definition of Thread
# define as empty lists
time_list = []
light_list = []
temperature_list = []
label_list = []
class Socket_Thread(threading.Thread):
def __init__(self, iD, port):
threading.Thread.__init__(self)
self.iD = iD
self.port = port
def run(self):
# Initialize Socket
PORTNO = self.port
dt_classifier = pickle.load(open("sensor_dt.sav", 'rb'))
# converter for UNIX-times
dateconv = np.vectorize(dt.datetime.fromtimestamp)
class handler(socketserver.DatagramRequestHandler):
def handle(self):
newmsg = self.rfile.readline().strip().decode()
print(newmsg)
# split the message data into sensor values
lgt, tmp, lab = newmsg.split(',')
# append the sensor values to
time_list.append(dateconv(time.time()))
light_list.append(lgt)
temperature_list.append(tmp)
label_list.append(lab)
# convert the sensor values into a
d = {'light': [lgt], 'temperature': [tmp]}
obs = pd.DataFrame(d)
pr = dt_classifier.predict(obs)
print("DT said: ", pr[0])
pi_msg = str(pr[0]).encode()
print(pi_msg)
# send back the prediction
self.wfile.write(pi_msg)
s = socketserver.UDPServer(('',PORTNO), handler)
self.s = s
print("Awaiting UDP messages on port {}".format(PORTNO))
s.oldmsg = "This is the starting socketservermessage."
s.serve_forever()
def stop(self):
self.s.shutdown()
print("socket closed successfully")
### Dashboard ### -------------------------------------------------------------
# for initial deque
dateconv = np.vectorize(dt.datetime.fromtimestamp)
# init deques
l = deque(maxlen=25)
l.append(0)
t = deque(maxlen=25)
t.append(0)
tm = deque(maxlen=25)
tm.append(dateconv(time.time()))
app = dash.Dash()
app.css.append_css({'external_url': 'https://codepen.io/amyoshino/pen/jzXypZ.css'})
app.layout = html.Div([
# Selector row
html.Div([
html.Div([
html.P('Show:'),
dcc.Checklist(id = 'variables',
options=[{'label': 'Light', 'value': 'lgt_c'},
{'label': 'Temperature', 'value': 'tmp_c'}
],
values=['lgt_c', 'tmp_c'],
labelStyle={'display': 'inline-block'}
), # End Checklist
],
className='six columns',
style={'margin-top': '10'}
),
], className = 'row'), # End row (2)
# Graph row
html.Div([
html.Div(dcc.Graph(id="box-plot",
animate=False), className = 'twelve columns'),
# Event
dcc.Interval(id="graph-update",
interval=1000
),
], className = 'row'), # End row (3)
], className='ten columns offset-by-one') # End Global Div
# box plot + Callback
@app.callback(Output("box-plot", "figure"),
[Input('variables', 'values')],
events = [Event("graph-update", "interval")])
def update_box_plot(selector):
data = []
data_l = go.Box(
y=light_list,
name="Light"
)
data_t = go.Box(
y=temperature_list,
name="Temperature"
)
if 'lgt_c' in selector:
data.append(data_l)
if 'tmp_c' in selector:
data.append(data_t)
return{"data":data,
"layout": go.Layout(legend=dict(orientation="h"))}
### Main:
if __name__ == '__main__':
t1 = Socket_Thread(1, 10556)
t1.start()
time.sleep(10)
print(light_list)
app.run_server(debug=True)