Python绘制分类数据直方图时x轴刻度偏移且出现未知0值求助
分类数据直方图问题解决:刻度居中与异常0值处理
问题背景
使用Python绘制分类数据的直方图时,出现两个问题:x轴刻度未与柱子居中对齐,且图中出现了数据集中不存在的0值柱子。原代码如下:
def distribution(data, colName, title, plot_name): fig = plt.figure(figsize = (50,10)); for i, feature in enumerate(colName): ax = fig.add_subplot(1, 2, i+1) ax.hist(data[feature], bins = 25, color = 'maroon') ax.tick_params(axis='x', rotation=90, labelsize=20) ax.set_ylim((0, 2000)) ax.set_yticks([0, 500, 1000, 1500, 2000]) ax.set_yticklabels([0, 500, 1000, 1500, ">2000"], fontsize=20) ax.bar_label(ax.containers[0], size=20) ax.set_title(title, fontsize = 30) plt.savefig(plot_name, format='png') plt.show() distribution(df, ['Subtype 1'], "Distribution of Subtype 1", "Distribution of Subtype 1.png" )
一、x轴刻度未居中的解决方法
原因
hist()是为连续数值数据设计的函数,会自动生成等间隔的bins区间。而分类数据是离散的,用hist绘制时,生成的bins区间和分类值无法一一对应,导致刻度和柱子错位。
两种解决方式
方式1:改用条形图(更适合分类数据)
条形图专门用于展示离散分类的频数,能自动让刻度与柱子居中对齐。修改代码如下:
import pandas as pd import matplotlib.pyplot as plt def distribution(data, colName, title, plot_name): fig = plt.figure(figsize=(50,10)) for i, feature in enumerate(colName): ax = fig.add_subplot(1, 2, i+1) # 统计每个分类的频数并按索引排序 freq_data = data[feature].value_counts().sort_index() # 绘制条形图 bars = ax.bar(freq_data.index, freq_data.values, color='maroon') ax.tick_params(axis='x', rotation=90, labelsize=20) ax.set_ylim((0, 2000)) ax.set_yticks([0, 500, 1000, 1500, 2000]) ax.set_yticklabels([0, 500, 1000, 1500, ">2000"], fontsize=20) ax.bar_label(bars, size=20) ax.set_title(title, fontsize=30) plt.savefig(plot_name, format='png') plt.show()
方式2:手动调整直方图的bins与刻度
如果坚持使用直方图,需要让bins区间严格匹配分类值的范围,确保每个分类对应一个独立的bins区间,再手动设置x轴刻度:
import matplotlib.pyplot as plt def distribution(data, colName, title, plot_name): fig = plt.figure(figsize=(50,10)) for i, feature in enumerate(colName): ax = fig.add_subplot(1, 2, i+1) # 获取排序后的分类值 sorted_categories = sorted(data[feature].unique()) # 设置bins:每个分类值对应一个左右偏移0.5的区间 bins = [x - 0.5 for x in sorted_categories] + [sorted_categories[-1] + 0.5] ax.hist(data[feature], bins=bins, color='maroon') # 将x轴刻度设置为分类值,实现居中对齐 ax.set_xticks(sorted_categories) ax.tick_params(axis='x', rotation=90, labelsize=20) ax.set_ylim((0, 2000)) ax.set_yticks([0, 500, 1000, 1500, 2000]) ax.set_yticklabels([0, 500, 1000, 1500, ">2000"], fontsize=20) ax.bar_label(ax.containers[0], size=20) ax.set_title(title, fontsize=30) plt.savefig(plot_name, format='png') plt.show()
二、异常0值的来源与解决方法
原因
原代码中设置了bins=25,matplotlib会自动生成从数据最小值到最大值的25个等间隔区间。如果你的分类数据最小值大于0,第一个区间会包含0到最小值的范围,而这个区间内没有数据,就会生成一个高度为0的空柱子,bar_label会自动显示这个0值。
解决方法
- 优先改用条形图:如上述方式1,条形图只会根据存在的分类生成柱子,不会出现空的0值柱子。
- 精准设置直方图的bins:使用方式2中的bins设置,只包含存在的分类值对应的区间,避免生成空区间。
- 过滤空柱子的标签:如果不想修改绘图逻辑,可以在添加标签时过滤掉0值:
# 替换原代码中的ax.bar_label(ax.containers[0], size=20) for container in ax.containers: ax.bar_label(container, labels=[val if val > 0 else '' for val in container.datavalues], size=20)
内容的提问来源于stack exchange,提问作者user6688
相关产品推荐
相关产品推荐

