Python脚本数据仪表盘Dash如何搭建

wen 实用脚本 2

本文目录导读:

Python脚本数据仪表盘Dash如何搭建

  1. 基础环境搭建
  2. 完整仪表盘示例
  3. 高级功能实现
  4. 性能优化技巧
  5. 部署建议

我来详细介绍如何使用Python的Dash框架搭建数据仪表盘。

基础环境搭建

安装依赖

pip install dash pandas plotly

基础Dash应用模板

import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
# 初始化Dash应用
app = dash.Dash(__name__)
server = app.server  # 用于部署
# 应用布局
app.layout = html.Div([
    html.H1("数据仪表盘", style={'text-align': 'center'}),
    # 下拉选择器
    dcc.Dropdown(
        id='data-selector',
        options=[
            {'label': '数据A', 'value': 'A'},
            {'label': '数据B', 'value': 'B'}
        ],
        value='A'
    ),
    # 图表容器
    dcc.Graph(id='main-chart')
])
if __name__ == '__main__':
    app.run_server(debug=True)

完整仪表盘示例

多图表仪表盘

import dash
from dash import dcc, html, dash_table
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# 生成示例数据
def generate_data():
    dates = pd.date_range('2023-01-01', periods=100, freq='D')
    df = pd.DataFrame({
        'date': dates,
        'value': np.random.randn(100).cumsum(),
        'category': np.random.choice(['A', 'B', 'C'], 100),
        'region': np.random.choice(['North', 'South', 'East', 'West'], 100)
    })
    return df
df = generate_data()
# 初始化应用
app = dash.Dash(__name__)
# 布局设计
app.layout = html.Div([
    html.Div([
        html.H1("销售数据仪表盘", style={'color': '#2c3e50', 'text-align': 'center'})
    ], style={'padding': '20px', 'background-color': '#ecf0f1'}),
    # 控制面板
    html.Div([
        html.Div([
            html.Label("选择地区:"),
            dcc.Dropdown(
                id='region-dropdown',
                options=[{'label': '全部', 'value': 'all'}] + 
                        [{'label': r, 'value': r} for r in df['region'].unique()],
                value='all',
                style={'width': '200px'}
            )
        ], style={'display': 'inline-block', 'margin': '10px'}),
        html.Div([
            html.Label("选择日期范围:"),
            dcc.DatePickerRange(
                id='date-picker',
                start_date=df['date'].min(),
                end_date=df['date'].max(),
                display_format='YYYY-MM-DD'
            )
        ], style={'display': 'inline-block', 'margin': '10px'})
    ], style={'padding': '20px', 'background-color': '#f8f9fa'}),
    # KPI指标
    html.Div([
        html.Div([
            html.H3("总销售额"),
            html.H2(id='total-sales', style={'color': '#27ae60'})
        ], className='kpi-card'),
        html.Div([
            html.H3("平均销售额"),
            html.H2(id='avg-sales', style={'color': '#2980b9'})
        ], className='kpi-card'),
        html.Div([
            html.H3("最高销售额"),
            html.H2(id='max-sales', style={'color': '#e74c3c'})
        ], className='kpi-card')
    ], style={'display': 'flex', 'justify-content': 'space-around', 'margin': '20px'}),
    # 图表区域
    html.Div([
        html.Div([
            dcc.Graph(id='line-chart')
        ], style={'width': '48%', 'display': 'inline-block'}),
        html.Div([
            dcc.Graph(id='bar-chart')
        ], style={'width': '48%', 'display': 'inline-block'})
    ]),
    # 数据表格
    html.Div([
        dash_table.DataTable(
            id='data-table',
            columns=[{"name": i, "id": i} for i in df.columns],
            style_table={'overflowX': 'auto'},
            style_cell={'textAlign': 'left'},
            style_header={'backgroundColor': '#f8f9fa', 'fontWeight': 'bold'}
        )
    ], style={'margin': '20px'})
], style={'font-family': 'Arial, sans-serif'})
# 回调函数
@app.callback(
    [Output('total-sales', 'children'),
     Output('avg-sales', 'children'),
     Output('max-sales', 'children'),
     Output('line-chart', 'figure'),
     Output('bar-chart', 'figure'),
     Output('data-table', 'data')],
    [Input('region-dropdown', 'value'),
     Input('date-picker', 'start_date'),
     Input('date-picker', 'end_date')]
)
def update_dashboard(region, start_date, end_date):
    # 过滤数据
    filtered_df = df.copy()
    if region != 'all':
        filtered_df = filtered_df[filtered_df['region'] == region]
    filtered_df = filtered_df[
        (filtered_df['date'] >= start_date) & 
        (filtered_df['date'] <= end_date)
    ]
    # 计算KPI
    total_sales = f"${filtered_df['value'].sum():,.2f}"
    avg_sales = f"${filtered_df['value'].mean():,.2f}"
    max_sales = f"${filtered_df['value'].max():,.2f}"
    # 创建折线图
    line_fig = px.line(
        filtered_df, 
        x='date', 
        y='value', 
        color='category',
        title='销售趋势',
        template='plotly_white'
    )
    # 创建柱状图
    bar_fig = px.bar(
        filtered_df.groupby('region')['value'].sum().reset_index(),
        x='region',
        y='value',
        title='各地区销售额',
        template='plotly_white',
        color='region'
    )
    # 准备表格数据
    table_data = filtered_df.to_dict('records')
    return total_sales, avg_sales, max_sales, line_fig, bar_fig, table_data
