plt绘制条形图与折线图的组合图

一、背景

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轴的位置

 

  • 分两次循环分别画出柱形图和条形图

 

posted @ 2025-03-10 11:07  qsl_你猜  阅读(39)  评论(0)    收藏  举报