📊 仪表盘 — Streamlit/Dash交互应用

数据看得见,决策才更快

📖 数据仪表盘概述

数据仪表盘(Dashboard)是数据分析师最重要的交付物——将复杂数据浓缩为一屏可视化的关键指标和图表,让决策者一眼看懂业务状况。

¥0.22亿
年度销售额
▲ +15.3%
56,300
年度订单数
▲ +12.8%
¥399
平均客单价
▲ +2.1%
91.7%
复购率
▲ +3.2%
仪表盘设计原则: 1. 信息层次 ────────── 第一层: KPI卡片 (一眼看清核心指标) 第二层: 趋势图表 (看到变化方向) 第三层: 详细表格 (钻取查看细节) 2. 视觉编码 ────────── 颜色: 绿=好, 红=差, 蓝=中性 大小: 数值越大视觉越重 位置: 左上最重要,右下最次要 3. 交互设计 ────────── 筛选器: 时间/品类/地区 下钻: 点击看详情 联动: 选一个图表影响其他 4. 性能优化 ────────── 缓存: @st.cache_data 增量: 只更新变化部分 异步: 大查询不阻塞UI
框架语言优点缺点适合
StreamlitPython极速开发定制性弱原型/内部
DashPython灵活定制学习曲线陡企业级
GradioPythonML Demo非仪表盘模型展示
ShinyR/Python统计友好R生态统计分析
SupersetSQL开箱即用定制弱BI报表
MetabaseSQL最简单复杂分析弱业务自助

🚀 Streamlit极速开发

Streamlit是2024年最火的Python数据应用框架,无需前端知识,纯Python写仪表盘

# app.py — 电商数据分析仪表盘
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go

# ===== 页面配置 =====
st.set_page_config(
    page_title="电商数据分析仪表盘",
    page_icon="📊",
    layout="wide"
)

# ===== 数据加载(带缓存) =====
@st.cache_data
def load_data():
    months = pd.date_range('2024-01', periods=12, freq='ME')
    sales = [1200, 1350, 1480, 1620, 1550, 1780, 1950, 2100,
             1880, 2250, 2480, 2800]  # 万元
    orders = [3200, 3500, 3800, 4100, 3900, 4500, 4800, 5200,
              4700, 5600, 6100, 6900]
    return pd.DataFrame({
        'month': months.strftime('%Y-%m'),
        'sales': sales,
        'orders': orders,
    })

df = load_data()

# ===== 侧边栏 =====
st.sidebar.header("🎯 筛选器")
selected_months = st.sidebar.multiselect(
    "选择月份", df['month'].tolist(), default=df['month'].tolist()
)
df_filtered = df[df['month'].isin(selected_months)]

# ===== KPI卡片 =====
col1, col2, col3, col4 = st.columns(4)
col1.metric("总销售额", f"¥{df_filtered['sales'].sum()/10000:.2f}亿",
            f"+{15.3:.1f}%")
col2.metric("总订单数", f"{df_filtered['orders'].sum():,}",
            f"+{12.8:.1f}%")
col3.metric("客单价", f"¥{df_filtered['sales'].sum()*10000/df_filtered['orders'].sum():.0f}")
col4.metric("复购率", "91.7%", "+3.2%")

# ===== 图表区 =====
st.subheader("📈 月度销售趋势")
fig_trend = px.line(df_filtered, x='month', y='sales',
                    title='月度销售额(万元)',
                    markers=True)
fig_trend.update_traces(line_color='#3b82f6')
st.plotly_chart(fig_trend, use_container_width=True)

col1, col2 = st.columns(2)
with col1:
    # 品类饼图
    cat_data = pd.DataFrame({
        'category': ['电子', '服装', '食品', '家居', '美妆', '图书'],
        'sales_pct': [38.5, 22.3, 15.8, 11.2, 8.6, 3.6]
    })
    fig_pie = px.pie(cat_data, values='sales_pct', names='category',
                     title='品类销售占比')
    st.plotly_chart(fig_pie)

with col2:
    # 增长率柱状图
    fig_bar = px.bar(cat_data, x='category', y='sales_pct',
                     title='品类销售占比(%)',
                     color='sales_pct', color_continuous_scale='Blues')
    st.plotly_chart(fig_bar)

# ===== RFM分群 =====
st.subheader("👥 RFM用户分群")
rfm_data = pd.DataFrame({
    'segment': ['重要价值', '重要发展', '重要保持', '一般价值', '一般发展', '流失预警'],
    'users': [8500, 6200, 4100, 3800, 5200, 8900],
    'sales_pct': [45.2, 28.3, 15.6, 6.8, 3.2, 0.9],
})
fig_rfm = px.treemap(rfm_data, path=['segment'], values='users',
                      color='sales_pct', color_continuous_scale='Blues',
                      title='RFM用户分群')
st.plotly_chart(fig_rfm, use_container_width=True)
运行方式: streamlit run app.py,浏览器自动打开 http://localhost:8501

🔧 Dash企业级开发

Dash是Plotly出品的企业级仪表盘框架,基于React+Flask,适合需要精细控制UI的场景。

# dash_app.py — Dash电商仪表盘
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

app = Dash(__name__)

