为何Pandas的df.plot.bar()不支持传入宽度数组?
Pandas bar/barh无法处理多宽度值的原因及解决办法
我之前也碰到过这个坑!明明Matplotlib原生的bar和barh函数都支持传入数组作为每个条形的宽度/高度,但用Pandas的plot.bar()或者plot.barh()调用时就会报错,堆栈信息里全是轴范围计算相关的错误。
先把你提到的最小复现代码补全:
import pandas as pd import matplotlib.pyplot as plt # 完整的最小复现代码 df = pd.DataFrame({'value': [3,5,4], 'width': [0.1, 0.3, 0.2]}) # 尝试用Pandas barh调用,会触发报错 df.plot.barh(height=df['width']) plt.show()
问题根源
这其实是Pandas对Matplotlib的包装层的一个小缺陷:Pandas的plot.bar/barh在内部计算坐标轴范围的时候,默认把width(bar的参数)或者height(barh的参数)当成单个标量来处理。比如在调整y轴范围时,它会执行类似y + height的运算,但如果height是数组,这里的逻辑没有做数组兼容的处理,导致类型不匹配或者运算错误,最终抛出异常。
而Matplotlib原生函数则完全支持数组类型的宽度/高度参数,因为它的轴范围计算逻辑是针对每个条形单独处理的。
解决办法
最直接省心的方案就是绕过Pandas的plot包装器,直接用Matplotlib的原生函数来绘制,这样就能正常使用数组宽度了:
import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame({'value': [3,5,4], 'width': [0.1, 0.3, 0.2]}) fig, ax = plt.subplots() # 生成y轴位置的数组 y_positions = range(len(df)) # 用Matplotlib原生barh,传入宽度数组作为height参数 ax.barh(y_positions, df['value'], height=df['width']) # 设置y轴刻度和标签(对应原DataFrame的索引) ax.set_yticks(y_positions) ax.set_yticklabels(df.index) plt.tight_layout() plt.show()
如果一定要坚持用Pandas的plot接口,也可以先调用Pandas绘制,再手动遍历每个条形对象修改宽度,但这种方法比较繁琐,不如直接用Matplotlib原生函数来得高效。
内容的提问来源于stack exchange,提问作者eecharlie
相关产品推荐
相关产品推荐

