dash

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Dash Production Dashboard Skill

Dash生产级仪表盘技能

Build enterprise-grade interactive dashboards with Plotly Dash. Features reactive callbacks, professional layouts, and scalable deployment for production workloads.
使用Plotly Dash构建企业级交互式仪表盘。具备响应式回调、专业布局以及针对生产工作负载的可扩展部署能力。

When to Use This Skill

何时使用该技能

USE Dash when:

适合使用Dash的场景:

  • Production dashboards - Building dashboards for business users
  • Complex interactivity - Need fine-grained control over updates
  • Enterprise requirements - Authentication, scaling, reliability needed
  • Plotly ecosystem - Already using Plotly for visualizations
  • Custom components - Need to extend with JavaScript/React
  • Long-term projects - Dashboard will be maintained and extended
  • Multi-user access - Multiple concurrent users accessing dashboards
  • 生产级仪表盘 - 为业务用户构建仪表盘
  • 复杂交互 - 需要对更新进行细粒度控制
  • 企业级需求 - 需要身份验证、扩容、可靠性保障
  • Plotly生态 - 已在使用Plotly进行可视化
  • 自定义组件 - 需要通过JavaScript/React进行扩展
  • 长期项目 - 仪表盘需要维护和扩展
  • 多用户访问 - 多个并发用户访问仪表盘

DON'T USE Dash when:

不适合使用Dash的场景:

  • Quick prototypes - Use Streamlit for faster iteration
  • Simple visualizations - Static reports may suffice
  • No interactivity needed - Use static HTML/PDF reports
  • Limited Python knowledge - Steeper learning curve than Streamlit
  • Single-user tools - Jupyter notebooks may be simpler
  • 快速原型 - 使用Streamlit进行更快迭代
  • 简单可视化 - 静态报告可能足够
  • 无需交互 - 使用静态HTML/PDF报告
  • Python知识有限 - 学习曲线比Streamlit更陡峭
  • 单用户工具 - Jupyter笔记本可能更简单

Prerequisites

前置条件

bash
undefined
bash
undefined

Basic installation

基础安装

pip install dash
pip install dash

With common extras

包含常用扩展

pip install dash plotly pandas dash-bootstrap-components
pip install dash plotly pandas dash-bootstrap-components

Full installation

完整安装

pip install dash plotly pandas polars dash-bootstrap-components dash-ag-grid gunicorn
pip install dash plotly pandas polars dash-bootstrap-components dash-ag-grid gunicorn

Using uv (recommended)

使用uv(推荐)

uv pip install dash plotly pandas dash-bootstrap-components dash-ag-grid
undefined
uv pip install dash plotly pandas dash-bootstrap-components dash-ag-grid
undefined

Core Capabilities

核心功能

1. Basic Application Structure

1. 基础应用结构

Minimal Dash App:
python
from dash import Dash, html, dcc
import plotly.express as px
import pandas as pd
最简Dash应用:
python
from dash import Dash, html, dcc
import plotly.express as px
import pandas as pd

Initialize app

初始化应用

app = Dash(name)
app = Dash(name)

Sample data

示例数据

df = pd.DataFrame({ "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], "Amount": [4, 1, 2, 2, 4, 5], "City": ["SF", "SF", "SF", "NYC", "NYC", "NYC"] })
df = pd.DataFrame({ "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], "Amount": [4, 1, 2, 2, 4, 5], "City": ["SF", "SF", "SF", "NYC", "NYC", "NYC"] })

Create figure

创建图表

fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")

Layout

布局

app.layout = html.Div([ html.H1("Hello Dash"), html.P("This is a simple Dash application."), dcc.Graph(id="example-graph", figure=fig) ])
app.layout = html.Div([ html.H1("Hello Dash"), html.P("这是一个简单的Dash应用。"), dcc.Graph(id="example-graph", figure=fig) ])

Run server

启动服务器

if name == "main": app.run(debug=True)

**Run the app:**
```bash
python app.py
if name == "main": app.run(debug=True)

**运行应用:**
```bash
python app.py
undefined
undefined

2. Callbacks and Interactivity

2. 回调与交互

Basic Callback:
python
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

app = Dash(__name__)
基础回调:
python
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

app = Dash(__name__)

Sample data

示例数据

df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=100), "category": ["A", "B", "C", "D"] * 25, "value": range(100) })
df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=100), "category": ["A", "B", "C", "D"] * 25, "value": range(100) })

Layout

布局

app.layout = html.Div([ html.H1("Interactive Dashboard"),
html.Label("Select Category:"),
dcc.Dropdown(
    id="category-dropdown",
    options=[{"label": c, "value": c} for c in df["category"].unique()],
    value="A",
    clearable=False
),

dcc.Graph(id="line-chart")
])
app.layout = html.Div([ html.H1("交互式仪表盘"),
html.Label("选择类别:"),
dcc.Dropdown(
    id="category-dropdown",
    options=[{"label": c, "value": c} for c in df["category"].unique()],
    value="A",
    clearable=False
),

dcc.Graph(id="line-chart")
])

Callback

回调

@callback( Output("line-chart", "figure"), Input("category-dropdown", "value") ) def update_chart(selected_category): filtered_df = df[df["category"] == selected_category]
fig = px.line(
    filtered_df,
    x="date",
    y="value",
    title=f"Values for Category {selected_category}"
)

return fig
if name == "main": app.run(debug=True)

**Multiple Inputs and Outputs:**
```python
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

app = Dash(__name__)
@callback( Output("line-chart", "figure"), Input("category-dropdown", "value") ) def update_chart(selected_category): filtered_df = df[df["category"] == selected_category]
fig = px.line(
    filtered_df,
    x="date",
    y="value",
    title=f"类别 {selected_category} 的数值"
)

return fig
if name == "main": app.run(debug=True)

**多输入与多输出:**
```python
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

app = Dash(__name__)

Sample data

示例数据

df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=365), "category": ["A", "B", "C"] * 122 + ["A"], "region": ["North", "South", "East", "West"] * 91 + ["North"], "value": [i + (i % 30) * 10 for i in range(365)] })
app.layout = html.Div([ html.H1("Multi-Input Dashboard"),
html.Div([
    html.Div([
        html.Label("Category"),
        dcc.Dropdown(
            id="category-filter",
            options=[{"label": c, "value": c} for c in df["category"].unique()],
            value=["A", "B", "C"],
            multi=True
        )
    ], style={"width": "45%", "display": "inline-block"}),

    html.Div([
        html.Label("Region"),
        dcc.Dropdown(
            id="region-filter",
            options=[{"label": r, "value": r} for r in df["region"].unique()],
            value=["North", "South", "East", "West"],
            multi=True
        )
    ], style={"width": "45%", "display": "inline-block", "marginLeft": "5%"})
]),

html.Div([
    html.Div([
        dcc.Graph(id="trend-chart")
    ], style={"width": "60%", "display": "inline-block"}),

    html.Div([
        dcc.Graph(id="pie-chart")
    ], style={"width": "38%", "display": "inline-block", "marginLeft": "2%"})
]),

html.Div(id="summary-stats")
])
@callback( [Output("trend-chart", "figure"), Output("pie-chart", "figure"), Output("summary-stats", "children")], [Input("category-filter", "value"), Input("region-filter", "value")] ) def update_all(categories, regions): # Filter data filtered = df[ (df["category"].isin(categories)) & (df["region"].isin(regions)) ]
# Trend chart
trend = filtered.groupby("date")["value"].sum().reset_index()
trend_fig = px.line(trend, x="date", y="value", title="Value Trend")

# Pie chart
by_category = filtered.groupby("category")["value"].sum().reset_index()
pie_fig = px.pie(by_category, values="value", names="category", title="By Category")

# Summary stats
stats = html.Div([
    html.H4("Summary Statistics"),
    html.P(f"Total records: {len(filtered):,}"),
    html.P(f"Total value: {filtered['value'].sum():,}"),
    html.P(f"Average value: {filtered['value'].mean():.2f}")
])

return trend_fig, pie_fig, stats
if name == "main": app.run(debug=True)

