如何在堆积条形图中使用百分比作为标签?

5
我正在尝试在ggplot2的堆叠条形图中将百分比数字显示为标签。我找到了3年前的其他帖子,但我无法复制它:如何在基于组的ggplot2中绘制显示百分比的堆叠条形图? 那篇文章的答案几乎完全符合我的要求。
这是我的数据的简单示例:
df = data.frame('sample' = c('cond1','cond1','cond1','cond2','cond2','cond2','cond3','cond3','cond3','cond4','cond4','cond4'),
                'class' = c('class1','class2','class3','class1','class2','class3','class1','class2','class3','class1','class2','class3'))
ggplot(data=df, aes(x=sample, fill=class)) + 
    coord_flip() +
    geom_bar(position=position_fill(reverse=TRUE), width=0.7)

enter image description here

我希望每个条形图都显示百分比/分数,所以在这种情况下它们都将是33%。实际上,如果可以实时计算值,那就更好了,但如果需要,我也可以手动输入百分比。有人能帮忙吗?
附带问题:如何减少条形图之间的空间?我也找到了许多答案,但它们建议在position_fill()中使用width参数,但这个参数似乎已经不存在了。
非常感谢!
编辑:
到目前为止,有两个示例完全展示了我所要求的内容(非常感谢您的快速回复),但是当应用于我的真实数据时,它们会失败。这里是示例数据,只添加了另一个元素以显示发生了什么:
df = data.frame('sample' = c('cond1','cond1','cond1','cond2','cond2','cond2','cond3','cond3','cond3','cond4','cond4','cond4','cond1'),
                'class' = c('class1','class2','class3','class1','class2','class3','class1','class2','class3','class1','class2','class3','class2'))

基本上,我希望每个类别/条件组合只有一个标签。

3
可能是ggplot中用百分比替换geom_bar中的计数的重复问题,以及这里 - Roman
3个回答

5

我认为OP想要的是在条形图的实际部分上加上标签。我们可以使用data.table获取计数百分比和格式化百分比,然后使用ggplot绘图:

library(data.table)
library(scales)
dt <- setDT(df)[,list(count = .N), by = .(sample,class)][,list(class = class, count = count,
                percent_fmt = paste0(formatC(count*100/sum(count), digits = 2), "%"),
                percent_num = count/sum(count)
                ), by = sample]

ggplot(data=dt, aes(x=sample, y= percent_num, fill=class)) +   
  geom_bar(position=position_fill(reverse=TRUE), stat = "identity", width=0.7) +
  geom_text(aes(label = percent_fmt),position = position_stack(vjust = 0.5)) + coord_flip()

enter image description here

编辑:另一种解决方案是在聚合过程中计算标签的y值。这样我们就不必依赖于position_stack(vjust = 0.5)

dt <- setDT(df)[,list(count = .N), by = .(sample,class)][,list(class = class, count = count,
               percent_fmt = paste0(formatC(count*100/sum(count), digits = 2), "%"),
               percent_num = count/sum(count),
               cum_pct = cumsum(count/sum(count)),
               label_y = (cumsum(count/sum(count)) + cumsum(ifelse(is.na(shift(count/sum(count))),0,shift(count/sum(count))))) / 2
), by = sample]

ggplot(data=dt, aes(x=sample, y= percent_num, fill=class)) +   
  geom_bar(position=position_fill(reverse=TRUE), stat = "identity", width=0.7) +
  geom_text(aes(label = percent_fmt, y = label_y)) + coord_flip()

确实就是我想要做的,谢谢!但是这里有些奇怪。你的例子完美运作,但当我将它应用到我的数据上(比给出的例子中的数据稍多一些),输出结果看起来像这样:链接我认为它正在标记每个进入柱形图的类别实例。但我不明白为什么柱子丢失了以及为什么坐标轴完全偏移。 - fakechek
嗯,你能发布更多的数据吗? - Mike H.
我会将其添加到帖子中。 - fakechek
@fakechek请看我的更新。我在第二个data.table链中将.N改为了sum(count)。我还在第一步中进行了折叠操作。我认为这是问题的根源。 - Mike H.
非常感谢,现在完美了 :) - fakechek

3

这里有一个解决方案,首先使用dplyr计算百分比,然后绘制它们:

更新:

options(stringsAsFactors = F)

df = data.frame(sample = c('cond1','cond1','cond1','cond2','cond2','cond2','cond3','cond3','cond3','cond4','cond4','cond4'), 
                class = c('class1','class2','class3','class1','class2','class3','class1','class2','class3','class1','class2','class3'))

library(dplyr) 
library(scales)

df%>%
  # count how often each class occurs in each sample.
  count(sample, class)%>% 
  group_by(sample)%>%
  mutate(pct = n / sum(n))%>%
  ggplot(aes(x = sample, y = pct, fill = class)) + 
  coord_flip() +
  geom_col(width=0.7)+
  geom_text(aes(label = paste0(round(pct * 100), '%')),
            position = position_stack(vjust = 0.5))

enter image description here


非常感谢,不幸的是我和其他人的解决方案一样有同样的问题。简而言之,当添加更多元素(类/条件组合)时,它们会根据颜色代码进行分组,每个元素都会有自己的标签。相反,我正在尝试每种颜色只添加一个标签 :/ - fakechek
我会更新答案,使其更加强大,以适应更多的类/条件组合。 - Jeroen Boeye
如果您不想计算每个样本中的类别,而是想要唯一的类别和样本组合,您可以在分析开始时(在“count(sample, class)”之前)添加“distinct(sample, class)”这一行。在这种替代计算中,每个样本内的百分比将始终相等。 - Jeroen Boeye
太棒了,非常感谢你的帮助!这太美妙了! - fakechek

2
使用 scales
library(scales)
ggplot(data=df, aes(x=sample, fill=class)) +
  coord_flip() +
  geom_bar(position=position_fill(reverse=TRUE), width=0.7) +
  scale_y_continuous(labels =percent_format())

谢谢你的建议,这是我后来也想解决的问题。但实际上,我在这里尝试做的是为每个条形图添加一个标签,例如使用geom_text()或geom_label(),显示该条件下每个类别的百分比。 - fakechek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接