Matplotlib柱状图缺失X轴类别及误差条不显示问题求助
问题排查与解决方案
问题原因
1. 仅显示2个柱状条
从你给出的前10行数据来看,smoking-number只有1.0和3.0两类,完全没有2.0的样本。执行groupby('smoking-number').mean()后,只会生成这两类的统计结果,所以绘图时自然只有2个柱子。
2. 标准误差条(sem)未显示
你给plot.bar的yerr参数传了整个sem数据框,但pandas的柱状图要求yerr必须是对应y轴列的标准误差值序列,不是完整的DataFrame。另外你设置的xlim(0.5,3.5)会偏移柱子的位置,也可能导致误差条被隐藏。
额外问题:你给newdata的smoking-number做了字符串映射,但sem里的smoking-number还是原始数值,虽然当前分组后行顺序一致,但后续数据变化可能导致误差条和柱子不匹配。
修复方案
1. 补全缺失的类别(解决柱子数量问题)
如果你的数据集里确实没有smoking-number=2的样本,手动补全该行,保证X轴能显示三个标签:
# 定义需要的所有类别 required_cats = [1,2,3] # 重新生成统计结果,补全缺失类别 newdata = newdf.groupby('smoking-number').mean().reindex(required_cats).reset_index() sem = newdf.groupby('smoking-number').sem().reindex(required_cats).reset_index() # 填充缺失值(无样本的类别均值和sem会是NaN,这里用0填充,可根据需求调整) newdata.fillna(0, inplace=True) sem.fillna(0, inplace=True) # 映射类别名称 newdata['smoking-number'] = newdata['smoking-number'].map({1: 'never', 2: 'former', 3: 'current'})
如果数据集里其实有smoking-number=2的样本,先检查newdf['smoking-number'].unique()确认类别是否完整,可能是预处理时丢失了数据。
2. 修正误差条参数(解决sem不显示问题)
绘图时给yerr传对应列的sem值,而不是整个DataFrame:
# 绘制distance柱状图,用sem['distance']作为误差值 newdata.plot.bar(x='smoking-number', y='distance', yerr=sem['distance'], ax=axes[0], legend=False) # 绘制duration柱状图,用sem['duration']作为误差值 newdata.plot.bar(x='smoking-number', y='duration', yerr=sem['duration'], ax=axes[1], legend=False)
3. 调整X轴范围
现在有3个柱子,X轴刻度索引是0、1、2,把xlim改成适配的范围:
axes[0].set_xlim(-0.5, 2.5) axes[1].set_xlim(-0.5, 2.5)
完整修正代码
import matplotlib.pyplot as plt import pandas as pd fig, axes = plt.subplots(nrows=2) fig.tight_layout(pad=3.2) # 补全缺失的smoking-number类别 required_cats = [1,2,3] newdata = newdf.groupby('smoking-number').mean().reindex(required_cats).reset_index() sem = newdf.groupby('smoking-number').sem().reindex(required_cats).reset_index() newdata.fillna(0, inplace=True) sem.fillna(0, inplace=True) # 映射类别名称 newdata['smoking-number'] = newdata['smoking-number'].map({1: 'never', 2: 'former', 3: 'current'}) print(newdata) # 修正误差条参数 newdata.plot.bar(x='smoking-number', y='distance', yerr=sem['distance'], ax=axes[0], legend=False) newdata.plot.bar(x='smoking-number', y='duration', yerr=sem['duration'], ax=axes[1], legend=False) # 修正Y轴范围计算(用对应列的最值,逻辑更合理) upper_dist = newdata['distance'].max() + sem['distance'].max() lower_dist = newdata['distance'].min() - sem['distance'].max() upper_dur = newdata['duration'].max() + sem['duration'].max() lower_dur = newdata['duration'].min() - sem['duration'].max() axes[0].set_ylim(lower_dist, upper_dist) axes[0].set_xlim(-0.5, 2.5) axes[1].set_ylim(lower_dur, upper_dur) axes[1].set_xlim(-0.5, 2.5) axes[0].set_ylabel("Wayfinding distance") axes[0].set_xlabel("Smoking frequency") axes[1].set_ylabel("Wayfinding duration") axes[1].set_xlabel("Smoking frequency") plt.show()
内容的提问来源于stack exchange,提问作者Caledonian26
相关产品推荐
相关产品推荐