if __name__ == '__main__':
    app.run_server(debug=True, port=8050)

高级功能实现

实时数据更新

import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import random
from collections import deque
# 实时数据仪表盘
app = dash.Dash(__name__)
# 存储实时数据
X = deque(maxlen=20)
Y = deque(maxlen=20)
X.append(0)
Y.append(0)
app.layout = html.Div([
    dcc.Graph(id='live-graph'),
    dcc.Interval(
        id='graph-update',
        interval=1000  # 毫秒
    ),
])
@app.callback(
    Output('live-graph', 'figure'),
    [Input('graph-update', 'n_intervals')]
)
def update_graph(n):
    # 生成新数据点
    X.append(X[-1] + 1)
    Y.append(Y[-1] + random.uniform(-1, 1))
    # 创建图表
    trace = go.Scatter(
        x=list(X),
        y=list(Y),
        mode='lines+markers',
        name='实时数据',
        line=dict(color='blue', width=2)
    )
    return {
        'data': [trace],
        'layout': go.Layout(
            xaxis=dict(range=[min(X), max(X)]),
            yaxis=dict(range=[min(Y), max(Y)]),
            title='实时数据监控',
            uirevision='same'  # 保持图表状态
        )
    }

主题定制和CSS样式

# 在app初始化时添加外部CSS
app = dash.Dash(__name__)
# 自定义CSS
app.index_string = '''
<!DOCTYPE html>
<html>
    <head>
        {%metas%}
        <title>{%title%}</title>
        {%favicon%}
        {%css%}
        <style>
            .kpi-card {
                background: white;
                border-radius: 10px;
                padding: 20px;
                box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                text-align: center;
                min-width: 200px;
                margin: 10px;
            }
            .kpi-card h3 {
                color: #7f8c8d;
                margin-bottom: 10px;
                font-size: 14px;
                text-transform: uppercase;
            }
            .kpi-card h2 {
                margin: 0;
                font-size: 32px;
            }
            .dashboard-header {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 20px;
                border-radius: 10px;
                margin-bottom: 20px;
            }
        </style>
    </head>
    <body>
        {%app_entry%}
        <footer>
            {%config%}
            {%scripts%}
            {%renderer%}
        </footer>
    </body>
</html>
'''

性能优化技巧

数据缓存

import dash
from flask_caching import Cache
app = dash.Dash(__name__)
cache = Cache(app.server, config={
    'CACHE_TYPE': 'filesystem',
    'CACHE_DIR': 'cache-directory'
})
@cache.memoize(timeout=60)
def expensive_data_processing():
    # 处理耗时数据
    return processed_data

懒加载

# 使用dcc.Loading组件
app.layout = html.Div([
    dcc.Loading(
        id="loading",
        type="circle",  # 'graph', 'cube', 'circle', 'dot'
        children=[
            dcc.Graph(id="slow-graph")
        ]
    )
])

部署建议

生产环境配置

if __name__ == '__main__':
    # 开发环境
    app.run_server(debug=True, host='0.0.0.0', port=8050)
    # 生产环境建议使用Gunicorn
    # gunicorn app:server -b 0.0.0.0:8050 -w 4

这个框架提供了完整的Dash仪表盘搭建方案,你可以根据具体需求进行修改和扩展,记得根据实际数据类型和业务需求调整图表类型和布局。

抱歉,评论功能暂时关闭!