**Chained Callbacks:**
```python
from dash import Dash, html, dcc, callback, Output, Input
import pandas as pd

app = Dash(__name__)
df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=365), "category": ["A", "B", "C"] * 122 + ["A"], "region": ["North", "South", "East", "West"] * 91 + ["North"], "value": [i + (i % 30) * 10 for i in range(365)] })
app.layout = html.Div([ html.H1("多输入仪表盘"),
html.Div([
    html.Div([
        html.Label("类别"),
        dcc.Dropdown(
            id="category-filter",
            options=[{"label": c, "value": c} for c in df["category"].unique()],
            value=["A", "B", "C"],
            multi=True
        )
    ], style={"width": "45%", "display": "inline-block"}),

    html.Div([
        html.Label("区域"),
        dcc.Dropdown(
            id="region-filter",
            options=[{"label": r, "value": r} for r in df["region"].unique()],
            value=["North", "South", "East", "West"],
            multi=True
        )
    ], style={"width": "45%", "display": "inline-block", "marginLeft": "5%"})
]),

html.Div([
    html.Div([
        dcc.Graph(id="trend-chart")
    ], style={"width": "60%", "display": "inline-block"}),

    html.Div([
        dcc.Graph(id="pie-chart")
    ], style={"width": "38%", "display": "inline-block", "marginLeft": "2%"})
]),

html.Div(id="summary-stats")
])
@callback( [Output("trend-chart", "figure"), Output("pie-chart", "figure"), Output("summary-stats", "children")], [Input("category-filter", "value"), Input("region-filter", "value")] ) def update_all(categories, regions): # 过滤数据 filtered = df[ (df["category"].isin(categories)) & (df["region"].isin(regions)) ]
# 趋势图
trend = filtered.groupby("date")["value"].sum().reset_index()
trend_fig = px.line(trend, x="date", y="value", title="数值趋势")

# 饼图
by_category = filtered.groupby("category")["value"].sum().reset_index()
pie_fig = px.pie(by_category, values="value", names="category", title="按类别统计")

# 汇总统计
stats = html.Div([
    html.H4("汇总统计"),
    html.P(f"总记录数: {len(filtered):,}"),
    html.P(f"总数值: {filtered['value'].sum():,}"),
    html.P(f"平均数值: {filtered['value'].mean():.2f}")
])

return trend_fig, pie_fig, stats
if name == "main": app.run(debug=True)

**链式回调:**
```python
from dash import Dash, html, dcc, callback, Output, Input
import pandas as pd

app = Dash(__name__)

Hierarchical data

层级数据

data = { "USA": {"California": ["San Francisco", "Los Angeles"], "Texas": ["Houston", "Dallas"]}, "Canada": {"Ontario": ["Toronto", "Ottawa"], "Quebec": ["Montreal", "Quebec City"]} }
app.layout = html.Div([ html.H1("Chained Dropdowns"),
html.Label("Country"),
dcc.Dropdown(id="country-dropdown"),

html.Label("State/Province"),
dcc.Dropdown(id="state-dropdown"),

html.Label("City"),
dcc.Dropdown(id="city-dropdown"),

html.Div(id="selection-output")
])
data = { "USA": {"California": ["San Francisco", "Los Angeles"], "Texas": ["Houston", "Dallas"]}, "Canada": {"Ontario": ["Toronto", "Ottawa"], "Quebec": ["Montreal", "Quebec City"]} }
app.layout = html.Div([ html.H1("链式下拉菜单"),
html.Label("国家"),
dcc.Dropdown(id="country-dropdown"),

html.Label("州/省"),
dcc.Dropdown(id="state-dropdown"),

html.Label("城市"),
dcc.Dropdown(id="city-dropdown"),

html.Div(id="selection-output")
])

Populate country dropdown

填充国家下拉菜单

@callback( Output("country-dropdown", "options"), Input("country-dropdown", "id") # Dummy input to trigger on load ) def set_countries(_): return [{"label": c, "value": c} for c in data.keys()]
@callback( Output("country-dropdown", "options"), Input("country-dropdown", "id") # 虚拟输入,用于加载时触发 ) def set_countries(_): return [{"label": c, "value": c} for c in data.keys()]

Update state options based on country

根据国家更新州选项

@callback( Output("state-dropdown", "options"), Output("state-dropdown", "value"), Input("country-dropdown", "value") ) def set_states(country): if country is None: return [], None states = data.get(country, {}).keys() return [{"label": s, "value": s} for s in states], None
@callback( Output("state-dropdown", "options"), Output("state-dropdown", "value"), Input("country-dropdown", "value") ) def set_states(country): if country is None: return [], None states = data.get(country, {}).keys() return [{"label": s, "value": s} for s in states], None

Update city options based on state

根据州更新城市选项

@callback( Output("city-dropdown", "options"), Output("city-dropdown", "value"), Input("country-dropdown", "value"), Input("state-dropdown", "value") ) def set_cities(country, state): if country is None or state is None: return [], None cities = data.get(country, {}).get(state, []) return [{"label": c, "value": c} for c in cities], None
@callback( Output("city-dropdown", "options"), Output("city-dropdown", "value"), Input("country-dropdown", "value"), Input("state-dropdown", "value") ) def set_cities(country, state): if country is None or state is None: return [], None cities = data.get(country, {}).get(state, []) return [{"label": c, "value": c} for c in cities], None

Display selection

显示选择结果

@callback( Output("selection-output", "children"), Input("country-dropdown", "value"), Input("state-dropdown", "value"), Input("city-dropdown", "value") ) def display_selection(country, state, city): return f"Selected: {country or '-'} > {state or '-'} > {city or '-'}"
if name == "main": app.run(debug=True)
undefined
@callback( Output("selection-output", "children"), Input("country-dropdown", "value"), Input("state-dropdown", "value"), Input("city-dropdown", "value") ) def display_selection(country, state, city): return f"已选择: {country or '-'} > {state or '-'} > {city or '-'}"
if name == "main": app.run(debug=True)
undefined

3. Layout Components

3. 布局组件

HTML Components:
python
from dash import html
HTML组件:
python
from dash import html

Text elements

文本元素

layout = html.Div([ html.H1("Main Title"), html.H2("Subtitle"), html.H3("Section Header"), html.P("Paragraph text with ", html.Strong("bold"), " and ", html.Em("italic")), html.Hr(), # Horizontal rule html.Br(), # Line break
# Lists
html.Ul([
    html.Li("Item 1"),
    html.Li("Item 2"),
    html.Li("Item 3")
]),

# Links
html.A("Click here", href="https://example.com", target="_blank"),

# Images
html.Img(src="/assets/logo.png", style={"width": "200px"}),

# Tables
html.Table([
    html.Thead([
        html.Tr([html.Th("Name"), html.Th("Value")])
    ]),
    html.Tbody([
        html.Tr([html.Td("Item 1"), html.Td("100")]),
        html.Tr([html.Td("Item 2"), html.Td("200")])
    ])
])
])

**Core Components (dcc):**
```python
from dash import dcc
layout = html.Div([ html.H1("主标题"), html.H2("副标题"), html.H3("章节标题"), html.P("段落文本包含 ", html.Strong("粗体"), " 和 ", html.Em("斜体")), html.Hr(), # 水平线 html.Br(), # 换行
# 列表
html.Ul([
    html.Li("项目1"),
    html.Li("项目2"),
    html.Li("项目3")
]),

# 链接
html.A("点击这里", href="https://example.com", target="_blank"),

# 图片
html.Img(src="/assets/logo.png", style={"width": "200px"}),

# 表格
html.Table([
    html.Thead([
        html.Tr([html.Th("名称"), html.Th("数值")])
    ]),
    html.Tbody([
        html.Tr([html.Td("项目1"), html.Td("100")]),
        html.Tr([html.Td("项目2"), html.Td("200")])
    ])
])
])

**核心组件(dcc):**
```python
from dash import dcc

Input components

输入组件

components = html.Div([ # Dropdown dcc.Dropdown( id="dropdown", options=[ {"label": "Option A", "value": "a"}, {"label": "Option B", "value": "b"}, {"label": "Option C", "value": "c", "disabled": True} ], value="a", multi=False, clearable=True, searchable=True, placeholder="Select..." ),
# Multi-select dropdown
dcc.Dropdown(
    id="multi-dropdown",
    options=[{"label": f"Option {i}", "value": i} for i in range(10)],
    value=[1, 2, 3],
    multi=True
),

# Slider
dcc.Slider(
    id="slider",
    min=0,
    max=100,
    step=5,
    value=50,
    marks={0: "0", 25: "25", 50: "50", 75: "75", 100: "100"}
),

# Range slider
dcc.RangeSlider(
    id="range-slider",
    min=0,
    max=100,
    step=1,
    value=[20, 80],
    marks={i: str(i) for i in range(0, 101, 20)}
),

# Input
dcc.Input(
    id="text-input",
    type="text",
    placeholder="Enter text...",
    debounce=True  # Wait for typing to stop
),

# Textarea
dcc.Textarea(
    id="textarea",
    placeholder="Enter longer text...",
    style={"width": "100%", "height": "100px"}
),

# Checklist
dcc.Checklist(
    id="checklist",
    options=[
        {"label": "Option 1", "value": "1"},
        {"label": "Option 2", "value": "2"},
        {"label": "Option 3", "value": "3"}
    ],
    value=["1"],
    inline=True
),

# Radio items
dcc.RadioItems(
    id="radio",
    options=[
        {"label": "Small", "value": "s"},
        {"label": "Medium", "value": "m"},
        {"label": "Large", "value": "l"}
    ],
    value="m",
    inline=True
),

# Date picker
dcc.DatePickerSingle(
    id="date-picker",
    date="2025-01-01",
    display_format="YYYY-MM-DD"
),

# Date range picker
dcc.DatePickerRange(
    id="date-range",
    start_date="2025-01-01",
    end_date="2025-12-31",
    display_format="YYYY-MM-DD"
),

# Upload
dcc.Upload(
    id="upload",
    children=html.Div(["Drag and Drop or ", html.A("Select Files")]),
    style={
        "width": "100%",
        "height": "60px",
        "lineHeight": "60px",
        "borderWidth": "1px",
        "borderStyle": "dashed",
        "borderRadius": "5px",
        "textAlign": "center"
    }
),

# Tabs
dcc.Tabs(id="tabs", value="tab-1", children=[
    dcc.Tab(label="Tab 1", value="tab-1"),
    dcc.Tab(label="Tab 2", value="tab-2")
]),

# Loading indicator
dcc.Loading(
    id="loading",
    type="default",  # default, graph, cube, circle, dot
    children=html.Div(id="loading-output")
),

# Interval (for periodic updates)
dcc.Interval(
    id="interval-component",
    interval=1000,  # milliseconds
    n_intervals=0
),

# Store (client-side data storage)
dcc.Store(id="data-store", storage_type="session"),  # memory, session, local

# Graph
dcc.Graph(
    id="graph",
    config={
        "displayModeBar": True,
        "displaylogo": False,
        "modeBarButtonsToRemove": ["lasso2d", "select2d"]
    }
)
])
undefined
components = html.Div([ # 下拉菜单 dcc.Dropdown( id="dropdown", options=[ {"label": "选项A", "value": "a"}, {"label": "选项B", "value": "b"}, {"label": "选项C", "value": "c", "disabled": True} ], value="a", multi=False, clearable=True, searchable=True, placeholder="选择..." ),
# 多选下拉菜单
dcc.Dropdown(
    id="multi-dropdown",
    options=[{"label": f"选项{i}", "value": i} for i in range(10)],
    value=[1, 2, 3],
    multi=True
),

# 滑块
dcc.Slider(
    id="slider",
    min=0,
    max=100,
    step=5,
    value=50,
    marks={0: "0", 25: "25", 50: "50", 75: "75", 100: "100"}
),

# 范围滑块
dcc.RangeSlider(
    id="range-slider",
    min=0,
    max=100,
    step=1,
    value=[20, 80],
    marks={i: str(i) for i in range(0, 101, 20)}
),

# 输入框
dcc.Input(
    id="text-input",
    type="text",
    placeholder="输入文本...",
    debounce=True  # 等待输入停止后触发
),

# 文本域
dcc.Textarea(
    id="textarea",
    placeholder="输入较长文本...",
    style={"width": "100%", "height": "100px"}
),

# 复选框
dcc.Checklist(
    id="checklist",
    options=[
        {"label": "选项1", "value": "1"},
        {"label": "选项2", "value": "2"},
        {"label": "选项3", "value": "3"}
    ],
    value=["1"],
    inline=True
),

# 单选按钮
dcc.RadioItems(
    id="radio",
    options=[
        {"label": "小", "value": "s"},
        {"label": "中", "value": "m"},
        {"label": "大", "value": "l"}
    ],
    value="m",
    inline=True
),

# 日期选择器
dcc.DatePickerSingle(
    id="date-picker",
    date="2025-01-01",
    display_format="YYYY-MM-DD"
),

# 日期范围选择器
dcc.DatePickerRange(
    id="date-range",
    start_date="2025-01-01",
    end_date="2025-12-31",
    display_format="YYYY-MM-DD"
),

# 文件上传
dcc.Upload(
    id="upload",
    children=html.Div(["拖拽文件或 ", html.A("选择文件")]),
    style={
        "width": "100%",
        "height": "60px",
        "lineHeight": "60px",
        "borderWidth": "1px",
        "borderStyle": "dashed",
        "borderRadius": "5px",
        "textAlign": "center"
    }
),

# 标签页
dcc.Tabs(id="tabs", value="tab-1", children=[
    dcc.Tab(label="标签页1", value="tab-1"),
    dcc.Tab(label="标签页2", value="tab-2")
]),

# 加载指示器
dcc.Loading(
    id="loading",
    type="default",  # default, graph, cube, circle, dot
    children=html.Div(id="loading-output")
),

# 定时器(用于周期性更新)
dcc.Interval(
    id="interval-component",
    interval=1000,  # 毫秒
    n_intervals=0
),

# 存储(客户端数据存储)
dcc.Store(id="data-store", storage_type="session"),  # memory, session, local

# 图表
dcc.Graph(
    id="graph",
    config={
        "displayModeBar": True,
        "displaylogo": False,
        "modeBarButtonsToRemove": ["lasso2d", "select2d"]
    }
)
])
undefined

4. Bootstrap Components

4. Bootstrap组件

Using Dash Bootstrap Components:
python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
使用Dash Bootstrap Components:
python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd

Initialize with Bootstrap theme

使用Bootstrap主题初始化

app = Dash(name, external_stylesheets=[dbc.themes.BOOTSTRAP])
app = Dash(name, external_stylesheets=[dbc.themes.BOOTSTRAP])

Sample data

示例数据

df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=100), "sales": [100 + i * 2 + (i % 7) * 10 for i in range(100)], "orders": [50 + i + (i % 5) * 5 for i in range(100)] })
df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=100), "sales": [100 + i * 2 + (i % 7) * 10 for i in range(100)], "orders": [50 + i + (i % 5) * 5 for i in range(100)] })

