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

Plotnine:如何隐藏或不绘制计数过小的标签

问题:Plotnine堆叠柱状图小类别标签重叠,无法隐藏小计数标签

我用Plotnine绘制了堆叠柱状图,代码如下,其中combine函数改编自官方教程《Show counts and percentages for bar plots》:

import pandas as pd
from plotnine import ggplot, aes, after_stat, geom_bar, geom_label


def combine(counts: pd.Series, percentages: pd.Series):
    fmt = "{} ({}%)".format
    return [
        fmt(c, round(p))
        for c, p
        in zip(counts, percentages, strict=True)
    ]

d = {
    'cat': [*(2200 * ['cat1']), *(180 * ['cat2']), *(490 * ['cat3'])],
    'subcat': [
        *(2200 * ['subcat1']),
        *(150 * ['subcat2']),
        *(30 * ['subcat3']),
        *(40 * ['subcat4']),
        *(450 * ['subcat5'])
    ]
}
df = pd.DataFrame(d)

cats = (
    ggplot(df, aes('cat', fill='subcat'))
    + geom_bar()
    + geom_label(
          aes(label=after_stat('combine(count, count / sum(count) * 100)')),
          stat='count',
          position='stack'
      )
)
cats.save('cats.png')

当前图表中subcat4的标签被subcat5遮挡,无法读取。我尝试修改combine函数,让百分比≤5%的标签返回(None, None),但结果显示为字符串"(None, None)",达不到隐藏效果;设置position='fill'也不可行,不仅小计数仍会重叠,还丢失了子类别的绝对比例关系。

希望解决标签重叠问题,除了隐藏小计数标签外,其他可行方案也可接受(比如垂直错开标签)。


解决方案1:隐藏小百分比标签(返回空字符串)

修改combine函数,当百分比≤5%时返回空字符串,Plotnine会自动不显示空标签:

def combine(counts: pd.Series, percentages: pd.Series):
    fmt = "{} ({}%)".format
    return [
        fmt(c, round(p)) if p > 5 else ""
        for c, p
        in zip(counts, percentages, strict=True)
    ]

这样百分比低于5%的小类别标签会直接被隐藏,不会显示无效字符串。

解决方案2:使用自动避障标签(geom_label_repel)

借助plotnine.extra中的geom_label_repel,它会自动调整标签位置避免重叠,无需手动筛选小标签:

首先安装依赖(如果未安装):

pip install plotnine[extra]

修改代码中的geom_label为geom_label_repel,并调整堆叠位置:

import pandas as pd
from plotnine import ggplot, aes, after_stat, geom_bar
from plotnine.extra import geom_label_repel


def combine(counts: pd.Series, percentages: pd.Series):
    fmt = "{} ({}%)".format
    return [
        fmt(c, round(p))
        for c, p
        in zip(counts, percentages, strict=True)
    ]

d = {
    'cat': [*(2200 * ['cat1']), *(180 * ['cat2']), *(490 * ['cat3'])],
    'subcat': [
        *(2200 * ['subcat1']),
        *(150 * ['subcat2']),
        *(30 * ['subcat3']),
        *(40 * ['subcat4']),
        *(450 * ['subcat5'])
    ]
}
df = pd.DataFrame(d)

cats = (
    ggplot(df, aes('cat', fill='subcat'))
    + geom_bar()
    + geom_label_repel(
          aes(label=after_stat('combine(count, count / sum(count) * 100)'), y=after_stat('count')),
          stat='count',
          position='stack',
          min_separation=2,  # 控制标签最小间距,避免重叠
          size=8  # 可调整标签大小
      )
)
cats.save('cats.png')

这个方法会自动将重叠的标签错开显示,保留所有标签的同时解决重叠问题。

解决方案3:手动调整标签垂直位置

如果不想用第三方扩展,可以手动给小百分比的标签添加垂直偏移,比如让小标签往上移动一点:

def combine(counts: pd.Series, percentages: pd.Series):
    fmt = "{} ({}%)".format
    return [
        fmt(c, round(p))
        for c, p
        in zip(counts, percentages, strict=True)
    ]

# 先计算每个子类别的计数和百分比,手动处理标签位置
summary_df = df.groupby(['cat', 'subcat']).size().reset_index(name='count')
summary_df['percentage'] = summary_df.groupby('cat')['count'].transform(lambda x: x/x.sum()*100)
summary_df['label'] = summary_df.apply(lambda row: f"{row['count']} ({round(row['percentage'])}%)" if row['percentage']>5 else "", axis=1)
# 给小百分比的标签添加y偏移
summary_df['y_offset'] = summary_df.apply(lambda row: 10 if row['percentage']<=5 else 0, axis=1)
# 计算堆叠的y位置
summary_df['y_pos'] = summary_df.groupby('cat')['count'].cumsum() - summary_df['count']/2 + summary_df['y_offset']

cats = (
    ggplot(summary_df, aes('cat', y='count', fill='subcat'))
    + geom_bar(stat='identity')
    + geom_label(aes(y='y_pos', label='label'))
)
cats.save('cats.png')

这种方法通过预计算数据,手动调整小标签的y轴位置,避免与大标签重叠。

内容的提问来源于stack exchange,提问作者edcsnt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:45:17