This is somewhat related to the aim described in this post. I want to use dash
to control a piece of equipment. User sets some parameters, sends the command to the equipment and then gets some data back to monitor variables of interest in real time.
Maybe, for example, we start up dash
and then send a command to a hypothetical wireless coffee maker. The API to the coffee might have a brew()
call that begins the heating process, adding it’s temperatures to a data frame so we can watch the process. Perhaps brew()
doesn’t return until the coffee maker reaches a target temp.
Here’s an example illustrating what I mean:
#!/usr/bin/env python
import dash
import dash_core_components as dcc
import dash_html_components as html
import datetime
import numpy as np
import pandas as pd
import plotly.graph_objs as go
import time
global data
data = pd.DataFrame(columns=['time', 'temp'])
def build_layout():
layout = html.Div([
html.H2('a dashboard'),
html.Div(dcc.Interval(id='refresh', interval=1000)),
html.Div(id='plot')
]) # app.layout
return layout
def generate_plot(data):
plot = dcc.Graph(
id='the_plot',
figure={
'data': [go.Scatter(name='plot',
x=data['time'],
y=data['temp'])],
'layout': go.Layout(title= 'Live test data')#,
},
style={'width': '80%', 'float': 'right'}
) # dcc.Graph
return plot
def generate_data():
count = 0
while True:
for i in range(10):
data.loc[len(data)] = [datetime.datetime.now(), np.random.uniform(50)]
print(data)
time.sleep(0.5)
app = dash.Dash()
app.layout = build_layout
@app.callback(
dash.dependencies.Output('plot', 'children'),
events=[dash.dependencies.Event('refresh', 'interval')])
def update():
return generate_plot(data)
if __name__ == '__main__':
app.run_server()
generate_data()
So we set up the dashboard (just a plot) and want it to update every second. I know that global variables are not recommended, but I’m a noob so it’s the best I could figure at the moment. After starting the server, generate_data()
is like the brew()
call mentioned above. It doesn’t return until brewing is complete, but it’s updating data at regular intervals.
The example above behaves like run_server()
is blocking somehow. It starts up, but I get a blank plot, and data
is never printed. When I Ctrl-C
in the terminal, the data starts printing out as expected.
In this example, I can change the callback to (adding a return to generate_data()
):
def update():
data = generate_data()
return generate_plot()
And that will update the plot at 1 sec intervals as expected. But… I don’t have the analog of this in the method I described.
How do you blend dash
with something that blocks or doesn’t return when you want? Do I need to separate these and, say, have one python file/thread writing interim data to a file, and a separate dash
process where the callback would read that file? I hoped to avoid this so everything could just pass a data object around vs. having to rely on I/O.
Thanks for any tips!