带双列索引的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
相关产品推荐
相关产品推荐

