Matplotlib绘制多组条形图时如何跳过NaN/0值的条形且维持布局间距
Matplotlib绘制多组条形图时如何跳过NaN/0值的条形且维持布局间距
嘿,很高兴能帮到你!我仔细看了你的问题和代码,咱们可以这样解决——既能跳过NaN或0值的条形,又能保住原本的分组顺序和布局间距,不会乱掉~
问题根源
你之前的代码是不管有没有有效数据,都给每个位置绘制了条形,所以NaN或0值的地方就会留下空白间隙。我们要做的是只在有有效数据(非NaN且大于0)的位置绘制条形,同时保证同组内的条形间距均匀。
解决方案代码
我把你的代码重构了一下,用循环来处理所有条形,同时加入有效性判断,这样代码更简洁,也能实现你要的效果:
import pandas as pd import matplotlib.pyplot as plt import numpy as np # 你的原始数据 bardict = {"B": [0.14,0.12,0.02,0.02,np.nan,np.nan,np.nan], "L": [0.08,0.14,0.06,0.06,0.07,0.12,0.08], "M": [0.08,0.09,0.07,0.08,0.22,0.15,0.06], "C": [0.11,0.10,0.13,0.35,np.nan,0.11,0.21], "S": [np.nan,0.11,0.17,0.46,0.09,0.10,0.08], "W": [0.12,0.09,0.29,0.63,0.10,0.38,0.26]} bar_C = pd.DataFrame(bardict) fig, ax = plt.subplots(figsize=(10, 6)) # 定义分组信息和x轴基准位置 groups = bar_C.columns.tolist() group_count = len(groups) group_x_positions = np.arange(group_count) # 定义每个子类别(对应表格的行,即3-9)的名称和颜色 subcategory_info = [ ("3", "mediumturquoise"), ("4", "darkred"), ("5", "lightgreen"), ("6", "purple"), ("7", "gray"), ("8", "orange"), ("9", "darkblue") ] single_bar_width = 0.12 # 单个条形的宽度,可根据需要调整 total_group_width = single_bar_width * len(subcategory_info) # 同组所有条形的总宽度 # 遍历每个分组,再遍历每个子类别,只绘制有效数据的条形 for group_idx, group_name in enumerate(groups): for subcat_idx, (subcat_name, color) in enumerate(subcategory_info): current_value = bar_C.loc[subcat_idx, group_name] # 只保留非NaN且大于0的有效数据 if not pd.isna(current_value) and current_value > 0: # 计算当前条形的精确x位置,保证同组内均匀分布 bar_x = group_x_positions[group_idx] - total_group_width/2 + (subcat_idx + 0.5)*single_bar_width ax.bar(bar_x, current_value, single_bar_width, color=color) # 设置x轴刻度和标签,保持原顺序 ax.set_xticks(group_x_positions) ax.set_xticklabels(groups) # 添加图表标签和标题 ax.set_xlabel("Group") ax.set_ylabel('Value') ax.set_title("Multi-Bar Graph") # 手动创建图例,确保所有子类别都能显示(哪怕某些分组没有对应数据) legend_handles = [plt.Rectangle((0,0), 1, 1, color=color) for _, color in subcategory_info] ax.legend(legend_handles, [name for name, _ in subcategory_info], loc='upper left') plt.tight_layout() plt.show()
关键修改点说明
- 循环替代重复代码:把原来7次重复的
plt.bar改成循环,既简洁又容易维护 - 有效数据判断:通过
not pd.isna(current_value) and current_value > 0筛选出需要绘制的条形,直接跳过无效值 - 精确计算x位置:重新计算每个条形的x坐标,保证同组内的条形均匀分布,不会因为跳过某些条形而导致间距混乱
- 手动创建图例:避免因为某些子类别在部分分组没有数据而丢失图例项
补充说明
你之前尝试的fillna(0)没用,是因为Matplotlib绘制值为0的条形时,高度为0,看起来是空白,但其实还是占据了位置。我们的方法是直接不绘制这些无效值的条形,从根源上消除空白间隙。
备注:内容来源于stack exchange,提问作者moss
相关产品推荐
相关产品推荐