Layout with Bootstrap components

使用Bootstrap组件的布局

app.layout = dbc.Container([ # Header dbc.Row([ dbc.Col([ html.H1("Sales Dashboard", className="text-primary"), html.P("Interactive analytics powered by Dash", className="lead") ]) ], className="mb-4"),
# Metrics row
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("Total Sales", className="card-title"),
                html.H2(f"${df['sales'].sum():,}", className="text-success")
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("Total Orders", className="card-title"),
                html.H2(f"{df['orders'].sum():,}", className="text-info")
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("Avg Order Value", className="card-title"),
                html.H2(f"${df['sales'].sum() / df['orders'].sum():.2f}", className="text-warning")
            ])
        ])
    ], md=4)
], className="mb-4"),

# Filters
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Filters"),
            dbc.CardBody([
                dbc.Label("Date Range"),
                dcc.DatePickerRange(
                    id="date-range",
                    start_date=df["date"].min(),
                    end_date=df["date"].max(),
                    className="mb-3"
                ),
                dbc.Label("Metric"),
                dcc.Dropdown(
                    id="metric-dropdown",
                    options=[
                        {"label": "Sales", "value": "sales"},
                        {"label": "Orders", "value": "orders"}
                    ],
                    value="sales"
                )
            ])
        ])
    ], md=3),
    dbc.Col([
        dcc.Graph(id="main-chart")
    ], md=9)
]),

# Tabs
dbc.Row([
    dbc.Col([
        dbc.Tabs([
            dbc.Tab(label="Daily Data", tab_id="daily"),
            dbc.Tab(label="Summary", tab_id="summary")
        ], id="tabs", active_tab="daily"),
        html.Div(id="tab-content", className="mt-3")
    ])
], className="mt-4")
], fluid=True)
@callback( Output("main-chart", "figure"), [Input("date-range", "start_date"), Input("date-range", "end_date"), Input("metric-dropdown", "value")] ) def update_chart(start_date, end_date, metric): filtered = df[ (df["date"] >= start_date) & (df["date"] <= end_date) ]
fig = px.line(
    filtered,
    x="date",
    y=metric,
    title=f"{metric.title()} Over Time"
)
fig.update_layout(template="plotly_white")

return fig
@callback( Output("tab-content", "children"), Input("tabs", "active_tab") ) def render_tab(tab): if tab == "daily": return dbc.Table.from_dataframe( df.tail(10), striped=True, bordered=True, hover=True ) elif tab == "summary": return html.Div([ html.P(f"Total Records: {len(df)}"), html.P(f"Date Range: {df['date'].min()} to {df['date'].max()}"), html.P(f"Sales Range: ${df['sales'].min()} - ${df['sales'].max()}") ])
if name == "main": app.run(debug=True)
undefined
app.layout = dbc.Container([ # 头部 dbc.Row([ dbc.Col([ html.H1("销售仪表盘", className="text-primary"), html.P("由Dash驱动的交互式分析", className="lead") ]) ], className="mb-4"),
# 指标行
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("总销售额", className="card-title"),
                html.H2(f"${df['sales'].sum():,}", className="text-success")
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("总订单数", className="card-title"),
                html.H2(f"{df['orders'].sum():,}", className="text-info")
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H4("平均订单价值", className="card-title"),
                html.H2(f"${df['sales'].sum() / df['orders'].sum():.2f}", className="text-warning")
            ])
        ])
    ], md=4)
], className="mb-4"),

