我有
绘制自
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')
combine
函数是根据显示条形图的计数和百分比中的原始函数进行修改的。
subcat4 的标签部分被 subcat5 的标签覆盖,导致其计数和百分比无法读取。
如何隐藏标签,或者更好的是,如果标签计数太小,则根本不绘制标签?
我试过了
...
fmt(c, round(p)) if p > 5 else (None, None)
...
但这只会使百分比低于或等于 5% 的标签显示“(无,无)。”
对
position='fill'
和 geom_bar
使用 geom_label
也不是真正的解决方案,因为对于足够小的计数,问题仍然存在(例如,如果 subcat4 的计数为 10)。而且我还想保持所有类别中子类别的比例,这会因为 position='fill'
而丢失。
最终目标实际上是“不”让标签重叠,因此除了隐藏标签之外的其他方法也是可以接受的。 (我想到了在 y 轴上垂直放置“dodging”标签,但我认为这是不可能的。)
combine
函数以返回空字符串
''
而不是 (None, None)
,如下所示: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)
]