You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 17:28:14