Dash 是一个由 Plotly 公司开发的开源框架,让你只用 Python 就能构建具有丰富交互性的 Web 应用。你不需要写任何 HTML、CSS 或 JavaScript,所有界面和逻辑都可以通过 Python 对象与回调函数完成。它非常适用于数据分析、仪表盘、机器学习演示等场景。

一、Dash 是什么

简单理解,Dash 把前端的 React 组件封装成了 Python 类,并把 Plotly.js 的强大图表能力也带到了 Python 生态中。一个 Dash 应用由两个核心部分组成:

· 布局:描述应用长什么样,由 html 和 dcc(Dash Core Components)等组件构成。
· 回调:描述交互逻辑,当用户操作组件时,如何更新其他组件。

最终,Dash 应用通过 Flask 服务器运行,你可以直接在浏览器中访问。

二、安装与快速开始

首先安装 Dash 及相关依赖。建议在虚拟环境中操作:

pip install dash pandas plotly

Dash 2.x 已将 dash-core-components、dash-html-components 和 dash-table 统一整合到 dash 包中,直接导入即可。

创建一个最小应用 app.py:

from dash import Dash, html

app = Dash(__name__)

app.layout = html.Div([
    html.H1('你好,Dash!'),
    html.P('这是我的第一个 Dash 应用。')
])

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

运行 python app.py,然后在浏览器打开 http://127.0.0.1:8050,你就能看到页面了。debug=True 开启热重载,修改代码后页面会自动刷新。

三、布局详解

布局由一系列组件以树形结构嵌套而成,就像搭积木一样。最常用的两个子包是:

· html:封装了所有 HTML 标签,比如 Div、H1、P、Img 等,属性和 HTML 几乎一致(比如 style、className)。
· dcc:提供高级交互组件,例如图表、下拉框、滑块、输入框等。

使用 HTML 组件

from dash import html

html.Div([
    html.H1('标题', style={'color': 'blue', 'textAlign': 'center'}),
    html.P('这是一段文字', className='my-class'),
    html.Img(src='/assets/logo.png', style={'width': '100px'})
])

样式可以用 Python 字典赋值给 style,CSS 类名通过 className 指定。注意,Dash 会自动在 assets 文件夹中寻找静态资源。

核心交互组件(dcc)

from dash import dcc

dcc.Dropdown(
    options=[
        {'label': '北京', 'value': 'BJ'},
        {'label': '上海', 'value': 'SH'},
        {'label': '广州', 'value': 'GZ'}
    ],
    value='BJ',  # 默认选中值
    id='city-dropdown'
)

dcc.Slider(min=0, max=100, step=5, value=30, id='my-slider')

dcc.Input(type='text', placeholder='请输入内容', id='input-box')

dcc.Graph(id='my-chart')   # 用于显示 Plotly 图表

每一个交互组件都需要一个唯一的 id,这是连接布局和回调的桥梁。

四、回调 —— 赋予应用灵魂

当用户操作组件时,回调函数会自动执行,从而实现页面更新。通过 @app.callback 装饰器来声明依赖关系。

基础回调:单输入 → 单输出

下面是一个根据输入框内容动态更新文字的例子:

from dash import Dash, html, dcc, Input, Output

app = Dash(__name__)

app.layout = html.Div([
    dcc.Input(id='input-text', type='text', placeholder='输入一些文字...'),
    html.Div(id='output-text')
])

@app.callback(
    Output('output-text', 'children'),
    Input('input-text', 'value')
)
def update_output(value):
    if value is None:
        value = ''
    return f'你输入了:{value}'

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

· Output:指定要修改的组件属性,这里是 output-text 组件的 children 属性(即显示内容)。
· Input:指定触发回调的组件属性,每次 input-text 的 value 变化时,函数就会运行。
· 函数返回值会赋给 Output 对应的属性。

链式回调与多输入/多输出

一个回调可以有多个 Input、多个 Output,也可以多个 State。例如,根据下拉框选择和滑块数值来更新图表和统计文本:

@app.callback(
    Output('graph', 'figure'),
    Output('stats', 'children'),
    Input('city-dropdown', 'value'),
    Input('year-slider', 'value')
)
def update_graph(city, year):
    # 根据 city 和 year 过滤数据,生成图表和统计
    filtered_df = df[(df['city'] == city) & (df['year'] == year)]
    fig = px.bar(filtered_df, x='month', y='sales')
    stats = f'总销售额:{filtered_df["sales"].sum()}'
    return fig, stats