# 过滤器
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("过滤器"),
            dbc.CardBody([
                dbc.Label("日期范围"),
                dcc.DatePickerRange(
                    id="date-range",
                    start_date=df["date"].min(),
                    end_date=df["date"].max(),
                    className="mb-3"
                ),
                dbc.Label("指标"),
                dcc.Dropdown(
                    id="metric-dropdown",
                    options=[
                        {"label": "销售额", "value": "sales"},
                        {"label": "订单数", "value": "orders"}
                    ],
                    value="sales"
                )
            ])
        ])
    ], md=3),
    dbc.Col([
        dcc.Graph(id="main-chart")
    ], md=9)
]),

# 标签页
dbc.Row([
    dbc.Col([
        dbc.Tabs([
            dbc.Tab(label="每日数据", tab_id="daily"),
            dbc.Tab(label="汇总", tab_id="summary")
        ], id="tabs", active_tab="daily"),
        html.Div(id="tab-content", className="mt-3")
    ])
], className="mt-4")
], fluid=True)
@callback( Output("main-chart", "figure"), [Input("date-range", "start_date"), Input("date-range", "end_date"), Input("metric-dropdown", "value")] ) def update_chart(start_date, end_date, metric): filtered = df[ (df["date"] >= start_date) & (df["date"] <= end_date) ]
fig = px.line(
    filtered,
    x="date",
    y=metric,
    title=f"{metric.title()} 趋势"
)
fig.update_layout(template="plotly_white")

return fig
@callback( Output("tab-content", "children"), Input("tabs", "active_tab") ) def render_tab(tab): if tab == "daily": return dbc.Table.from_dataframe( df.tail(10), striped=True, bordered=True, hover=True ) elif tab == "summary": return html.Div([ html.P(f"总记录数: {len(df)}"), html.P(f"日期范围: {df['date'].min()} 至 {df['date'].max()}"), html.P(f"销售额范围: ${df['sales'].min()} - ${df['sales'].max()}") ])
if name == "main": app.run(debug=True)
undefined

5. Multi-Page Applications

5. 多页面应用

Project Structure:
my_dash_app/
├── app.py              # Main entry point
├── pages/
│   ├── __init__.py
│   ├── home.py
│   ├── analytics.py
│   └── settings.py
├── components/
│   ├── __init__.py
│   ├── navbar.py
│   └── footer.py
├── utils/
│   ├── __init__.py
│   └── data.py
└── assets/
    ├── style.css
    └── logo.png
Main App (app.py):
python
from dash import Dash, html, dcc, page_container
import dash_bootstrap_components as dbc

app = Dash(
    __name__,
    use_pages=True,
    external_stylesheets=[dbc.themes.BOOTSTRAP]
)
项目结构:
my_dash_app/
├── app.py              # 主入口
├── pages/
│   ├── __init__.py
│   ├── home.py
│   ├── analytics.py
│   └── settings.py
├── components/
│   ├── __init__.py
│   ├── navbar.py
│   └── footer.py
├── utils/
│   ├── __init__.py
│   └── data.py
└── assets/
    ├── style.css
    └── logo.png
主应用(app.py):
python
from dash import Dash, html, dcc, page_container
import dash_bootstrap_components as dbc

app = Dash(
    __name__,
    use_pages=True,
    external_stylesheets=[dbc.themes.BOOTSTRAP]
)

Navbar

导航栏

navbar = dbc.NavbarSimple( children=[ dbc.NavItem(dbc.NavLink("Home", href="/")), dbc.NavItem(dbc.NavLink("Analytics", href="/analytics")), dbc.NavItem(dbc.NavLink("Settings", href="/settings")), ], brand="My Dashboard", brand_href="/", color="primary", dark=True, )
navbar = dbc.NavbarSimple( children=[ dbc.NavItem(dbc.NavLink"首页", href="/"), dbc.NavItem(dbc.NavLink"分析", href="/analytics"), dbc.NavItem(dbc.NavLink"设置", href="/settings"), ], brand="我的仪表盘", brand_href="/", color="primary", dark=True, )

Layout with navigation and page container

包含导航和页面容器的布局

app.layout = html.Div([ navbar, dbc.Container([ page_container ], fluid=True, className="mt-4") ])
if name == "main": app.run(debug=True)

**Home Page (pages/home.py):**
```python
from dash import html, register_page
import dash_bootstrap_components as dbc

register_page(__name__, path="/", name="Home")

layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            html.H1("Welcome to the Dashboard"),
            html.P("Select a page from the navigation bar to get started."),
            dbc.Card([
                dbc.CardBody([
                    html.H4("Quick Links"),
                    dbc.ListGroup([
                        dbc.ListGroupItem("Analytics", href="/analytics"),
                        dbc.ListGroupItem("Settings", href="/settings")
                    ])
                ])
            ])
        ])
    ])
])
Analytics Page (pages/analytics.py):
python
from dash import html, dcc, callback, Output, Input, register_page
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd

register_page(__name__, path="/analytics", name="Analytics")
app.layout = html.Div([ navbar, dbc.Container([ page_container ], fluid=True, className="mt-4") ])
if name == "main": app.run(debug=True)

**首页(pages/home.py):**
```python
from dash import html, register_page
import dash_bootstrap_components as dbc

register_page(__name__, path="/", name="Home")

layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            html.H1("欢迎来到仪表盘"),
            html.P("从导航栏选择页面开始使用。"),
            dbc.Card([
                dbc.CardBody([
                    html.H4("快速链接"),
                    dbc.ListGroup([
                        dbc.ListGroupItem("分析", href="/analytics"),
                        dbc.ListGroupItem("设置", href="/settings")
                    ])
                ])
            ])
        ])
    ])
])
分析页面(pages/analytics.py):
python
from dash import html, dcc, callback, Output, Input, register_page
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd

register_page(__name__, path="/analytics", name="Analytics")

Generate sample data

生成示例数据

df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=365), "value": [100 + i + (i % 30) * 5 for i in range(365)] })
layout = dbc.Container([ html.H1("Analytics"),
dbc.Row([
    dbc.Col([
        dbc.Label("Chart Type"),
        dcc.Dropdown(
            id="chart-type",
            options=[
                {"label": "Line", "value": "line"},
                {"label": "Bar", "value": "bar"},
                {"label": "Area", "value": "area"}
            ],
            value="line"
        )
    ], md=4)
], className="mb-4"),

dcc.Graph(id="analytics-chart")
])
@callback( Output("analytics-chart", "figure"), Input("chart-type", "value") ) def update_chart(chart_type): if chart_type == "line": fig = px.line(df, x="date", y="value") elif chart_type == "bar": monthly = df.resample("M", on="date")["value"].sum().reset_index() fig = px.bar(monthly, x="date", y="value") else: fig = px.area(df, x="date", y="value")
return fig
undefined
df = pd.DataFrame({ "date": pd.date_range("2025-01-01", periods=365), "value": [100 + i + (i % 30) * 5 for i in range(365)] })
layout = dbc.Container([ html.H1("分析"),
dbc.Row([
    dbc.Col([
        dbc.Label("图表类型"),
        dcc.Dropdown(
            id="chart-type",
            options=[
                {"label": "折线图", "value": "line"},
                {"label": "柱状图", "value": "bar"},
                {"label": "面积图", "value": "area"}
            ],
            value="line"
        )
    ], md=4)
], className="mb-4"),

dcc.Graph(id="analytics-chart")
])
@callback( Output("analytics-chart", "figure"), Input("chart-type", "value") ) def update_chart(chart_type): if chart_type == "line": fig = px.line(df, x="date", y="value") elif chart_type == "bar": monthly = df.resample("M", on="date")["value"].sum().reset_index() fig = px.bar(monthly, x="date", y="value") else: fig = px.area(df, x="date", y="value")
return fig
undefined

6. Authentication

6. 身份验证

Basic Authentication:
python
from dash import Dash, html, dcc
import dash_auth

app = Dash(__name__)
基础身份验证:
python
from dash import Dash, html, dcc
import dash_auth

app = Dash(__name__)

Basic authentication

基础身份验证

VALID_USERNAME_PASSWORD_PAIRS = { "admin": "admin123", "user": "user123" }
auth = dash_auth.BasicAuth( app, VALID_USERNAME_PASSWORD_PAIRS )
app.layout = html.Div([ html.H1("Protected Dashboard"), html.P("You are authenticated!") ])
if name == "main": app.run(debug=True)

