【问题标题】:Python Dash live update with dcc.Interval not workingdcc.Interval 的 Python Dash 实时更新不起作用
【发布时间】:2022-01-05 18:16:10
【问题描述】:

我正在尝试使用来自我制作的 websocket 服务器的数据更新在我的 web 浏览器中打开的 Dash 图表。 我对 websocket 部分没有任何问题。我的服务器将我添加到列表中的数据发送到客户端,并将此列表转换为 pandas DataFrame 对象。然后将此对象添加到 multiprocess.Queue。

在来自 dcc.Interval 的 Dash 回调中,我从前一个队列中获取数据(这部分似乎工作,因为我可以正确打印数据)并更新我的图表。

但是我浏览器中的图表没有更新。我没有在我的 python 代码或浏览器控制台中看到任何错误。 (我尝试使用 Firefox、Chrome 和 Brave) 我的 python 控制台在每个回调间隔打印dash-update-component HTTP/1.1" 200 - 和我的数据,选项卡名称是Updating... 更糟糕的是,有时我可以看到一个或 10 个数据正确显示,然后什么都没有,而无需更改代码,只需重新启动我的代码...

这里是代码(客户端):

import multiprocess as mp
import threading
import dash
from dash.dependencies import Output, Input
from dash import dcc
from dash import html
import plotly.graph_objs as go
from socket import *
import time
import json
import pandas as pd
from datetime import datetime


FLAG_QUIT = False  
FLAG_ASK_DATA = False

MAX_SIZE = 10

queue = mp.Queue()
datas = []


app = dash.Dash(__name__)
app.layout = html.Div(
    [
        html.H4('Live Chart'),
        dcc.Graph(id='live-update-graph', animate =True), 
        dcc.Interval(
            id='interval-component',
            interval=200,
            n_intervals=0
        )
    ]
)

@app.callback(Output('live-update-graph', 'figure'),
              [Input('interval-component', 'n_intervals')])
def update_graph(n):
    df = queue.get()
    print(df)
    fig = go.Scatter(x=df.index, y = df['Data'])
    return fig

    

# function for receiving message from client
def send_to_server(clsock):
    global FLAG_QUIT
    global FLAG_ASK_DATA
    while True:
        try:
            if FLAG_QUIT == True:
                break
        
            if FLAG_ASK_DATA:
                time.sleep(0.5)
                clsock.sendall("ok".encode())
        except Exception as ex:
            print(str(ex))
        

# function for receiving message from server
def recv_from_server(clsock):
    global FLAG_QUIT
    global FLAG_ASK_DATA
    while True:
        try:
            data = clsock.recv(1024).decode()
            if data == 'q':
                print('Closing connection')
                FLAG_QUIT = True
                break
            process_data(data)
            FLAG_ASK_DATA = True
        except Exception as ex:
            print(str(ex))
        

def process_data(data):
    global datas
    global queue
    process_websocket_data(data)
    datas_dataframe = convert_data_to_dataframe(datas)
    queue.put(datas_dataframe)

def convert_data_to_dataframe(data):
    data_frame = pd.DataFrame(data)
    data_frame = data_frame.drop_duplicates(0)
    data_frame_date = data_frame[0]

    final_date = []

    for time in data_frame_date.unique():
        readable = datetime.strptime(time, '%Y-%m-%d-%H-%M')
        final_date.append(readable)

    data_frame.pop(0)
    dataframe_final_date = pd.DataFrame(final_date)

    dataframe_final_date.columns = ['Date']

    final_dataframe = data_frame.join(dataframe_final_date)

    final_dataframe.set_index('Date', inplace = True)

    final_dataframe.columns = ['Data']
    return final_dataframe

def process_websocket_data(raw_data):
    data_json = json.loads(raw_data)
    data = [data_json['Date'],data_json['Data']]
    datas.append(data)
    while len(datas) > MAX_SIZE:
        datas.pop(0)


def main():
    threads = []
    HOST = 'localhost'
    PORT = 8765
    clientSocket = socket(AF_INET, SOCK_STREAM)
    connected = False
    while not connected:
        try:
            print("Waiting connecting server...")
            time.sleep(1)
            clientSocket.connect((HOST, PORT))
            connected = True
        except :
            pass
    
    print('Client is connected to a chat sever!\n')
    clientSocket.send('start'.encode())

    t_send = threading.Thread(target=send_to_server, args=(clientSocket,))
    t_rcv = threading.Thread(target=recv_from_server, args=(clientSocket,))


    t_send.start()
    t_rcv.start()



if __name__ == '__main__':
    main()
    app.run_server()

我编码错误或遗漏了什么?

编辑: 这是我在回调 update_graph(n) 方法中从队列中得到的数据。

                Data
Date
2019-09-16  10302.00
2019-09-23   8061.98
2019-09-30   8042.08
2019-10-07   7851.01
2019-10-14   8274.33
2019-10-21   8218.23
2019-10-28   9534.37
2019-11-04   9197.86
2019-11-11   9041.31
2019-11-18   8504.13

我还尝试用 int 列表而不是日期列表替换我的 X 轴,但结果是相同的。不提神。

提前致谢。

【问题讨论】:

  • 我敢打赌这是因为你的间隔太快了。 200 毫秒可能不足以让网络请求和回调在下一个间隔触发之前完成,这会重新启动回调。尝试将其设置为 20000 (20s) 之类的值来启动,看看它是否有效,然后仔细调整它,看看你能以多快的速度可靠地让它运行。
  • @coralvanda 感谢您的回复。不幸的是,我按照您的建议尝试了更大的间隔,但结果是一样的:我的浏览器中没有刷新。也许我试图实现我的应用程序的方式是完全错误的。我不熟悉 Dash。
  • 如果你调试,或者添加一些print语句,你能看到你的数据框在回调期间是什么样子的吗?这可能有助于指导解决方案。
  • @coralvanda 我用回调中获得的数据和我做的测试编辑了我的帖子,但没有成功。
  • 好的,你有数据了,很好。关于如何设置散点图的问题可能是问题所在。您可以尝试硬编码一个测试 df 来玩。此外,您可以尝试在 dcc.Graph 的布局中设置 figure={},因为有时没有定义道具会很有趣。

标签: python websocket plotly-dash


【解决方案1】:

我终于找到了问题,它似乎是回调中的队列。所以我去掉了队列机制,转而使用带锁的经典列表。

app = dash.Dash(__name__)
app.layout = html.Div([
    dcc.Graph(id="live_graph", animate=False),
    dcc.Interval(id='interval_component',
                interval=INTERVAL,
               
    )])


@app.callback(Output('live_graph', 'figure'),
    [Input('interval_component', 'n_intervals')])
def update_graph(num):
    global datas_dataframe
    
    lock.acquire()
    if len(datas_dataframe) == 0:
        print("No data")
        lock.release()
        return no_update

    try:
        df = datas_dataframe.pop(0)
        fig = go.Figure(data=[go.Scatter(x=df.index,y=df['Data'])],
                        layout=go.Layout(yaxis=dict(tickfont=dict(size=22))))

        lock.release()
        return fig
    except Exception as ex:
        print(str(ex))
        lock.release()
        return no_update

【讨论】:

    猜你喜欢
    • 2021-09-05
    • 2020-03-29
    • 2019-01-06
    • 2021-03-08
    • 2021-12-15
    • 2020-11-17
    • 2012-11-29
    • 2016-05-12
    • 1970-01-01
    相关资源
    最近更新 更多