如何在ggplot2中绘制(复杂的)堆积条形图,无需进行复杂的手动数据聚合。

3
我想绘制一个(分面)堆叠条形图,其中X轴以百分比表示。此外,频率标签显示在条形内部。
经过一番努力和查看stackoverflow上的许多不同问题,我找到了一个使用ggplot2解决此问题的解决方案。然而,我没有直接使用ggplot2,而是手动使用表格调用聚合数据。我以一种复杂的方式进行手动聚合,并使用临时变量手动计算百分比值(请参见源代码注释“手动聚合数据”)。
如何以更好的方式完成相同的绘图,而无需手动和复杂的数据聚合?
library(ggplot2)
library(scales)

library(gridExtra)
library(plyr)

##
##  Random Data
##
fact1 <- factor(floor(runif(1000, 1,6)),
                      labels = c("A","B", "C", "D", "E"))

fact2 <- factor(floor(runif(1000, 1,6)),
                      labels = c("g1","g2", "g3", "g4", "g5"))

##
##  STACKED BAR PLOT that scales x-axis to 100%
##

## manually aggregate data
##
mytable <- as.data.frame(table(fact1, fact2))

colnames(mytable) <- c("caseStudyID", "Group", "Freq")

mytable$total <- sapply(mytable$caseStudyID,
                        function(caseID) sum(subset(mytable, caseStudyID == caseID)$Freq))

mytable$percent <- round((mytable$Freq/mytable$total)*100,2)

mytable2 <- ddply(mytable, .(caseStudyID), transform, pos = cumsum(percent) - 0.5*percent)


## all case studies in one plot (SCALED TO 100%)

p1 <- ggplot(mytable2, aes(x=caseStudyID, y=percent, fill=Group)) +
    geom_bar(stat="identity") +
    theme(legend.key.size = unit(0.4, "cm")) +
    theme(axis.text.x = element_text(angle = 60, hjust = 1)) +
    geom_text(aes(label = sapply(Freq, function(x) ifelse(x>0, x, NA)), y = pos), size = 3) # the ifelse guards against printing labels with "0" within a bar


print(p1)

.. enter image description here


请注意,由于我所处的时区与大多数SO用户不同,因此可能需要长达14个小时才能回复评论或做出任何反应。 - mrsteve
2个回答

4

在制作数据后:

fact1 <- factor(floor(runif(1000, 1,6)),
                  labels = c("A","B", "C", "D", "E"))

fact2 <- factor(floor(runif(1000, 1,6)),
                  labels = c("g1","g2", "g3", "g4", "g5"))

dat = data.frame(caseStudyID=fact1, Group=fact2)

你可以使用 position_fill 自动创建一个你需要的无标签图形:
ggplot(dat, aes(caseStudyID, fill=Group)) + geom_bar(position="fill")

未标记的图形

我不知道是否有自动生成文本标签的方法。如果你想使用ggplot计算的位置和计数而不是单独计算,请使用ggplot_build获取堆积图的位置和计数。

p = ggplot(dat, aes(caseStudyID, fill=Group)) + geom_bar(position="fill")
ggplot_build(p)$data[[1]]

那将返回一个数据框,其中包括countxyyminymax变量,可用于创建定位标签。
如果你想要在每个类别中垂直居中标签,首先需要创建一个列,其值为yminymax之间的一半。
freq = ggplot_build(p)$data[[1]]
freq$y_pos = (freq$ymin + freq$ymax) / 2

然后使用annotate将标签添加到图表中。
p + annotate(x=freq$x, y=freq$y_pos, label=freq$count, geom="text", size=3)

labeled


1
如果您拥有每个组中案例研究ID的分布作为单个向量,您可以使用sjPlot软件包中的sjp.stackfrq函数。
A <- floor(runif(1000, 1,6))
B <- floor(runif(1000, 1,6))
C <- floor(runif(1000, 1,6))
D <- floor(runif(1000, 1,6))
E <- floor(runif(1000, 1,6))

mydf <- data.frame(A,B,C,D,E)
sjp.stackfrq(mydf, legendLabels = c("g1","g2", "g3", "g4", "g5"))

enter image description here

该函数提供许多参数以轻松自定义绘图外观(标签、大小和颜色等)。

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