**Custom Login (with session):**
```python
from dash import Dash, html, dcc, callback, Output, Input, State
import dash_bootstrap_components as dbc
from flask import session

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.server.secret_key = "your-secret-key-here"
VALID_USERNAME_PASSWORD_PAIRS = { "admin": "admin123", "user": "user123" }
auth = dash_auth.BasicAuth( app, VALID_USERNAME_PASSWORD_PAIRS )
app.layout = html.Div([ html.H1("受保护的仪表盘"), html.P("您已通过身份验证!") ])
if name == "main": app.run(debug=True)

**自定义登录(带会话):**
```python
from dash import Dash, html, dcc, callback, Output, Input, State
import dash_bootstrap_components as dbc
from flask import session

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.server.secret_key = "your-secret-key-here"

Login form

登录表单

login_form = dbc.Card([ dbc.CardBody([ html.H4("Login"), dbc.Input(id="username", placeholder="Username", className="mb-2"), dbc.Input(id="password", type="password", placeholder="Password", className="mb-2"), dbc.Button("Login", id="login-btn", color="primary"), html.Div(id="login-message") ]) ], style={"maxWidth": "400px", "margin": "100px auto"})
login_form = dbc.Card([ dbc.CardBody([ html.H4("登录"), dbc.Input(id="username", placeholder="用户名", className="mb-2"), dbc.Input(id="password", type="password", placeholder="密码", className="mb-2"), dbc.Button("登录", id="login-btn", color="primary"), html.Div(id="login-message") ]) ], style={"maxWidth": "400px", "margin": "100px auto"})

Main content

主内容

main_content = html.Div([ html.H1("Dashboard"), html.P("Welcome! You are logged in."), dbc.Button("Logout", id="logout-btn", color="secondary") ])
app.layout = html.Div([ dcc.Location(id="url"), html.Div(id="page-content") ])
@callback( Output("page-content", "children"), Input("url", "pathname") ) def display_page(pathname): if session.get("authenticated"): return main_content return login_form
@callback( [Output("login-message", "children"), Output("url", "pathname")], Input("login-btn", "n_clicks"), [State("username", "value"), State("password", "value")], prevent_initial_call=True ) def login(n_clicks, username, password): # Simple validation (use proper auth in production) if username == "admin" and password == "admin123": session["authenticated"] = True return "", "/" return dbc.Alert("Invalid credentials", color="danger"), "/"
@callback( Output("url", "pathname", allow_duplicate=True), Input("logout-btn", "n_clicks"), prevent_initial_call=True ) def logout(n_clicks): session.clear() return "/"
if name == "main": app.run(debug=True)
undefined
main_content = html.Div([ html.H1("仪表盘"), html.P("欢迎!您已登录。"), dbc.Button("退出登录", id="logout-btn", color="secondary") ])
app.layout = html.Div([ dcc.Location(id="url"), html.Div(id="page-content") ])
@callback( Output("page-content", "children"), Input("url", "pathname") ) def display_page(pathname): if session.get("authenticated"): return main_content return login_form
@callback( [Output("login-message", "children"), Output("url", "pathname")], Input("login-btn", "n_clicks"), [State("username", "value"), State("password", "value")], prevent_initial_call=True ) def login(n_clicks, username, password): # 简单验证(生产环境请使用正规身份验证) if username == "admin" and password == "admin123": session["authenticated"] = True return "", "/" return dbc.Alert("无效的凭据", color="danger"), "/"
@callback( Output("url", "pathname", allow_duplicate=True), Input("logout-btn", "n_clicks"), prevent_initial_call=True ) def logout(n_clicks): session.clear() return "/"
if name == "main": app.run(debug=True)
undefined

Complete Examples

完整示例

Example 1: Sales Analytics Dashboard

示例1:销售分析仪表盘

python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

Initialize app

初始化应用

app = Dash(name, external_stylesheets=[dbc.themes.FLATLY])
app = Dash(name, external_stylesheets=[dbc.themes.FLATLY])

Generate sample data

生成示例数据

np.random.seed(42) dates = pd.date_range("2024-01-01", "2025-12-31", freq="D") n_days = len(dates)
df = pd.DataFrame({ "date": dates, "revenue": np.cumsum(np.random.randn(n_days) * 100 + 500), "orders": np.random.poisson(100, n_days), "customers": np.random.poisson(80, n_days), "region": np.random.choice(["North", "South", "East", "West"], n_days), "category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], n_days) })
np.random.seed(42) dates = pd.date_range("2024-01-01", "2025-12-31", freq="D") n_days = len(dates)
df = pd.DataFrame({ "date": dates, "revenue": np.cumsum(np.random.randn(n_days) * 100 + 500), "orders": np.random.poisson(100, n_days), "customers": np.random.poisson(80, n_days), "region": np.random.choice(["North", "South", "East", "West"], n_days), "category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], n_days) })

Calculate previous period metrics

计算上期指标

current_revenue = df[df["date"] >= "2025-01-01"]["revenue"].sum() prev_revenue = df[df["date"] < "2025-01-01"]["revenue"].sum() revenue_change = ((current_revenue - prev_revenue) / prev_revenue * 100)
current_revenue = df[df["date"] >= "2025-01-01"]["revenue"].sum() prev_revenue = df[df["date"] < "2025-01-01"]["revenue"].sum() revenue_change = ((current_revenue - prev_revenue) / prev_revenue * 100)

Layout

布局

app.layout = dbc.Container([ # Header dbc.Row([ dbc.Col([ html.H1("Sales Analytics Dashboard", className="text-primary mb-0"), html.P(f"Last updated: {datetime.now().strftime('%Y-%m-%d %H:%M')}", className="text-muted") ], md=8), dbc.Col([ dbc.ButtonGroup([ dbc.Button("Export", outline=True, color="primary"), dbc.Button("Refresh", outline=True, color="secondary") ]) ], md=4, className="text-end") ], className="mb-4 mt-3"),
# Date filter
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                dbc.Row([
                    dbc.Col([
                        dbc.Label("Date Range"),
                        dcc.DatePickerRange(
                            id="date-filter",
                            start_date="2025-01-01",
                            end_date="2025-12-31",
                            display_format="YYYY-MM-DD"
                        )
                    ], md=4),
                    dbc.Col([
                        dbc.Label("Region"),
                        dcc.Dropdown(
                            id="region-filter",
                            options=[{"label": r, "value": r} for r in df["region"].unique()],
                            value=df["region"].unique().tolist(),
                            multi=True
                        )
                    ], md=4),
                    dbc.Col([
                        dbc.Label("Category"),
                        dcc.Dropdown(
                            id="category-filter",
                            options=[{"label": c, "value": c} for c in df["category"].unique()],
                            value=df["category"].unique().tolist(),
                            multi=True
                        )
                    ], md=4)
                ])
            ])
        ])
    ])
], className="mb-4"),

# KPI Cards
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Total Revenue", className="text-muted"),
                html.H3(id="kpi-revenue", className="text-success"),
                html.Small(id="kpi-revenue-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Total Orders", className="text-muted"),
                html.H3(id="kpi-orders", className="text-info"),
                html.Small(id="kpi-orders-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Unique Customers", className="text-muted"),
                html.H3(id="kpi-customers", className="text-warning"),
                html.Small(id="kpi-customers-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Avg Order Value", className="text-muted"),
                html.H3(id="kpi-aov", className="text-primary"),
                html.Small(id="kpi-aov-change", className="text-muted")
            ])
        ], color="light")
    ], md=3)
], className="mb-4"),

# Charts Row 1
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Revenue Trend"),
            dbc.CardBody([
                dcc.Graph(id="revenue-trend")
            ])
        ])
    ], md=8),
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Revenue by Category"),
            dbc.CardBody([
                dcc.Graph(id="category-pie")
            ])
        ])
    ], md=4)
], className="mb-4"),

# Charts Row 2
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Regional Performance"),
            dbc.CardBody([
                dcc.Graph(id="regional-bar")
            ])
        ])
    ], md=6),
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Orders vs Customers"),
            dbc.CardBody([
                dcc.Graph(id="scatter-chart")
            ])
        ])
    ], md=6)
], className="mb-4"),

# Data Table
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("Detailed Data"),
            dbc.CardBody([
                html.Div(id="data-table")
            ])
        ])
    ])
])
], fluid=True)
app.layout = dbc.Container([ # 头部 dbc.Row([ dbc.Col([ html.H1("销售分析仪表盘", className="text-primary mb-0"), html.P(f"最后更新: {datetime.now().strftime('%Y-%m-%d %H:%M')}", className="text-muted") ], md=8), dbc.Col([ dbc.ButtonGroup([ dbc.Button("导出", outline=True, color="primary"), dbc.Button("刷新", outline=True, color="secondary") ]) ], md=4, className="text-end") ], className="mb-4 mt-3"),
# 日期过滤器
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                dbc.Row([
                    dbc.Col([
                        dbc.Label("日期范围"),
                        dcc.DatePickerRange(
                            id="date-filter",
                            start_date="2025-01-01",
                            end_date="2025-12-31",
                            display_format="YYYY-MM-DD"
                        )
                    ], md=4),
                    dbc.Col([
                        dbc.Label("区域"),
                        dcc.Dropdown(
                            id="region-filter",
                            options=[{"label": r, "value": r} for r in df["region"].unique()],
                            value=df["region"].unique().tolist(),
                            multi=True
                        )
                    ], md=4),
                    dbc.Col([
                        dbc.Label("类别"),
                        dcc.Dropdown(
                            id="category-filter",
                            options=[{"label": c, "value": c} for c in df["category"].unique()],
                            value=df["category"].unique().tolist(),
                            multi=True
                        )
                    ], md=4)
                ])
            ])
        ])
    ])
], className="mb-4"),

