Python循环绘制多个分组柱状图子图的实现方法
按产品分面的分组柱状图实现方案
实现逻辑
核心逻辑是先计算适配产品总数的子图网格,再在每个子图内通过x轴位置偏移绘制两组并列柱形,全程不需要提前做透视表转换,原始长表DataFrame可直接使用。
完整实现代码
首先导入依赖库:
import pandas as pd import matplotlib.pyplot as plt import numpy as np from math import ceil
然后做基础配置与绘图:
# 固定版本排序,避免绘图时版本顺序错乱 df['version'] = pd.Categorical(df['version'], categories=[0, 1, 2, 5], ordered=True) # 获取所有产品清单 products = df['product'].unique() product_total = len(products) # 子图布局配置,列数可和你之前绘制折线图的参数保持一致 n_cols = 4 n_rows = ceil(product_total / n_cols) bar_width = 0.35 # 分组柱的单柱宽度 # 创建画布与子图网格 fig, axes = plt.subplots(n_rows, n_cols, figsize=(n_cols*4, n_rows*3), sharey=False) axes = axes.flatten() # 将二维子图数组转为一维,方便循环遍历 # 遍历每个产品绘制对应子图 for idx, product in enumerate(products): ax = axes[idx] # 筛选当前产品数据,按版本顺序排序 prod_data = df[df['product'] == product].sort_values('version') version_labels = prod_data['version'].astype(int).values x = np.arange(len(version_labels)) # 生成x轴基准位置 # 绘制两组并列柱形,通过位置偏移实现分组效果 ax.bar(x - bar_width/2, prod_data['count_before'], width=bar_width, label='count_before', color='#1f77b4') ax.bar(x + bar_width/2, prod_data['count_after'], width=bar_width, label='count_after', color='#ff7f0e') # 子图基础样式配置 ax.set_title(product) ax.set_xticks(x) ax.set_xticklabels(version_labels) # 数值量级差异大时开启下一行的对数轴配置 # ax.set_yscale('log') # 隐藏没有对应产品的空白子图 for idx in range(product_total, len(axes)): axes[idx].axis('off') # 全局统一添加图例,避免每个子图重复显示图例占用空间 handles, labels = axes[0].get_legend_handles_labels() fig.legend(handles, labels, loc='upper right', ncol=2) # 自动调整子图间距,避免标签、标题重叠 plt.tight_layout() plt.show()
优化提示
- 如果不同版本的计数值量级差异过大(比如部分值为百万级、部分值为个位数),取消代码中
ax.set_yscale('log')的注释启用对数坐标轴,即可解决小数值柱形被压缩到不可见的问题,大幅提升图表可读性。 - 数据中的缺失值
NaN会被matplotlib自动识别跳过,对应位置不会绘制柱形,不需要额外做填充或删除处理。 - 子图列数、画布尺寸、柱宽、配色都可以直接修改参数,和你之前生成的折线图参数对齐即可获得完全一致的布局效果。
内容的提问来源于stack exchange,提问作者Geosphere
相关产品推荐
相关产品推荐