State —— 仅在需要时触发

有时你不希望在每次输入时都立即更新,而是等用户点击按钮后再读取输入值。这时用 State 替代 Input:

@app.callback(
    Output('output', 'children'),
    Input('submit-btn', 'n_clicks'),
    State('input-box', 'value')
)
def on_button_click(n_clicks, text):
    if n_clicks is None:
        return ''
    return f'提交的内容:{text}'

按钮的 n_clicks 属性记录点击次数,初始为 None。只有当按钮被点击时,回调才会触发,同时读取输入框的当前值。

五、绘制图表

Dash 内置对 Plotly 图表的完美支持。你只需在回调中返回一个 plotly.graph_objects.Figure 或 plotly.express 生成的图表对象,然后赋值给 dcc.Graph 的 figure 属性即可。

import plotly.express as px

df = px.data.iris()

app.layout = html.Div([
    dcc.Dropdown(
        id='species-dropdown',
        options=[{'label': s, 'value': s} for s in df['species'].unique()],
        value='setosa'
    ),
    dcc.Graph(id='scatter-plot')
])

@app.callback(
    Output('scatter-plot', 'figure'),
    Input('species-dropdown', 'value')
)
def make_plot(species):
    filtered = df[df['species'] == species]
    fig = px.scatter(filtered, x='sepal_width', y='sepal_length', color='species')
    return fig

Plotly 图表本身是可交互的(缩放、悬停提示、框选等),无需额外代码。

六、应用结构最佳实践

当应用变复杂时,将所有代码放在一个文件会难以维护。推荐的标准组织方式:

· app.py:初始化 Dash 实例和布局。
· callbacks.py:单独存放回调函数,用 from app import app 导入实例来注册回调。
· assets/:存放 CSS、JS、图片等静态文件。Dash 会自动加载该目录下的文件。
· 数据加载与处理可以放在单独的模块中。

示例的多文件结构:

my_dash_app/
├── app.py
├── callbacks.py
├── data.py
├── assets/
│   ├── style.css
│   └── logo.png
└── requirements.txt

app.py 的典型内容:

from dash import Dash, html, dcc
import callbacks  # 必须导入,否则回调不注册

app = Dash(__name__)
app.layout = html.Div([...])

七、进阶功能速览

  1. 使用 DataTable 展示表格

dash_table 提供了功能丰富的表格组件,支持分页、排序、过滤、编辑等。

from dash import dash_table

dash_table.DataTable(
    id='table',
    columns=[{'name': '城市', 'id': 'city'}, {'name': '销售额', 'id': 'sales'}],
    data=df.to_dict('records'),
    page_size=10,
    filter_action='native',
    sort_action='native'
)
  1. 多页面应用

Dash 2.x 支持 dash.page_container 和 dash.register_page 轻松构建多页面应用。你只需在 pages/ 文件夹下放置各页面的模块即可。

  1. 性能优化

· 使用服务端缓存 @flask_caching 或 dash-extensions 中的缓存功能。
· 对于大型数据,避免在客户端存储过多,只传输展示需要的数据。
· 图形属性中慎用过大的 figure,可以启用 plotly 的 WebGL 渲染(scattergl 等)。

  1. 自定义样式与组件

你可以通过 assets 中的 CSS 文件自由控制外观,也可以使用 dash-bootstrap-components、dash-mantine-components 等第三方组件库获得专业的外观。

八、部署

开发完成后,你可以将应用部署到各种环境:

· 内部使用:直接 app.run(host=‘0.0.0.0’),让局域网内其他设备访问。
· 生产部署:使用 Gunicorn 等 WSGI 服务器。例如 gunicorn app:server(需要暴露 Flask 服务器实例 app.server)。
· 云平台:Dash 应用在 Heroku、Render、AWS、Azure 等平台上均有成熟的部署方案。
· Dash Enterprise:Plotly 官方提供的企业级部署与协作平台。

九、学习资源

· 官方文档:dash.plotly.com 是最权威的参考,包含大量示例和图库。
· Dash 示例库:dash.gallery 展示了大量漂亮的完整应用源码。
· Plotly 图表文档:plotly.com/python/ 学习 Plotly 图表的制作。
· 社区与论坛:Dash Community Forum 提问和分享经验。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