# KPI卡片
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("总销售额", className="text-muted"),
                html.H3(id="kpi-revenue", className="text-success"),
                html.Small(id="kpi-revenue-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("总订单数", className="text-muted"),
                html.H3(id="kpi-orders", className="text-info"),
                html.Small(id="kpi-orders-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("独立客户数", className="text-muted"),
                html.H3(id="kpi-customers", className="text-warning"),
                html.Small(id="kpi-customers-change", className="text-muted")
            ])
        ], color="light")
    ], md=3),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("平均订单价值", className="text-muted"),
                html.H3(id="kpi-aov", className="text-primary"),
                html.Small(id="kpi-aov-change", className="text-muted")
            ])
        ], color="light")
    ], md=3)
], className="mb-4"),

# 图表行1
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("销售额趋势"),
            dbc.CardBody([
                dcc.Graph(id="revenue-trend")
            ])
        ])
    ], md=8),
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("按类别销售额"),
            dbc.CardBody([
                dcc.Graph(id="category-pie")
            ])
        ])
    ], md=4)
], className="mb-4"),

# 图表行2
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("区域表现"),
            dbc.CardBody([
                dcc.Graph(id="regional-bar")
            ])
        ])
    ], md=6),
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("订单数 vs 客户数"),
            dbc.CardBody([
                dcc.Graph(id="scatter-chart")
            ])
        ])
    ], md=6)
], className="mb-4"),

# 数据表格
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("详细数据"),
            dbc.CardBody([
                html.Div(id="data-table")
            ])
        ])
    ])
])
], fluid=True)

Callbacks

回调

@callback( [Output("kpi-revenue", "children"), Output("kpi-orders", "children"), Output("kpi-customers", "children"), Output("kpi-aov", "children"), Output("revenue-trend", "figure"), Output("category-pie", "figure"), Output("regional-bar", "figure"), Output("scatter-chart", "figure"), Output("data-table", "children")], [Input("date-filter", "start_date"), Input("date-filter", "end_date"), Input("region-filter", "value"), Input("category-filter", "value")] ) def update_dashboard(start_date, end_date, regions, categories): # Filter data filtered = df[ (df["date"] >= start_date) & (df["date"] <= end_date) & (df["region"].isin(regions)) & (df["category"].isin(categories)) ]
# KPIs
revenue = f"${filtered['revenue'].sum():,.0f}"
orders = f"{filtered['orders'].sum():,}"
customers = f"{filtered['customers'].sum():,}"
aov = f"${filtered['revenue'].sum() / filtered['orders'].sum():.2f}" if filtered['orders'].sum() > 0 else "$0"

# Revenue trend
daily_revenue = filtered.groupby("date")["revenue"].sum().reset_index()
trend_fig = px.line(
    daily_revenue,
    x="date",
    y="revenue",
    title=None
)
trend_fig.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    hovermode="x unified"
)

# Category pie
by_category = filtered.groupby("category")["revenue"].sum().reset_index()
pie_fig = px.pie(
    by_category,
    values="revenue",
    names="category",
    title=None
)
pie_fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))

# Regional bar
by_region = filtered.groupby("region").agg({
    "revenue": "sum",
    "orders": "sum"
}).reset_index()
bar_fig = px.bar(
    by_region,
    x="region",
    y="revenue",
    color="region",
    title=None
)
bar_fig.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    showlegend=False
)

# Scatter
scatter_fig = px.scatter(
    filtered.groupby("date").agg({"orders": "sum", "customers": "sum"}).reset_index(),
    x="orders",
    y="customers",
    title=None,
    trendline="ols"
)
scatter_fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))

# Table
table = dbc.Table.from_dataframe(
    filtered.groupby(["region", "category"]).agg({
        "revenue": "sum",
        "orders": "sum",
        "customers": "sum"
    }).reset_index().round(2),
    striped=True,
    bordered=True,
    hover=True,
    responsive=True
)

return revenue, orders, customers, aov, trend_fig, pie_fig, bar_fig, scatter_fig, table
if name == "main": app.run(debug=True)
undefined
@callback( [Output("kpi-revenue", "children"), Output("kpi-orders", "children"), Output("kpi-customers", "children"), Output("kpi-aov", "children"), Output("revenue-trend", "figure"), Output("category-pie", "figure"), Output("regional-bar", "figure"), Output("scatter-chart", "figure"), Output("data-table", "children")], [Input("date-filter", "start_date"), Input("date-filter", "end_date"), Input("region-filter", "value"), Input("category-filter", "value")] ) def update_dashboard(start_date, end_date, regions, categories): # 过滤数据 filtered = df[ (df["date"] >= start_date) & (df["date"] <= end_date) & (df["region"].isin(regions)) & (df["category"].isin(categories)) ]
# KPIs
revenue = f"${filtered['revenue'].sum():,.0f}"
orders = f"{filtered['orders'].sum():,}"
customers = f"{filtered['customers'].sum():,}"
aov = f"${filtered['revenue'].sum() / filtered['orders'].sum():.2f}" if filtered['orders'].sum() > 0 else "$0"

# 销售额趋势
daily_revenue = filtered.groupby("date")["revenue"].sum().reset_index()
trend_fig = px.line(
    daily_revenue,
    x="date",
    y="revenue",
    title=None
)
trend_fig.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    hovermode="x unified"
)

# 类别饼图
by_category = filtered.groupby("category")["revenue"].sum().reset_index()
pie_fig = px.pie(
    by_category,
    values="revenue",
    names="category",
    title=None
)
pie_fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))

# 区域柱状图
by_region = filtered.groupby("region").agg({
    "revenue": "sum",
    "orders": "sum"
}).reset_index()
bar_fig = px.bar(
    by_region,
    x="region",
    y="revenue",
    color="region",
    title=None
)
bar_fig.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    showlegend=False
)

# 散点图
scatter_fig = px.scatter(
    filtered.groupby("date").agg({"orders": "sum", "customers": "sum"}).reset_index(),
    x="orders",
    y="customers",
    title=None,
    trendline="ols"
)
scatter_fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))

# 表格
table = dbc.Table.from_dataframe(
    filtered.groupby(["region", "category"]).agg({
        "revenue": "sum",
        "orders": "sum",
        "customers": "sum"
    }).reset_index().round(2),
    striped=True,
    bordered=True,
    hover=True,
    responsive=True
)

return revenue, orders, customers, aov, trend_fig, pie_fig, bar_fig, scatter_fig, table
if name == "main": app.run(debug=True)
undefined

Example 2: Real-Time Monitoring Dashboard

示例2:实时监控仪表盘

python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from collections import deque
import random
from datetime import datetime

app = Dash(__name__, external_stylesheets=[dbc.themes.CYBORG])
python
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from collections import deque
import random
from datetime import datetime

app = Dash(__name__, external_stylesheets=[dbc.themes.CYBORG])

Initialize data stores

初始化数据存储

MAX_POINTS = 50 time_data = deque(maxlen=MAX_POINTS) cpu_data = deque(maxlen=MAX_POINTS) memory_data = deque(maxlen=MAX_POINTS) network_data = deque(maxlen=MAX_POINTS)
MAX_POINTS = 50 time_data = deque(maxlen=MAX_POINTS) cpu_data = deque(maxlen=MAX_POINTS) memory_data = deque(maxlen=MAX_POINTS) network_data = deque(maxlen=MAX_POINTS)

Layout

布局

app.layout = dbc.Container([ html.H1("Real-Time System Monitor", className="text-center my-4"),
# Status indicators
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("CPU Usage"),
                html.H2(id="cpu-value", className="text-info"),
                dbc.Progress(id="cpu-progress", value=0, max=100)
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Memory Usage"),
                html.H2(id="memory-value", className="text-warning"),
                dbc.Progress(id="memory-progress", value=0, max=100)
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("Network I/O"),
                html.H2(id="network-value", className="text-success"),
                dbc.Progress(id="network-progress", value=0, max=100)
            ])
        ])
    ], md=4)
], className="mb-4"),

