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
相关产品推荐
相关产品推荐

