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

带双列索引的Pandas DataFrame绘图:自定义X轴刻度方法问询

解决双列索引DataFrame的分层X轴绘图需求

嘿,这个问题我之前也碰到过!默认的df.plot()确实不会自动把MultiIndex解析成你想要的分层X轴,不过有几种方法可以实现你要的效果——把floor作为大区块,room对应的数据点放在各自的区块里。

方法一:手动计算位置,自定义区块分隔

这种方法完全由你控制X轴的布局,能精准实现“floor分区块、room在区块内分布”的效果:

import pandas as pd
from matplotlib import pyplot as plt

# 原始数据处理
df = pd.DataFrame(data={'floor':[1,1,1,2,2,2,3,3],'room':[1,2,3,1,1,2,1,3],'count':[1, 1, 3,2,2,4,1,5]})
df2 = df.groupby(['floor','room']).sum()
df_reset = df2.reset_index()  # 重置索引,方便后续处理

# 定义每个floor区块的宽度,这里给每个floor分配3个单位宽度
floor_block_width = 3
x_positions = []
current_floor = None
floor_offset = 0

# 计算每个数据点的X轴位置
for idx, row in df_reset.iterrows():
    if row['floor'] != current_floor:
        current_floor = row['floor']
        floor_offset = (current_floor - 1) * floor_block_width
    # 让每个room在区块内居中显示
    x_pos = floor_offset + (row['room'] - 1) + 0.5
    x_positions.append(x_pos)

# 开始绘图
plt.figure(figsize=(10,6))
plt.bar(x_positions, df_reset['count'], width=0.8)

# 添加floor区块的分隔线
for floor_idx in range(1, df_reset['floor'].nunique()):
    plt.axvline(x=floor_idx * floor_block_width, color='#999999', linestyle='--', alpha=0.6)

# 设置X轴刻度与标签
# 房间级刻度
plt.xticks(x_positions, [f'Room {r}' for r in df_reset['room']], rotation=45)
# 楼层级标签(放在区块上方)
ax = plt.gca()
floor_center_ticks = [(i * floor_block_width) + floor_block_width/2 for i in range(df_reset['floor'].nunique())]
ax.set_xticks(floor_center_ticks, minor=True)
ax.set_xticklabels([f'Floor {f}' for f in df_reset['floor'].unique()], minor=True)
ax.tick_params(axis='x', which='minor', pad=20, size=0)

plt.xlabel('Floor & Room')
plt.ylabel('Total Count')
plt.title('Count Distribution by Floor and Room')
plt.tight_layout()
plt.show()

方法二:用Seaborn简化分类绘图

如果你不想手动计算位置,Seaborn的分类绘图功能可以帮你快速实现类似效果,代码更简洁:

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns

# 原始数据处理
df = pd.DataFrame(data={'floor':[1,1,1,2,2,2,3,3],'room':[1,2,3,1,1,2,1,3],'count':[1, 1, 3,2,2,4,1,5]})
df2 = df.groupby(['floor','room']).sum()
df_reset = df2.reset_index()

plt.figure(figsize=(10,6))
# 按room分组,用floor区分颜色,关闭 dodge 让同floor的room挨在一起
sns.barplot(x='room', y='count', hue='floor', data=df_reset, dodge=False)

# 添加floor区块的分隔线
room_counts_per_floor = df_reset.groupby('floor')['room'].nunique()
cumulative_rooms = 0
for i in range(len(room_counts_per_floor)-1):
    cumulative_rooms += room_counts_per_floor.iloc[i]
    plt.axvline(x=cumulative_rooms - 0.5, color='#999999', linestyle='--', alpha=0.6)

plt.xlabel('Room Number')
plt.ylabel('Total Count')
plt.title('Count Distribution by Floor and Room')
plt.legend(title='Floor')
plt.tight_layout()
plt.show()

为什么原代码的X轴是行号?因为当DataFrame是MultiIndex时,pandas默认的plot()方法会把行的整数位置作为X轴,而不会解析MultiIndex的层级信息。上面两种方法都是通过重置索引,把层级索引转换成普通列,再手动或借助可视化库实现分层布局。

内容的提问来源于stack exchange,提问作者Dimitry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:51:40