Dash 动态更新图表(完整教程)

快速解决

在 Dash 中实现 动态更新图表,最直接的方法是使用回调函数(callback),将图表组件的输出与某个状态或输入绑定,当状态变化时图表会自动刷新。以下是一个简单的示例代码:

import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
import random

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Interval(id='interval-component', interval=1000, n_intervals=0),  # 每秒触发一次
    dcc.Graph(id='live-update-graph'),  # 动态更新的图表
])

@app.callback(
    Output('live-update-graph', 'figure'),
    [Input('interval-component', 'n_intervals')]
)
def update_graph(n):
    # 生成随机数据
    df = pd.DataFrame({
        'x': range(n % 10, n % 10 + 10),
        'y': [random.random() for _ in range(10)]
    })
    # 生成折线图
    fig = px.line(df, x='x', y='y')
    return fig

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

此代码创建了一个每秒自动刷新的图表,适合用于实时数据展示场景。

常用方法

以下是 Dash 中实现 动态更新图表 的常见方法,按使用频率排序:

方法名称 描述 使用场景 所需组件
dcc.Interval 定时刷新图表 实时监控、数据轮询 dcc.Interval, dcc.Graph
dcc.Slider 通过滑块切换时间点 数据时间序列浏览 dcc.Slider, dcc.Graph
dcc.Dropdown 下拉选择图表类型或数据 用户交互筛选 dcc.Dropdown, dcc.Graph
dcc.Store 保存和恢复状态 多步交互流程 dcc.Store, dcc.Graph

详细说明

使用 dcc.Interval 定时更新图表

dcc.Interval 是 Dash 中实现定时更新的核心组件。通过设置 interval 属性(单位为毫秒),可以控制图表刷新频率。

import dash
from dash import html, dcc
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
import random

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Interval(id='interval', interval=2000, n_intervals=0),  # 每两秒触发一次
    dcc.Graph(id='live-chart')  # 动态图表组件
])

@app.callback(
    Output('live-chart', 'figure'),
    Input('interval', 'n_intervals')
)
def update_chart(n):
    # 生成新的数据
    df = pd.DataFrame({
        'x': range(n, n + 10),
        'y': [random.random() for _ in range(10)]
    })
    # 生成折线图
    fig = px.line(df, x='x', y='y', title='动态折线图')
    return fig

注释说明

  • dcc.Interval:设置定时器,每两秒触发一次回调。
  • update_chart:回调函数,根据 n_intervals 生成新的图表数据。
  • px.line:Plotly Express 创建折线图。

使用 dcc.Dropdown 控制图表数据源

通过下拉菜单,用户可以选择不同的数据集,图表会根据选择内容进行动态更新。

import dash
from dash import html, dcc
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd

app = dash.Dash(__name__)

df1 = pd.DataFrame({'x': [1, 2, 3], 'y': [10, 20, 30]})
df2 = pd.DataFrame({'x': [1, 2, 3], 'y': [30, 20, 10]})

app.layout = html.Div([
    dcc.Dropdown(
        id='data-select',
        options=[
            {'label': '数据集 1', 'value': 'df1'},
            {'label': '数据集 2', 'value': 'df2'}
        ],
        value='df1'  # 默认值
    ),
    dcc.Graph(id='dynamic-chart')
])

@app.callback(
    Output('dynamic-chart', 'figure'),
    Input('data-select', 'value')
)
def update_chart(selected_df):
    if selected_df == 'df1':
        data = df1
    else:
        data = df2
    fig = px.line(data, x='x', y='y', title='根据选择动态更新的图表')
    return fig

注释说明

  • dcc.Dropdown:提供用户选择不同数据集的下拉菜单。
  • update_chart:根据选择的值加载对应数据并生成图表。
  • 适合用于多数据源切换的场景,如不同产品销量对比等。

使用 dcc.Store 保存状态以供后续使用

在多步骤 Dash 应用中,使用 dcc.Store 可以将用户选择的数据或计算结果保存在前端,供其他回调使用。

