一、背景
1.1 原始数据
![]()
1.2 效果图
![]()
二、代码展示
import warnings
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
warnings.filterwarnings('ignore')
excel_file = r'plot.xlsx'
df = pd.read_excel(excel_file)
years = sorted(list(set(df['年份'])))
names = sorted(list(set(df['姓名'])))
df['年总计'] = df.groupby('年份')['值'].transform('sum')
# 计算比例
df['占比'] = df['值'] / df['年总计']
df = df[['姓名', '年份', '值', '占比']]
value_list = list()
proportion_list = list()
for name in names:
name_values = list()
proportion_values = list()
for year in years:
v = df[(df["年份"] == year) & (df["姓名"] == name)]['值'].sum()
p = df[(df["年份"] == year) & (df["姓名"] == name)]['占比'].sum()
name_values.append(v)
proportion_values.append(p)
value_list.append(name_values)
proportion_list.append(proportion_values)
value_array = np.array(value_list)
proportion_array = np.array(proportion_list)
fig, ax1 = plt.subplots(figsize=(15, 8))
# 定义柱状图的 X 坐标
line_step = 1 # 设置步长
bar_width = 0.08 # 设置柱状图的宽度
x1 = np.arange(len(names)) * line_step
x2 = np.arange(len(years)) * bar_width
# 绘制行业产出的柱状图
for i, year in enumerate(years):
bars= ax1.bar(x1 + i * bar_width, value_array[:, i], bar_width, label=str(year), alpha=0.4, color='blue',
edgecolor='black')
# 在每个柱上显示值
for bar in bars:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width() / 2, height, f'{height}', ha='center', va='bottom', fontsize=10)
ax1.set_xlabel('姓名')
ax1.set_ylabel('值')
ax1.set_title('某人在某年的值及其占比')
ax1.set_xticks(x1 + bar_width * (len(years) - 1) / 2)
ax1.set_xticklabels(names, rotation=45)
# 创建右侧 Y 轴
ax2 = ax1.twinx()
for i, name in enumerate(names):
x = x2 + i * line_step
y = proportion_array[i, :]
ax2.plot(x, y, label=f'S{name}', linestyle='-', alpha=0.8, color='red') # markersize=3,marker='o',
ax2.scatter(x,y , color='black', s=5)
for j in range(len(x)):
plt.text(x[j], y[j], f'{y[j] * 100:.0f}', ha='center', va='bottom', fontsize=10)
ax2.set_ylabel('占比')
ax2.yaxis.set_major_formatter(mtick.PercentFormatter(xmax=1, decimals=0))
# 添加图例
# ax1.legend(loc='upper left')
# ax2.legend(loc='upper left', bbox_to_anchor=(0.1, 1))
plt.savefig('Python.png', format='png')
plt.show()
三、原理分析
- 要设置柱子的宽度和步长, 会影响到坐标在X轴的位置
![]()