Plotly/Dash 以流畅的动画显示实时数据

2023-12-31

我们正在尝试在plotly-dash 中生成一个实时仪表板,用于显示生成的实时数据。我们通常遵循此处的指导(https://dash.plotly.com/live-updates https://dash.plotly.com/live-updates).

我们有一个回调,大约每秒从源收集大量新数据点,然后将数据附加到图表中。

当我们这样做时,图表的更新是断断续续的,因为我们每秒都会在回调中生成一个新的图表对象。我们希望图表能够顺利流动,即使这意味着我们落后实时数据一两秒。

我们正在看动画(https://plotly.com/python/animations/ https://plotly.com/python/animations/)但尚不清楚我们如何将动画应用于附加到图表的实时数据流。


更新痕迹Graph组件无需生成新的图形对象可以通过以下方式实现extendData财产。这是一个每秒附加数据的小例子,

import dash
import dash_html_components as html
import dash_core_components as dcc
import numpy as np

from dash.dependencies import Input, Output

# Example data (a circle).
resolution = 20
t = np.linspace(0, np.pi * 2, resolution)
x, y = np.cos(t), np.sin(t)
# Example app.
figure = dict(data=[{'x': [], 'y': []}], layout=dict(xaxis=dict(range=[-1, 1]), yaxis=dict(range=[-1, 1])))
app = dash.Dash(__name__, update_title=None)  # remove "Updating..." from title
app.layout = html.Div([dcc.Graph(id='graph', figure=figure), dcc.Interval(id="interval")])


@app.callback(Output('graph', 'extendData'), [Input('interval', 'n_intervals')])
def update_data(n_intervals):
    index = n_intervals % resolution
    # tuple is (dict of new data, target trace index, number of points to keep)
    return dict(x=[[x[index]]], y=[[y[index]]]), [0], 10


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

根据客户端和服务器之间的网络连接(每次更新时,客户端和服务器之间交换请求),此方法的刷新率可达 1 秒左右。

如果您需要更高的刷新率,我建议使用客户端回调 https://dash.plotly.com/clientside-callbacks。采用前面的示例,代码将类似于

import dash
import dash_html_components as html
import dash_core_components as dcc
import numpy as np

from dash.dependencies import Input, Output, State

# Example data (a circle).
resolution = 1000
t = np.linspace(0, np.pi * 2, resolution)
x, y = np.cos(t), np.sin(t)
# Example app.
figure = dict(data=[{'x': [], 'y': []}], layout=dict(xaxis=dict(range=[-1, 1]), yaxis=dict(range=[-1, 1])))
app = dash.Dash(__name__, update_title=None)  # remove "Updating..." from title
app.layout = html.Div([
    dcc.Graph(id='graph', figure=dict(figure)), dcc.Interval(id="interval", interval=25),
    dcc.Store(id='offset', data=0), dcc.Store(id='store', data=dict(x=x, y=y, resolution=resolution)),
])
app.clientside_callback(
    """
    function (n_intervals, data, offset) {
        offset = offset % data.x.length;
        const end = Math.min((offset + 10), data.x.length);
        return [[{x: [data.x.slice(offset, end)], y: [data.y.slice(offset, end)]}, [0], 500], end]
    }
    """,
    [Output('graph', 'extendData'), Output('offset', 'data')],
    [Input('interval', 'n_intervals')], [State('store', 'data'), State('offset', 'data')]
)

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

客户端更新应该足够快,以实现平滑更新。下面的 gif 显示了以 25 毫秒刷新率运行的上述示例,

请记住,只有当数据已经存在于客户端时才可能进行客户端更新,即需要另一种机制来从服务器获取数据。可能的数据流可以是

  1. 使用慢速Interval组件(例如 2 秒)触发一个(正常)回调,从源中获取一块数据并将其放入Store成分
  2. 使用快速Interval组件(例如 25 ms)触发客户端回调,该回调从Store组件到Graph成分
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Plotly/Dash 以流畅的动画显示实时数据 的相关文章

随机推荐