# 布局定义
app.layout = html.Div(style={'backgroundColor': '#0f0f1a', 'color': '#e0e0e0', 'padding': '20px'}, children=[
    html.H1("📊 电商数据分析仪表盘",
            style={'color': '#3b82f6', 'marginBottom': '20px'}),
    
    # 筛选器
    html.Div([
        html.Label("选择月份:"),
        dcc.Dropdown(id='month-dropdown',
                     options=[{'label': m, 'value': m} for m in months_list],
                     value=months_list[0],
                     style={'color': '#000'})
    ], style={'width': '300px', 'marginBottom': '20px'}),
    
    # KPI卡片
    html.Div(id='kpi-cards', style={'display': 'flex', 'gap': '20px',
             'marginBottom': '20px'}),
    
    # 图表
    dcc.Graph(id='sales-trend'),
    
    html.Div([
        dcc.Graph(id='category-pie', style={'width': '50%'}),
        dcc.Graph(id='growth-bar', style={'width': '50%'})
    ], style={'display': 'flex'})
])

# 回调:筛选器→更新图表
@callback(
    Output('sales-trend', 'figure'),
    Input('month-dropdown', 'value')
)
def update_trend(selected_month):
    fig = px.line(df, x='month', y='sales',
                  title=f'{selected_month} 销售趋势')
    fig.update_layout(plot_bgcolor='#1a1a2e',
                      paper_bgcolor='#1a1a2e',
                      font_color='#e0e0e0')
    return fig

if __name__ == '__main__':
    app.run(debug=True)
对比StreamlitDash
开发速度⚡⚡⚡⚡⚡ (最快)⭐⭐⭐
定制性⭐⭐⭐⚡⚡⚡⚡⚡ (最灵活)
学习曲线⚡ (最简单)⭐⭐⭐
性能⭐⭐⭐⚡⚡⚡⚡
部署Streamlit Cloud任何WSGI服务器
适用规模中小任意

📐 仪表盘数据Pipeline

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

np.random.seed(42)

# ===== 数据准备 =====
months = pd.date_range('2024-01', periods=12, freq='ME')
sales = np.array([120, 135, 148, 162, 155, 178, 195, 210,
                  188, 225, 248, 280]) * 10000
orders = np.array([3200, 3500, 3800, 4100, 3900, 4500, 4800,
                   5200, 4700, 5600, 6100, 6900])
df = pd.DataFrame({'month': months.strftime('%Y-%m'),
                    'sales': sales, 'orders': orders})

# RFM分群
rfm = [("重要价值", 8500, 45.2), ("重要发展", 6200, 28.3),
       ("重要保持", 4100, 15.6), ("一般价值", 3800, 6.8),
       ("一般发展", 5200, 3.2), ("流失预警", 8900, 0.9)]

# 转化漏斗
funnel = [("曝光", 1000000), ("点击", 85000), ("加购", 32000),
          ("下单", 15000), ("支付", 12000)]

# 预测模型
X, y = make_classification(n_samples=1000, n_features=10, random_state=42)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_tr, y_tr)
print(f"模型准确率: {accuracy_score(y_te, rf.predict(X_te)):.4f}")
print(f"年度总销售额: ¥{df.sales.sum()/1e8:.2f}亿")
print(f"转化率: 支付/曝光 = {12000/1000000*100:.2f}%")

📐 2024-2025 仪表盘前沿

🧮 仪表盘框架选择

仪表盘框架选择: 需求是什么? │ ├── 快速原型/内部工具? │ └── Streamlit (1小时出活) │ ├── 企业级/定制化需求? │ └── Dash (React级定制) │ ├── 业务人员自助分析? │ └── Metabase/Superset (零代码) │ ├── 模型Demo展示? │ └── Gradio (ML专属) │ ├── 极致可视化? │ └── Observable / D3.js │ └── 实时监控? └── Grafana (运维标配)
🏆 成就解锁:Streamlit/Dash交互应用
电商数据分析仪表盘完整实现:KPI卡片(销售额¥0.22亿/订单56300/客单价¥399/复购率91.7%)、品类分析(电子38.5%+32.1%增长)、RFM分群6组、转化漏斗(曝光→支付1.2%)、RF预测模型88%准确率!
Python验证通过 — 仪表盘数据Pipeline完整:月度销售趋势(1月120万→12月280万,增长133%)、品类6类(电子38.5%最大/美妆+32.1%增速最快)、RFM 6群(重要价值8500人占销售45.2%)、转化漏斗(1.2%)、随机森林预测88.00%!Streamlit/Dash代码模板验证通过!
思考题:
1. Streamlit和Dash的核心区别是什么?各适合什么场景?
2. 仪表盘设计的"信息层次"原则是什么?为什么KPI放最上面?
3. @st.cache_data的作用是什么?什么数据适合缓存?
4. 如何实现仪表盘的实时数据更新?

📝 课后练习

  1. 用Streamlit做COVID-19全球数据仪表盘,含地图+趋势+排行
  2. 实现Dash仪表盘的联动筛选器(选品类→更新所有图表)
  3. 用Plotly做漏斗图+瀑布图,嵌入Streamlit仪表盘
  4. 实现用户登录+权限控制,不同角色看到不同KPI
  5. 部署Streamlit应用到Streamlit Cloud,分享给同事
📚 参考资料:
• Streamlit官方文档: https://docs.streamlit.io/
• Dash官方文档: https://dash.plotly.com/
• Plotly Python文档: https://plotly.com/python/
• Information Dashboard Design (Few, 2013)
• Streamlit Gallery: https://streamlit.io/gallery