# Charts
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("System Metrics (Last 50 Updates)"),
            dbc.CardBody([
                dcc.Graph(id="live-graph", animate=True)
            ])
        ])
    ])
]),

# Interval component for updates
dcc.Interval(
    id="interval-component",
    interval=1000,  # 1 second
    n_intervals=0
)
], fluid=True)
@callback( [Output("cpu-value", "children"), Output("memory-value", "children"), Output("network-value", "children"), Output("cpu-progress", "value"), Output("memory-progress", "value"), Output("network-progress", "value"), Output("live-graph", "figure")], Input("interval-component", "n_intervals") ) def update_metrics(n): # Simulate metrics cpu = random.uniform(20, 80) memory = random.uniform(40, 90) network = random.uniform(10, 60)
# Update data stores
time_data.append(datetime.now())
cpu_data.append(cpu)
memory_data.append(memory)
network_data.append(network)

# Create figure
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(cpu_data),
    name="CPU",
    mode="lines",
    line=dict(color="#17a2b8")
))

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(memory_data),
    name="Memory",
    mode="lines",
    line=dict(color="#ffc107")
))

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(network_data),
    name="Network",
    mode="lines",
    line=dict(color="#28a745")
))

fig.update_layout(
    template="plotly_dark",
    paper_bgcolor="rgba(0,0,0,0)",
    plot_bgcolor="rgba(0,0,0,0)",
    yaxis=dict(range=[0, 100], title="Usage %"),
    xaxis=dict(title="Time"),
    legend=dict(orientation="h", yanchor="bottom", y=1.02),
    margin=dict(l=50, r=20, t=30, b=50),
    uirevision="constant"  # Preserve zoom/pan on update
)

return (
    f"{cpu:.1f}%",
    f"{memory:.1f}%",
    f"{network:.1f}%",
    cpu,
    memory,
    network,
    fig
)
if name == "main": app.run(debug=True)
undefined
app.layout = dbc.Container([ html.H1("实时系统监控", className="text-center my-4"),
# 状态指示器
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("CPU使用率"),
                html.H2(id="cpu-value", className="text-info"),
                dbc.Progress(id="cpu-progress", value=0, max=100)
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("内存使用率"),
                html.H2(id="memory-value", className="text-warning"),
                dbc.Progress(id="memory-progress", value=0, max=100)
            ])
        ])
    ], md=4),
    dbc.Col([
        dbc.Card([
            dbc.CardBody([
                html.H6("网络I/O"),
                html.H2(id="network-value", className="text-success"),
                dbc.Progress(id="network-progress", value=0, max=100)
            ])
        ])
    ], md=4)
], className="mb-4"),

# 图表
dbc.Row([
    dbc.Col([
        dbc.Card([
            dbc.CardHeader("系统指标(最近50次更新)"),
            dbc.CardBody([
                dcc.Graph(id="live-graph", animate=True)
            ])
        ])
    ])
]),

# 用于更新的定时器组件
dcc.Interval(
    id="interval-component",
    interval=1000,  # 1秒
    n_intervals=0
)
], fluid=True)
@callback( [Output("cpu-value", "children"), Output("memory-value", "children"), Output("network-value", "children"), Output("cpu-progress", "value"), Output("memory-progress", "value"), Output("network-progress", "value"), Output("live-graph", "figure")], Input("interval-component", "n_intervals") ) def update_metrics(n): # 模拟指标 cpu = random.uniform(20, 80) memory = random.uniform(40, 90) network = random.uniform(10, 60)
# 更新数据存储
time_data.append(datetime.now())
cpu_data.append(cpu)
memory_data.append(memory)
network_data.append(network)

# 创建图表
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(cpu_data),
    name="CPU",
    mode="lines",
    line=dict(color="#17a2b8")
))

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(memory_data),
    name="内存",
    mode="lines",
    line=dict(color="#ffc107")
))

fig.add_trace(go.Scatter(
    x=list(time_data),
    y=list(network_data),
    name="网络",
    mode="lines",
    line=dict(color="#28a745")
))

fig.update_layout(
    template="plotly_dark",
    paper_bgcolor="rgba(0,0,0,0)",
    plot_bgcolor="rgba(0,0,0,0)",
    yaxis=dict(range=[0, 100], title="使用率 %"),
    xaxis=dict(title="时间"),
    legend=dict(orientation="h", yanchor="bottom", y=1.02),
    margin=dict(l=50, r=20, t=30, b=50),
    uirevision="constant"  # 更新时保留缩放/平移状态
)

return (
    f"{cpu:.1f}%",
    f"{memory:.1f}%",
    f"{network:.1f}%",
    cpu,
    memory,
    network,
    fig
)
if name == "main": app.run(debug=True)
undefined

Example 3: Data Table with AG Grid

示例3:带AG Grid的数据表格

python
from dash import Dash, html, callback, Output, Input
import dash_ag_grid as dag
import dash_bootstrap_components as dbc
import pandas as pd
import numpy as np

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
python
from dash import Dash, html, callback, Output, Input
import dash_ag_grid as dag
import dash_bootstrap_components as dbc
import pandas as pd
import numpy as np

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

Generate sample data

生成示例数据

