使用Pandas与Matplotlib绘制带嵌套分组子标签的柱状图
实现Matplotlib层级嵌套分组标签的柱状图
我之前也碰到过类似的需求,想要用Matplotlib做出像Excel那样带嵌套层级分组标签的柱状图(比如London -> Switch 1、Switch3 -> Interface这种清晰的结构),折腾了一番后终于找到了解决方案,刚好适配你的样本数据,分享给你!
首先准备你的样本数据
import pandas as pd data = { 'Location': ['NYC', 'NYC', 'NYC', 'NYC', 'LON', 'LON', 'LON', 'TKY', 'TKY', 'TKY'], 'Device': ['Device1', 'Device2', 'Device3', 'Device1', 'Switch1', 'Switch1', 'Switch3', 'Router1', 'Router2', 'Router2'], 'Interface': ['Et1', 'Et2', 'Et3', 'Et2', 'Et1', 'Et3', 'Et22', 'Gi1', 'Gi1', 'Gi2'], 'Errors': [69, 58, 16, 83, 58, 78, 16, 30, 33, 64] } df = pd.DataFrame(data)
完整实现代码
我们通过几个自定义函数来处理层级标签绘制、分隔线添加以及数值标注,最终实现嵌套分组效果:
from matplotlib import pyplot as plt from collections import Counter def add_line(ax, xpos, ypos): # 绘制层级之间的灰色分隔线 line = plt.Line2D([xpos, xpos], [ypos + .1, ypos], transform=ax.transAxes, color='gray') line.set_clip_on(False) ax.add_line(line) def my_label(my_index, level): # 统计每个层级标签的出现次数,用于计算标签的居中位置 labels = my_index.get_level_values(level) if level == my_index.nlevels - 1: # 最内层每个标签对应一个柱子,次数为1 return [(x, 1) for x in labels] else: # 外层标签统计出现的频次 count = Counter(labels) return count.items() def label_group_bar_table(ax, df): # 从最外层到最内层依次绘制嵌套标签 ypos = -.1 scale = 1. / df.index.size # 按柱子数量计算比例,适配不同数据量 for level in range(df.index.nlevels)[::-1]: pos = 0 for label, rpos in my_label(df.index, level): # 计算标签的水平居中位置 lxpos = (pos + .5 * rpos) * scale ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes, size=12, color='gray') add_line(ax, pos * scale, ypos) pos += rpos add_line(ax, pos * scale, ypos) ypos -= .05 # 每层标签向下偏移,避免重叠 def autonotate(df): # 在每个柱子上方标注对应的Errors数值 for num, (_, row) in enumerate(df.reset_index().iterrows()): errors = row['Errors'] ax.text(num, errors * 1.02, errors, ha='center', size=12, color='black') # 按Location→Device→Interface三层结构分组求和 grouped_df = df.groupby(['Location','Device','Interface']).sum() # 初始化绘图对象 fig = plt.figure(figsize=(20,7)) ax = fig.add_subplot() # 绘制柱状图,隐藏默认的x轴标签(避免和自定义层级标签冲突) grouped_df.plot(kind='bar', stacked=False, ax=ax, color='orange') ax.set_xticklabels(['' for _ in ax.get_xticklabels()]) ax.set_xlabel('') # 添加自定义层级嵌套标签 label_group_bar_table(ax, grouped_df) # 调整图表底部边距,确保所有层级标签都能显示 fig.subplots_adjust(bottom=.1 * grouped_df.index.nlevels) # 添加柱子上方的数值标注 autonotate(grouped_df) plt.tight_layout() plt.show()
关键细节说明
- 层级分组:通过
groupby按你的需求层级对数据进行聚合,确保数据结构和嵌套标签完全对应。 - 标签定位:利用
Counter统计每个外层标签对应的柱子数量,计算出标签的居中位置,保证每个分组标签能准确覆盖其下的所有柱子。 - 分隔线:通过
add_line函数绘制灰色分隔线,清晰区分不同层级的分组边界。 - 边距调整:根据层级数量动态调整图表底部边距,避免长标签被截断。
运行这段代码后,就能得到和Excel示例图类似的、带有清晰嵌套分组标签的柱状图了。
内容的提问来源于stack exchange,提问作者Enthusiast
相关产品推荐
相关产品推荐

