Dash:数据可视化仪表盘 (Dash: Data Visualization Dashboards)


章节概述

Dash 是 Plotly 团队开发的纯 Python 数据可视化仪表盘框架。无需编写 HTML/JavaScript,纯 Python 即可构建交互式 Web 仪表盘。适合数据分析师、量化交易员、科研人员快速构建数据看板。

C 程序员视角:如果 Flask 是 Web 的 printf,那 Dash 就是 Web 的 matplotlib——声明式地描述”我要什么图”,框架负责渲染和交互。


1. 安装与入门

pip install dash
# app.py
import dash
from dash import html, dcc
import plotly.express as px
import pandas as pd
 
app = dash.Dash(__name__)
 
df = pd.DataFrame({
    'x': [1, 2, 3, 4, 5],
    'y': [10, 25, 18, 32, 22],
    'label': ['A', 'B', 'C', 'D', 'E']
})
 
app.layout = html.Div([
    html.H1("我的第一个 Dash 仪表盘"),
    dcc.Graph(
        figure=px.scatter(df, x='x', y='y', color='label', title="散点图")
    )
])
 
if __name__ == '__main__':
    app.run(debug=True)
# 访问 http://127.0.0.1:8050/

2. 布局组件

from dash import html, dcc
 
app.layout = html.Div([
    # 标题
    html.H1("数据看板", style={'textAlign': 'center'}),
 
    # 下拉选择器
    dcc.Dropdown(
        id='metric-selector',
        options=[
            {'label': '销售额', 'value': 'sales'},
            {'label': '利润', 'value': 'profit'},
        ],
        value='sales'
    ),
 
    # 日期范围选择
    dcc.DatePickerRange(
        id='date-range',
        start_date_placeholder_text="开始日期",
        end_date_placeholder_text="结束日期"
    ),
 
    # 滑块
    dcc.Slider(min=0, max=100, step=5, value=50, marks={i: str(i) for i in range(0, 101, 20)}),
 
    # 图表
    dcc.Graph(id='main-chart'),
 
    # 刷新按钮
    html.Button('刷新数据', id='refresh-btn', n_clicks=0),
 
    # 定时器(自动刷新)
    dcc.Interval(id='interval', interval=5000, n_intervals=0)
])

3. 回调交互

from dash import Input, Output, State, callback
 
# 基础回调:下拉框选择 → 更新图表
@callback(
    Output('main-chart', 'figure'),
    Input('metric-selector', 'value')
)
def update_chart(metric):
    fig = px.bar(df, x='category', y=metric, title=f"{metric} 分布")
    return fig
 
# 多输入回调
@callback(
    Output('main-chart', 'figure'),
    Input('metric-selector', 'value'),
    Input('date-range', 'start_date'),
    Input('date-range', 'end_date')
)
def update_chart_with_date(metric, start_date, end_date):
    filtered = df[(df['date'] >= start_date) & (df['date'] <= end_date)]
    return px.bar(filtered, x='category', y=metric)
 
# 按钮回调(使用 State 避免循环触发)
@callback(
    Output('output', 'children'),
    Input('refresh-btn', 'n_clicks'),
    State('metric-selector', 'value')
)
def refresh_data(n_clicks, metric):
    if n_clicks == 0:
        return "点击刷新按钮加载数据"
    return f"已刷新 {metric} 数据(第 {n_clicks} 次)"

4. 多页面应用

from dash import Dash, html, dcc
from dash.dependencies import Input, Output
 
app = Dash(__name__, use_pages=True)
 
app.layout = html.Div([
    html.H1("多页面仪表盘"),
    # 导航
    dcc.Link("概览", href="/"), html.Span(" | "),
    dcc.Link("详细数据", href="/details"), html.Span(" | "),
    dcc.Link("设置", href="/settings"),
    # 页面内容
    dash.page_container
])
# pages/overview.py
import dash
from dash import html, dcc
import plotly.express as px
 
dash.register_page(__name__, path='/', name='概览')
 
def layout():
    return html.Div([
        html.H2("概览页面"),
        dcc.Graph(figure=px.line(df, x='date', y='value'))
    ])

5. 实时数据更新

from dash import Input, Output
from dash.dependencies import clientside_callback
 
# 服务端回调(定时器触发)
@callback(
    Output('live-chart', 'figure'),
    Input('interval', 'n_intervals')
)
def update_live_chart(n):
    # 从数据库/API 获取最新数据
    new_data = fetch_latest_data()
    return px.line(new_data, x='time', y='value')
 
# 客户端回调(JavaScript 执行,减少服务器负载)
clientside_callback("""
    function(n_intervals) {
        return fetch('/api/latest-data')
            .then(r => r.json())
            .then(data => ({
                data: [{x: data.time, y: data.value, type: 'scatter'}],
                layout: {title: '实时数据'}
            }));
    }
""", Output('live-chart', 'figure'), Input('interval', 'n_intervals'))

6. 部署

# 开发环境
python app.py
 
# 生产环境(gunicorn)
pip install gunicorn
gunicorn app:server -b 0.0.0.0:8050 -w 4
 
# Docker
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install dash pandas plotly gunicorn
CMD ["gunicorn", "app:server", "-b", "0.0.0.0:8050"]

7. 常用图表类型

import plotly.express as px
import plotly.graph_objects as go
 
# 散点图
px.scatter(df, x='x', y='y', color='category')
 
# 折线图
px.line(df, x='date', y='value', color='series')
 
# 柱状图
px.bar(df, x='category', y='count', color='group')
 
# 饼图
px.pie(df, names='category', values='count')
 
# 热力图
px.density_heatmap(df, x='x', y='y', z='value')
 
# 3D 散点
px.scatter_3d(df, x='x', y='y', z='z', color='category')
 
# 地理图
px.choropleth(df, locations='country', color='value', hover_name='country')
 
# 树状图
px.treemap(df, path=['region', 'category'], values='sales')

速查卡片

需求命令/代码
安装pip install dash
创建应用app = dash.Dash(__name__)
布局app.layout = html.Div([...])
回调@callback(Output(...), Input(...))
启动app.run(debug=True)
访问http://127.0.0.1:8050/
生产部署gunicorn app:server -b 0.0.0.0:8050