You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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. 优先改用条形图:如上述方式1,条形图只会根据存在的分类生成柱子,不会出现空的0值柱子。
  2. 精准设置直方图的bins:使用方式2中的bins设置,只包含存在的分类值对应的区间,避免生成空区间。
  3. 过滤空柱子的标签:如果不想修改绘图逻辑,可以在添加标签时过滤掉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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:20:34