Python堆叠柱状图如何隐藏含0/NaN的单元格而非整行?
解决堆叠柱状图中0值单元格隐藏问题
问题背景
使用Python 3.12 + Spyder,通过Pandas处理DataFrame后绘制堆叠柱状图。原始处理后的数据如下:
{'storage': {0: 'a', 2: 'a', 3: 'a', 4: 'b', 5: 'b'}, 'time': {0: '4h', 2: '4h', 3: '4h', 4: '4h', 5: '4h'}, 'Predicted Class': {0: 'germling', 2: 'resting', 3: 'swollen', 4: 'germling', 5: 'hyphae'}, '%': {0: 0.22, 2: 99.02, 3: 0.76, 4: 65.41, 5: 1.72}}
通过以下代码透视数据后出现0值单元格,希望仅隐藏这些0值对应的柱子,而非删除整行:
class_order = ['resting', 'swollen', 'germling', 'hyphae', 'mature hyphae'] counts2_reduced_df['Predicted Class'] = pd.Categorical(counts2_reduced_df['Predicted Class'], categories=class_order, ordered=True) counts2_pivot_df = counts2_reduced_df.pivot_table(index=["storage","time"], columns="Predicted Class", values="%", aggfunc="sum")
尝试将0转为NaN后用drop.na会删除整行,转为空字符串会导致对应列完全不显示,现需解决仅隐藏0值柱子的问题。
解决方案
核心思路是将透视后的0值替换为NaN,然后在绘图时过滤掉高度为0的柱子,同时只对非0值添加注释。
修改后的完整代码
import pandas as pd import matplotlib.pyplot as plt # 原始数据(示例) data = {'storage': {0: 'a', 2: 'a', 3: 'a', 4: 'b', 5: 'b'}, 'time': {0: '4h', 2: '4h', 3: '4h', 4: '4h', 5: '4h'}, 'Predicted Class': {0: 'germling', 2: 'resting', 3: 'swollen', 4: 'germling', 5: 'hyphae'}, '%': {0: 0.22, 2: 99.02, 3: 0.76, 4: 65.41, 5: 1.72}} counts2_reduced_df = pd.DataFrame(data) # 数据透视处理 class_order = ['resting', 'swollen', 'germling', 'hyphae', 'mature hyphae'] counts2_reduced_df['Predicted Class'] = pd.Categorical(counts2_reduced_df['Predicted Class'], categories=class_order, ordered=True) counts2_pivot_df = counts2_reduced_df.pivot_table(index=["storage","time"], columns="Predicted Class", values="%", aggfunc="sum") # 关键步骤:将0值替换为NaN,绘图时不会显示对应柱子 counts2_pivot_df = counts2_pivot_df.replace(0, pd.NA) # 绘图部分 fig, ax = plt.subplots() color_mapping = { 'resting': 'yellow', 'swollen': 'blue', 'germling': 'red', 'hyphae': 'cyan', 'mature hyphae': 'green', } colors = [color_mapping[class_name] for class_name in class_order] # 绘制堆叠柱状图 counts2_pivot_df.plot(kind='bar', stacked=True, color=colors, ax=ax) # 设置X轴标签 ax.set_xticks(range(len(counts2_pivot_df.index))) ax.set_xticklabels([f'{i[0]} & {i[1]}' for i in counts2_pivot_df.index], rotation=0) ax.set_xlabel('Storage Condition and Time after Inoculation') ax.set_ylabel('Percentage (%)') ax.legend(title='Predicted Class', loc='center left', bbox_to_anchor=(1, 0.5)) # 仅对非0值添加注释 for bar_group in ax.containers: # 过滤掉高度为0的柱子 bars = [bar for bar in bar_group if bar.get_height() > 0] for bar in bars: height = bar.get_height() text_x = bar.get_x() + bar.get_width() / 2 text_y = bar.get_y() + height / 2 ha = 'center' if height > 5 else 'left' text_x_adjusted = text_x if height > 5 else bar.get_x() + bar.get_width() ax.annotate(f'{height:.2f}%', xy=(text_x_adjusted, text_y), ha=ha, va='center', color='black', fontsize=8, fontweight='bold') plt.tight_layout() plt.show()
关键说明
- 替换0为NaN:
counts2_pivot_df = counts2_pivot_df.replace(0, pd.NA),Pandas在绘制堆叠柱状图时会自动忽略NaN值对应的柱子,不会显示,且不会删除整行。 - 过滤注释:遍历柱子容器时,只处理高度大于0的柱子,避免对0值添加不必要的注释。
- 布局优化:添加
plt.tight_layout()避免图例和图表元素重叠。
内容的提问来源于stack exchange,提问作者mr.raccoon
相关产品推荐
相关产品推荐