import dash
from dash import html, dcc
from dash.dependencies import Input, Output, State
import plotly.express as px
import pandas as pd

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Input(id='user-input', type='number', value=10),
    html.Button('更新数据', id='update-button'),
    dcc.Store(id='stored-data'),  # 用于存储数据
    dcc.Graph(id='stored-chart')
])

@app.callback(
    Output('stored-data', 'data'),
    Input('update-button', 'n_clicks'),
    State('user-input', 'value')
)
def generate_data(n_clicks, input_value):
    if not n_clicks:
        return None
    # 生成数据
    df = pd.DataFrame({
        'x': range(1, input_value + 1),
        'y': [i * 2 for i in range(1, input_value + 1)]
    })
    return df.to_dict()  # 转为字典保存

@app.callback(
    Output('stored-chart', 'figure'),
    Input('stored-data', 'data')
)
def update_chart(data):
    if not data:
        return {}
    df = pd.DataFrame(data)
    fig = px.line(df, x='x', y='y', title='根据输入值生成的动态图表')
    return fig

注释说明

  • dcc.Store:用于在浏览器中存储数据,不会暴露给用户。
  • 第一个回调:用户点击按钮后,根据输入值生成数据并保存。
  • 第二个回调:读取存储的数据并更新图表。
  • 适用于需要缓存用户输入或中间计算结果的场景。

高级技巧

1. 结合 dcc.Intervaldcc.Store 实现数据缓存 + 实时刷新

有些场景需要定时刷新图表,同时避免重复请求数据。可以使用 dcc.Store 缓存数据,再由定时器触发图表更新。

import dash
from dash import html, dcc
from dash.dependencies import Input, Output, State
import plotly.express as px
import pandas as pd
import random

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Interval(id='interval', interval=2000, n_intervals=0),
    dcc.Store(id='cached-data', data={}),  # 缓存数据
    dcc.Graph(id='cached-chart')
])

@app.callback(
    Output('cached-data', 'data'),
    Input('interval', 'n_intervals'),
    State('cached-data', 'data')
)
def update_cached_data(n, cached):
    # 模拟从外部 API 获取新数据
    new_data = pd.DataFrame({
        'x': [i for i in range(n, n + 10)],
        'y': [random.random() for _ in range(10)]
    })
    # 合并缓存数据
    cached_df = pd.DataFrame(cached) if cached else pd.DataFrame()
    updated_df = pd.concat([cached_df, new_data]).drop_duplicates(subset='x')
    return updated_df.to_dict()

2. 实时图表 + 动态数据加载(如 WebSocket)

如果数据来自实时流(如 WebSocket),你可以将数据保存在 dcc.Store 中,然后通过定时器刷新图表。这部分需要后端配合,但 Dash 前端实现可以很简洁。

3. 多图表联动更新

多个图表可以共享一个数据源,通过统一的回调函数实现同步更新。例如,点击一个按钮后,多个图表同时刷新。

@app.callback(
    [Output('chart1', 'figure'), Output('chart2', 'figure')],
    Input('refresh-button', 'n_clicks')
)
def update_charts(n):
    # 生成两个不同的图表
    fig1 = px.line(data1, x='x', y='y')
    fig2 = px.bar(data2, x='x', y='y')
    return fig1, fig2

常见问题

Q1:为什么图表没有更新?

可能是回调函数未正确绑定,或输出组件的 id 不一致。确保 Outputid 与图表组件的 id 完全匹配。

Q2:如何在 Dash 中避免数据重复加载?

使用 dcc.Store 保存数据,避免每次回调都重新请求或计算。判断是否已有数据再进行处理。

Q3:可以实现毫秒级图表刷新吗?

可以,设置 dcc.Interval(interval=100) 即可每 100 毫秒触发一次。但要注意数据量和性能开销。

Q4:图表更新时如何保留历史数据?

在回调函数中将新数据与旧数据合并,例如使用 pd.concat,并设置合适的去重逻辑。

总结

通过回调函数与 Dash 的组件组合(如 dcc.Intervaldcc.Dropdowndcc.Store),你可以高效地实现 Dash 动态更新图表,满足实时监控、用户交互等多种需求。