使用Python绘制Excel柱状线型组合图与树状图(含数据透视表操作指南)

1、组合图、数据透视表

(1)数据预处理

知识点

  1. 日期函数 year() month()
  2. 数据透视表操作
  3. 同比计算公式
  4. 环比计算公式

(2)excel 数据透视表+插入组合图

a.2015~2017数据集处理方式:

  • 操作:
  • 结果
  • b.2020~2022数据集处理方式

    一次数据透视结果:
  • 操作

  • 结果
  • 两次数据透视结果
  • 操作:
  • 结果:
  • (3)python绘制组合图

    a.数据预处理结果

    b.代码

    知识点:

    1. 使用 make_subplots 创建子图,设置 secondary_y=True 启用双 Y 轴

    2. 交互模式:hovermode=‘x unified’ 使鼠标悬停时同时显示所有系列在同一日期的数据,便于对比。

    import pandas as pd
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    
    # 读取数据
    data = pd.read_excel('组合图数据.xlsx',engine='openpyxl')
    
    # 将日期列转换为datetime类型
    data['日期'] = pd.to_datetime(data['日期'])
    
    # 创建组合图
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    
    # 添加成交金额柱状图
    fig.add_trace(
        go.Bar(
            x=data['日期'],
            y=data['求和项:成交金额'],
            name='求和项:成交金额',
            marker_color='#1f77b4'
        ),
        secondary_y=False
    )
    
    # 添加同比增幅折线图
    fig.add_trace(
        go.Line(
            x=data['日期'],
            y=data['同比'],
            name='同比增幅',
            line=dict(color='#d62728', width=2, dash='dash')
        ),
        secondary_y=True
    )
    
    # 添加环比增幅折线图
    fig.add_trace(
        go.Line(
            x=data['日期'],
            y=data['环比'],
            name='环比增幅',
            line=dict(color='#2ca02c', width=2, dash='dash')
        ),
        secondary_y=True
    )
    
    # 设置图表布局
    fig.update_layout(
        title='2020年1月1日-2022年12月1日的成交金额、环比增幅、同比增幅的组合图',
        xaxis_title='日期',
        yaxis_title='成交金额',
        yaxis2=dict(
            title='增幅 (%)',
            overlaying='y',
            side='right'
        ),
        hovermode='x unified'
    )
    
    # 显示图表
    fig.show()
    

    c.结果

    组合图

    优化:销售数据仪表盘:

    a.代码

    知识点

    1. dash 构建交互界面,dash_bootstrap_components 提供美观的 UI 组件。
    2. dbc.Container:Bootstrap 的响应式容器,fluid=True表示宽度 100%
    3. dbc.Row, dbc.Col:Bootstrap 的网格系统,一行一列。
    4. html.H1:HTML 标题标签,className添加样式(居中、上下边距)。
    5. dcc.Dropdown:下拉菜单组件:
      id:组件唯一标识,用于回调。
      options:选项列表,格式为[{label:显示文本, value:实际值}]。
      value:默认选中的值。
      multi=True:允许多选。
    6. dbc.Button:Bootstrap 按钮:
      n_clicks:记录点击次数,触发回调。
      color=“primary”:蓝色主按钮。
    7. dbc.Spinner:加载动画,在数据处理时显示。
    8. dcc.Graph:Plotly 图表组件,id='sales-graph’用于显示组合图。
    9. @app.callback:装饰器,定义回调函数。
    10. Output:回调输出,更新sales-graph组件的figure属性。
    11. Input:触发回调的输入,这里是按钮的n_clicks。
    12. State:获取下拉菜单当前值(不触发回调)。
    13. hovertemplate:鼠标悬停时显示的信息:
      %{x|%Y年%m月}:格式化日期(如 2023 年 01 月)。
      %{text}:显示text中的金额。
      < extra></ extra>:隐藏右侧默认信息。
    14. overlaying=‘y’:与左侧 Y 轴共享 X 轴。
    15. hovermode=‘x unified’:鼠标悬停时,所有数据在同一 X 轴对齐显示。
    16. tickformat=‘% Y 年 % m 月’:X 轴日期格式化为2023年01月。
      tickformat=‘,’:Y 轴数字添加千位分隔符(如1,000,000)。
    17. 流式布局(fluid layout)fluid=True 响应式布局适配不同屏幕。
    import pandas as pd
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    import dash
    from dash import dcc, html, Input, Output, State
    import dash_bootstrap_components as dbc
    
    # 读取数据
    data = pd.read_excel('组合图数据.xlsx',engine='openpyxl')
    
    # 确保日期列是正确的格式
    data['日期'] = pd.to_datetime(data['日期'])
    data['年份'] = data['日期'].dt.year
    data['月份'] = data['日期'].dt.month
    
    # 创建应用
    app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
    server = app.server  # 用于生产部署
    
    # 获取年份和月份的唯一值
    years = sorted(data['年份'].unique())
    months = list(range(1, 13))
    month_names = ['一月', '二月', '三月', '四月', '五月', '六月',
                   '七月', '八月', '九月', '十月', '十一月', '十二月']
    
    # 应用布局
    app.layout = dbc.Container([
        dbc.Row([
            dbc.Col(html.H1("销售数据分析仪表盘", className="text-center mt-4 mb-4"), width=12)
        ]),
    
        dbc.Row([
            dbc.Col([
                html.Label("选择年份:", className="mr-2"),
                dcc.Dropdown(
                    id='year-dropdown',
                    options=[{'label': str(year), 'value': year} for year in years],
                    value=years,  # 默认选择所有年份
                    multi=True,
                    className="w-100"
                )
            ], width=3),
    
            dbc.Col([
                html.Label("选择月份:", className="mr-2"),
                dcc.Dropdown(
                    id='month-dropdown',
                    options=[{'label': month_names[i - 1], 'value': i} for i in months],
                    value=months,  # 默认选择所有月份
                    multi=True,
                    className="w-100"
                )
            ], width=3),
    
            dbc.Col([
                dbc.Button(
                    "应用筛选",
                    id='apply-filter',
                    n_clicks=0,
                    className="mt-3",
                    color="primary"
                )
            ], width=2)
        ], className="mb-4"),
    
        dbc.Row([
            dbc.Col([
                dbc.Spinner(
                    id="loading-spinner",
                    children=[dcc.Graph(id='sales-graph')],
                    color="primary",
                    type="grow"
                )
            ], width=12)
        ])
    
    ], fluid=True)
    
    
    # 回调函数
    @app.callback(
        Output('sales-graph', 'figure'),
        [Input('apply-filter', 'n_clicks')],
        [State('year-dropdown', 'value'),
         State('month-dropdown', 'value')]
    )
    def update_graph(n_clicks, selected_years, selected_months):
        # 确保参数有效
        if not selected_years:
            selected_years = years
        if not selected_months:
            selected_months = months
    
        # 筛选数据
        filtered_data = data[
            data['年份'].isin(selected_years) &
            data['月份'].isin(selected_months)
            ]
    
        # 如果没有数据,返回空图表
        if filtered_data.empty:
            fig = go.Figure()
            fig.update_layout(
                title="没有匹配的数据",
                xaxis_title="日期",
                yaxis_title="成交金额"
            )
            return fig
    
        # 创建组合图
        fig = make_subplots(specs=[[{"secondary_y": True}]])
    
        # 添加成交金额柱状图
        fig.add_trace(
            go.Bar(
                x=filtered_data['日期'],
                y=filtered_data['求和项:成交金额'],
                name='成交金额',
                text=[f"{x:,.0f}" for x in filtered_data['求和项:成交金额']],
                hovertemplate='日期: %{x|%Y年%m月}<br>成交金额: %{text}<extra></extra>',
                marker_color='#1f77b4'
            ),
            secondary_y=False
        )
    
        # 添加同比增幅折线图
        fig.add_trace(
            go.Scatter(
                x=filtered_data['日期'],
                y=filtered_data['同比'],
                name='同比增幅',
                text=[f"{x:.1f}%" for x in filtered_data['同比']],
                hovertemplate='日期: %{x|%Y年%m月}<br>同比增幅: %{text}<extra></extra>',
                line=dict(color='#d62728', width=2, dash='dash'),
                marker=dict(size=8)
            ),
            secondary_y=True
        )
    
        # 添加环比增幅折线图
        fig.add_trace(
            go.Scatter(
                x=filtered_data['日期'],
                y=filtered_data['环比'],
                name='环比增幅',
                text=[f"{x:.1f}%" for x in filtered_data['环比']],
                hovertemplate='日期: %{x|%Y年%m月}<br>环比增幅: %{text}<extra></extra>',
                line=dict(color='#2ca02c', width=2, dash='dash'),
                marker=dict(size=8)
            ),
            secondary_y=True
        )
    
        # 设置图表布局
        fig.update_layout(
            title=f"成交金额与增幅分析 ({', '.join(map(str, selected_years))}年)",
            title_font=dict(size=20),
            xaxis_title="日期",
            yaxis_title="成交金额",
            yaxis2=dict(
                title="增幅 (%)",
                overlaying='y',
                side='right'
            ),
            legend=dict(
                x=0, y=1.05,
                orientation='h',
                bgcolor='rgba(255, 255, 255, 0.8)',
                bordercolor='rgba(0, 0, 0, 0.1)',
                borderwidth=1,
                font=dict(size=14)
            ),
            hovermode='x unified',
            plot_bgcolor='rgba(240, 240, 240, 0.5)',
            margin=dict(l=60, r=60, t=60, b=60),
            font=dict(family="SimHei, WenQuanYi Micro Hei, Heiti TC", size=14)
        )
    
        # 设置X轴格式
        fig.update_xaxes(
            tickformat='%Y年%m月',
            tickfont=dict(size=14)
        )
    
        # 设置Y轴格式
        fig.update_yaxes(
            tickformat=',',
            title_font=dict(size=16)
        )
    
        return fig
    
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    
    b.结果

    销售数据仪表盘

    2、树状图可视化

    (1)数据预处理,数据透视表实现求和

    (2)EXCEL 插入树状图

    (3)python matplotlib库中的squarify.plot()函数绘制树状图

    import pandas as pd
    import matplotlib.pyplot as plt
    import squarify
    import numpy as np
    
    # 读取数据
    df = pd.read_excel('树状图.xlsx', engine='openpyxl')
    
    # 设置图片清晰度
    plt.rcParams['figure.dpi'] = 300
    # 设置中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC']
    
    # 数据预处理:计算占比,用于标签显示
    total = df['求和项:成交金额'].sum()
    df['占比'] = df['求和项:成交金额'].apply(lambda x: f"{x/total*100:.1f}%")
    
    # 创建自定义颜色映射
    cmap = plt.cm.get_cmap('viridis', len(df))
    colors = [cmap(i) for i in range(len(df))]
    
    # 绘制树状图
    plt.figure(figsize=(12, 8))  # 设置图形大小
    
    squarify.plot(
        sizes=df['求和项:成交金额'],
        label=[f"{name}\n{amount/1e8:.1f}亿\n{percent}"
               for name, amount, percent in zip(df['类别'], df['求和项:成交金额'], df['占比'])],
        color=colors,
        alpha=0.8,
        pad=True  # 添加间隔,使图形更清晰
    )
    
    # 设置标题和样式
    plt.title('不同类别成交金额树状图', fontsize=16, pad=10)
    plt.axis('off')  # 隐藏坐标轴
    
    # 添加图例说明
    plt.text(
        0.99, 0.01,
        f"总计: {total/1e8:.2f}亿",
        ha='right',
        va='bottom',
        transform=plt.gca().transAxes,
        fontsize=10,
        bbox=dict(facecolor='white', alpha=0.7)
    )
    
    # 调整布局
    plt.tight_layout()
    
    # 显示图形
    plt.show()
    

    作者:༺ Dorothy ༻

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用Python绘制Excel柱状线型组合图与树状图(含数据透视表操作指南)

    发表回复