我编写了一个定期接收和处理地理数据的程序。我想在提供 dash
plotly
绘图的 Scattergeo
应用程序中绘制由该程序生成的(纬度,经度)对,或多或少随着数据进入。
这是一个双线程程序的 MWE,它使用队列从地理数据源接收数据并简单地打印它。本例中的数据只是 (lat, lon)
元组。
import threading
from queue import Queue
from CoordSource import CoordGetter
class Receiver(object):
def __init__(self, q):
while True:
item = q.get()
print("RECEIVED", item)
if __name__ == '__main__':
mainQueue = Queue()
cg = threading.Thread(target=CoordGetter, args=(mainQueue, ))
cg.start()
rt = threading.Thread(target=Receiver, args=(mainQueue, ))
rt.start()
这是一个基本的破折号应用程序的 MWE,它创建一个 Scattergeo 图并每两秒更新一次绘制的数据,但在这种情况下,它只是绘制了两个硬编码点:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__, prevent_initial_callbacks=True)
app.layout = html.Div(
html.Div([
dcc.Graph(id='live-update-graph'),
dcc.Interval(
id='interval-component',
interval=1*2000,
n_intervals=1
)
])
)
@app.callback(Output('live-update-graph', 'figure'),
Input('interval-component', 'n_intervals'))
def update_graph_live(n):
fig = go.Figure(go.Scattergeo())
fig.update_geos(projection_type="orthographic")
# hard-coded points, would like to receive from queue instead
df = pd.DataFrame({'lat': [0, 20], 'lon': [20, 0]})
fig.add_traces(data=go.Scattergeo(lat=df['lat'], lon=df['lon']))
return fig
if __name__ == '__main__':
app.run_server(debug=True)
根据我对它们的引用,这两个 MWE 都经过测试并且运行良好。但是,我一直遇到在生成数据的线程和绘制数据的仪表板应用程序之间共享队列的问题。
我已经尝试了很多东西,阅读了很多文档和示例,在这一点上,我很确定我对 dash 如何维护其线程有误解?因此,作为答案的一部分,我希望深入了解 dash 在这方面的工作原理。
另外,我应该注意,当我在 CoordGetter
之前开始 app.run_server()
时,它似乎开始两次。也就是说,它的 __init__()
函数中的任何调试打印语句都会输出两次,并且它第二次会抱怨它打开的 UDP 端口已经被使用。它开始两次并且我希望它开始一次表明对 dash 如何处理线程的额外误解,我想澄清一下。我怀疑对我的主要问题的一个很好的回答也会澄清这一点,但我想我会明确提到它。
注意:如果有帮助,我可以分享 CoordSource
,但它有点混乱并且与外部硬件和软件交互。我认为对于这个问题,可以简单地说它有效并将其视为黑匣子。我想在这里测试创建一个随机生成坐标的小类也同样有效,我也很乐意这样做以使问题更加独立。
编辑:以下类大致模仿了 CoordSource.CoordGetter
的行为:
from random import randrange, uniform
from time import sleep
class CoordGetter():
def __init__(self, queue):
self.queue = queue
self.generate()
def generate(self):
while True:
sleep(randrange(10))
for i in range(1, randrange(10)):
lat = uniform(-90,90)
lon = uniform(-180,180)
self.queue.put((lat, lon))