np.random.seed(42) df = pd.DataFrame({ "ID": range(1, 1001), "Name": [f"Product {i}" for i in range(1, 1001)], "Category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], 1000), "Price": np.random.uniform(10, 500, 1000).round(2), "Stock": np.random.randint(0, 100, 1000), "Rating": np.random.uniform(1, 5, 1000).round(1), "Last Updated": pd.date_range("2025-01-01", periods=1000, freq="H") })
np.random.seed(42) df = pd.DataFrame({ "ID": range(1, 1001), "Name": [f"Product {i}" for i in range(1, 1001)], "Category": np.random.choice(["Electronics", "Clothing", "Food", "Home"], 1000), "Price": np.random.uniform(10, 500, 1000).round(2), "Stock": np.random.randint(0, 100, 1000), "Rating": np.random.uniform(1, 5, 1000).round(1), "Last Updated": pd.date_range("2025-01-01", periods=1000, freq="H") })

Column definitions

列定义

column_defs = [ {"field": "ID", "filter": "agNumberColumnFilter", "width": 80}, {"field": "Name", "filter": "agTextColumnFilter"}, { "field": "Category", "filter": "agSetColumnFilter", "cellStyle": {"fontWeight": "bold"} }, { "field": "Price", "filter": "agNumberColumnFilter", "valueFormatter": {"function": "'$' + params.value.toFixed(2)"}, "cellStyle": { "function": "params.value > 300 ? {'color': 'red'} : {'color': 'green'}" } }, { "field": "Stock", "filter": "agNumberColumnFilter", "cellStyle": { "function": "params.value < 10 ? {'backgroundColor': '#ffcccc'} : {}" } }, { "field": "Rating", "filter": "agNumberColumnFilter", "cellRenderer": "agSparklineCellRenderer", "cellRendererParams": { "sparklineOptions": { "type": "bar", "fill": "#5470c6" } } }, { "field": "Last Updated", "filter": "agDateColumnFilter", "valueFormatter": {"function": "new Date(params.value).toLocaleDateString()"} } ]
column_defs = [ {"field": "ID", "filter": "agNumberColumnFilter", "width": 80}, {"field": "Name", "filter": "agTextColumnFilter"}, { "field": "Category", "filter": "agSetColumnFilter", "cellStyle": {"fontWeight": "bold"} }, { "field": "Price", "filter": "agNumberColumnFilter", "valueFormatter": {"function": "'$' + params.value.toFixed(2)"}, "cellStyle": { "function": "params.value > 300 ? {'color': 'red'} : {'color': 'green'}" } }, { "field": "Stock", "filter": "agNumberColumnFilter", "cellStyle": { "function": "params.value < 10 ? {'backgroundColor': '#ffcccc'} : {}" } }, { "field": "Rating", "filter": "agNumberColumnFilter", "cellRenderer": "agSparklineCellRenderer", "cellRendererParams": { "sparklineOptions": { "type": "bar", "fill": "#5470c6" } } }, { "field": "Last Updated", "filter": "agDateColumnFilter", "valueFormatter": {"function": "new Date(params.value).toLocaleDateString()"} } ]

Layout

布局

app.layout = dbc.Container([ html.H1("Product Inventory", className="my-4"),
dbc.Row([
    dbc.Col([
        dbc.Input(
            id="search-input",
            placeholder="Quick search...",
            className="mb-3"
        )
    ], md=4),
    dbc.Col([
        dbc.Button("Export CSV", id="export-btn", color="primary")
    ], md=2)
]),

dag.AgGrid(
    id="inventory-grid",
    columnDefs=column_defs,
    rowData=df.to_dict("records"),
    defaultColDef={
        "sortable": True,
        "filter": True,
        "resizable": True,
        "floatingFilter": True
    },
    dashGridOptions={
        "pagination": True,
        "paginationPageSize": 20,
        "rowSelection": "multiple",
        "animateRows": True
    },
    style={"height": "600px"}
),

html.Div(id="selection-output", className="mt-3")
], fluid=True)
@callback( Output("inventory-grid", "dashGridOptions"), Input("search-input", "value") ) def update_search(search_value): return { "pagination": True, "paginationPageSize": 20, "rowSelection": "multiple", "animateRows": True, "quickFilterText": search_value }
@callback( Output("selection-output", "children"), Input("inventory-grid", "selectedRows") ) def display_selection(selected): if selected: return dbc.Alert( f"Selected {len(selected)} items. Total value: ${sum(r['Price'] for r in selected):,.2f}", color="info" ) return ""
if name == "main": app.run(debug=True)
undefined
app.layout = dbc.Container([ html.H1("产品库存", className="my-4"),
dbc.Row([
    dbc.Col([
        dbc.Input(
            id="search-input",
            placeholder="快速搜索...",
            className="mb-3"
        )
    ], md=4),
    dbc.Col([
        dbc.Button("导出CSV", id="export-btn", color="primary")
    ], md=2)
]),

dag.AgGrid(
    id="inventory-grid",
    columnDefs=column_defs,
    rowData=df.to_dict("records"),
    defaultColDef={
        "sortable": True,
        "filter": True,
        "resizable": True,
        "floatingFilter": True
    },
    dashGridOptions={
        "pagination": True,
        "paginationPageSize": 20,
        "rowSelection": "multiple",
        "animateRows": True
    },
    style={"height": "600px"}
),

html.Div(id="selection-output", className="mt-3")
], fluid=True)
@callback( Output("inventory-grid", "dashGridOptions"), Input("search-input", "value") ) def update_search(search_value): return { "pagination": True, "paginationPageSize": 20, "rowSelection": "multiple", "animateRows": True, "quickFilterText": search_value }
@callback( Output("selection-output", "children"), Input("inventory-grid", "selectedRows") ) def display_selection(selected): if selected: return dbc.Alert( f"已选择 {len(selected)} 个项目。总价值: ${sum(r['Price'] for r in selected):,.2f}", color="info" ) return ""
if name == "main": app.run(debug=True)
undefined

Deployment Patterns

部署模式

Gunicorn Production Server

Gunicorn生产服务器

python
undefined
python
undefined

wsgi.py

wsgi.py

from app import app
server = app.server
if name == "main": server.run()

```bash
from app import app
server = app.server
if name == "main": server.run()

```bash

Run with Gunicorn

使用Gunicorn运行

gunicorn wsgi:server -b 0.0.0.0:8050 -w 4
undefined
gunicorn wsgi:server -b 0.0.0.0:8050 -w 4
undefined

Docker Deployment

Docker部署

dockerfile
undefined
dockerfile
undefined

Dockerfile

Dockerfile

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8050
CMD ["gunicorn", "wsgi:server", "-b", "0.0.0.0:8050", "-w", "4"]

```yaml
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8050
CMD ["gunicorn", "wsgi:server", "-b", "0.0.0.0:8050", "-w", "4"]

```yaml

docker-compose.yml

docker-compose.yml

version: "3.8" services: dash: build: . ports: - "8050:8050" environment: - DASH_DEBUG=false restart: unless-stopped
undefined
version: "3.8" services: dash: build: . ports: - "8050:8050" environment: - DASH_DEBUG=false restart: unless-stopped
undefined

Cloud Deployment (Heroku)

云部署(Heroku)

txt
undefined
txt
undefined

Procfile

Procfile

web: gunicorn wsgi:server
web: gunicorn wsgi:server

requirements.txt

requirements.txt

dash>=2.14.0 dash-bootstrap-components>=1.5.0 plotly>=5.18.0 pandas>=2.0.0 gunicorn>=21.0.0
undefined
dash>=2.14.0 dash-bootstrap-components>=1.5.0 plotly>=5.18.0 pandas>=2.0.0 gunicorn>=21.0.0
undefined

Best Practices

最佳实践

1. Optimize Callback Performance

1. 优化回调性能

python
undefined
python
undefined

Use prevent_initial_call when appropriate

适当使用prevent_initial_call

@callback( Output("output", "children"), Input("button", "n_clicks"), prevent_initial_call=True ) def handle_click(n_clicks): return f"Clicked {n_clicks} times"
@callback( Output("output", "children"), Input("button", "n_clicks"), prevent_initial_call=True ) def handle_click(n_clicks): return f"点击了 {n_clicks} 次"

Use State for non-triggering inputs

对非触发输入使用State

@callback( Output("output", "children"), Input("submit-btn", "n_clicks"), State("input-field", "value") # Doesn't trigger callback ) def submit_form(n_clicks, value): return f"Submitted: {value}"
undefined
@callback( Output("output", "children"), Input("submit-btn", "n_clicks"), State("input-field", "value") # 不会触发回调 ) def submit_form(n_clicks, value): return f"已提交: {value}"
undefined

2. Efficient Data Loading

2. 高效数据加载

python
undefined
python
undefined

Cache expensive computations

缓存昂贵的计算

from flask_caching import Cache
cache = Cache(app.server, config={"CACHE_TYPE": "simple"})
@cache.memoize(timeout=300) def load_data(): return pd.read_parquet("large_file.parquet")
undefined
from flask_caching import Cache
cache = Cache(app.server, config={"CACHE_TYPE": "simple"})
@cache.memoize(timeout=300) def load_data(): return pd.read_parquet("large_file.parquet")
undefined

3. Modular Callbacks

3. 模块化回调

python
undefined
python
undefined

Separate callbacks into modules

将回调分离到模块中

callbacks/analytics.py

callbacks/analytics.py

from dash import callback, Output, Input
def register_callbacks(app): @callback( Output("chart", "figure"), Input("dropdown", "value") ) def update_chart(value): return create_figure(value)
undefined
from dash import callback, Output, Input
def register_callbacks(app): @callback( Output("chart", "figure"), Input("dropdown", "value") ) def update_chart(value): return create_figure(value)
undefined

4. Error Handling

4. 错误处理

python
from dash import callback, Output, Input
from dash.exceptions import PreventUpdate

@callback(
    Output("output", "children"),
    Input("input", "value")
)
def safe_callback(value):
    if value is None:
        raise PreventUpdate

    try:
        result = process(value)
        return result
    except Exception as e:
        return html.Div(f"Error: {str(e)}", className="text-danger")
python
from dash import callback, Output, Input
from dash.exceptions import PreventUpdate

@callback(
    Output("output", "children"),
    Input("input", "value")
)
def safe_callback(value):
    if value is None:
        raise PreventUpdate

    try:
        result = process(value)
        return result
    except Exception as e:
        return html.Div(f"错误: {str(e)}", className="text-danger")

Troubleshooting

故障排除

Common Issues

常见问题

Issue: Callback not firing
python
undefined
问题:回调未触发
python
undefined

Check component IDs match exactly

检查组件ID是否完全匹配

Verify Input/Output/State decorators

验证Input/Output/State装饰器

Check for circular dependencies

检查是否存在循环依赖


**Issue: Slow initial load**
```python

**问题:初始加载缓慢**
```python

Use loading states

使用加载状态

dcc.Loading( children=[dcc.Graph(id="graph")], type="circle" )

**Issue: Memory leaks**
```python
dcc.Loading( children=[dcc.Graph(id="graph")], type="circle" )

**问题:内存泄漏**
```python

Clear caches periodically

定期清理缓存

Use background callbacks for long operations

对长时间运行的操作使用后台回调

Limit data in client-side stores

限制客户端存储中的数据量


**Issue: Multiple callback outputs**
```python

**问题:多个回调输出**
```python

Use allow_duplicate=True for same output

对同一输出使用allow_duplicate=True

@callback( Output("output", "children", allow_duplicate=True), Input("button2", "n_clicks"), prevent_initial_call=True )
undefined
@callback( Output("output", "children", allow_duplicate=True), Input("button2", "n_clicks"), prevent_initial_call=True )
undefined

Version History

版本历史

  • 1.0.0 (2026-01-17): Initial release
    • Core application structure
    • Callbacks and interactivity
    • Layout components (HTML, DCC, Bootstrap)
    • Multi-page applications
    • Authentication patterns
    • Complete dashboard examples
    • Real-time monitoring example
    • AG Grid integration
    • Deployment patterns
    • Best practices and troubleshooting
  • 1.0.0 (2026-01-17): 初始版本
    • 核心应用结构
    • 回调与交互
    • 布局组件(HTML、DCC、Bootstrap)
    • 多页面应用
    • 身份验证模式
    • 完整仪表盘示例
    • 实时监控示例
    • AG Grid集成
    • 部署模式
    • 最佳实践与故障排除

Resources

资源