EXCEL Python 实现绘制柱状线型组合图和树状图(包含数据透视表)
1、组合图、数据透视表
(1)数据预处理
知识点
- 日期函数 year() month()
- 数据透视表操作
- 同比计算公式
- 环比计算公式
(2)excel 数据透视表+插入组合图
a.2015~2017数据集处理方式:
- 操作:
- 结果
b.2020~2022数据集处理方式
一次数据透视结果:
- 操作
- 结果
两次数据透视结果
- 操作:
- 结果:
(3)python绘制组合图
a.数据预处理结果
b.代码
知识点:
使用 make_subplots 创建子图,设置 secondary_y=True 启用双 Y 轴
交互模式: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.代码
知识点
- dash 构建交互界面,dash_bootstrap_components 提供美观的 UI 组件。
- dbc.Container:Bootstrap 的响应式容器,fluid=True表示宽度 100%
- dbc.Row, dbc.Col:Bootstrap 的网格系统,一行一列。
- html.H1:HTML 标题标签,className添加样式(居中、上下边距)。
- dcc.Dropdown:下拉菜单组件:
id:组件唯一标识,用于回调。
options:选项列表,格式为[{label:显示文本, value:实际值}]。
value:默认选中的值。
multi=True:允许多选。- dbc.Button:Bootstrap 按钮:
n_clicks:记录点击次数,触发回调。
color=“primary”:蓝色主按钮。- dbc.Spinner:加载动画,在数据处理时显示。
- dcc.Graph:Plotly 图表组件,id='sales-graph’用于显示组合图。
- @app.callback:装饰器,定义回调函数。
- Output:回调输出,更新sales-graph组件的figure属性。
- Input:触发回调的输入,这里是按钮的n_clicks。
- State:获取下拉菜单当前值(不触发回调)。
- hovertemplate:鼠标悬停时显示的信息:
%{x|%Y年%m月}:格式化日期(如 2023 年 01 月)。
%{text}:显示text中的金额。
< extra></ extra>:隐藏右侧默认信息。- overlaying=‘y’:与左侧 Y 轴共享 X 轴。
- hovermode=‘x unified’:鼠标悬停时,所有数据在同一 X 轴对齐显示。
- tickformat=‘% Y 年 % m 月’:X 轴日期格式化为2023年01月。
tickformat=‘,’:Y 轴数字添加千位分隔符(如1,000,000)。- 流式布局(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 = yearsif 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 figif __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()