如何用Matplotlib/Pandas绘制非堆叠非并列的重叠水平条形图?
实现重叠水平条形图(小条形在上,大条形在下)
我完全懂你的需求——要让所有水平条形重叠在一起,小条形能显示在大条形上方,既不堆叠数值,也不会被完全遮挡,还不想用透明度导致颜色混得乱七八糟。你之前的问题出在绘图逻辑上:按列循环绘制时,同一类别的所有条形会批量画出来,不管数值大小,后面的类别会直接覆盖前面的,结果就是小条形经常被大的完全挡住。
咱们换个思路来解决:针对每个星期几(每个y轴位置),先画数值大的条形(底层),再画数值小的条形(上层),这样小条形就不会被大的完全遮盖了。下面是修改后的代码:
import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv("flow_actions.csv", index_col="weekday") def pyplot_overlapped_chart(df, **kwargs): # 给每个星期几分配y轴的数值位置,确保所有条形对齐在同一水平线 y_positions = range(len(df.index)) # 遍历每个星期几和对应的y轴位置 for y, weekday in zip(y_positions, df.index): # 获取当天所有类别的数据 daily_values = df.loc[weekday] # 按数值从大到小排序,先画大的(底层),后画小的(上层) sorted_daily = daily_values.sort_values(ascending=False) # 逐个绘制当天的条形,只在第一个星期几添加图例标签(避免图例重复) for category, value in sorted_daily.items(): plt.barh(y=y, width=value, label=category if y == 0 else "", height=0.8, **kwargs) # 设置y轴显示星期几的文字标签 plt.yticks(y_positions, df.index) # 清理重复的图例项,只保留一份各类别的标签 handles, labels = plt.gca().get_legend_handles_labels() unique_legend = dict(zip(labels, handles)) plt.legend(unique_legend.values(), unique_legend.keys()) plt.grid(axis="x") plt.show() # 调用函数测试效果 pyplot_overlapped_chart(df)
关键逻辑说明:
- 按天排序绘制:不再按类别批量绘制,而是针对每个星期几单独处理数据,把数值大的类别先画(在底层),小的后画(在上层),确保小条形能露在大条形上方。
- 图例去重:如果每个星期几绘制时都添加图例标签,图例会重复显示多次,所以只在第一个星期几绘制时添加标签,最后通过字典去重得到干净的图例。
- y轴位置对齐:用
y_positions固定每个星期几的y轴数值位置,确保同一星期几的所有条形都对齐在同一水平线,不会出现偏移。
这样出来的效果正好符合你的预期:所有条形重叠,小条形在大条形上方,数值独立不堆叠,也不会有完全被遮挡的情况,颜色也不会因为透明度变得模糊。
内容的提问来源于stack exchange,提问作者Felipe Muniz
相关产品推荐
相关产品推荐

