ggplot填充变量以添加到100%

时间:2017-06-13 18:52:50

标签: r ggplot2

这是一个数据框

DF <- data.frame(SchoolYear = c("2015-2016", "2016-2017"), 
                 Value = sample(c('Agree', 'Disagree', 'Strongly agree', 'Strongly disagree'), 50, replace = TRUE))

我已创建此图表。

ggplot(DF, aes(x = Value, fill = SchoolYear)) +
       geom_bar(position = 'dodge', aes(y = (..count..)/sum(..count..))) +   
       geom_text(aes(y = ((..count..)/sum(..count..)), label = scales::percent((..count..)/sum(..count..))), 
                 stat = "count", vjust = -0.25, size = 2, position = position_dodge(width = 0.9)) + 
       scale_y_continuous(labels = percent) + 
       ylab("Percent") + xlab("Response") +   
       theme(axis.text.x = element_text(angle = 75, hjust = 1))

enter image description here

有没有办法让每个学年的数据加起来达到100%,但图中没有数据堆叠?

我知道这个问题类似于这个问题Create stacked barplot where each stack is scaled to sum to 100%,但我不希望图表堆叠。我无法弄清楚如何在我的问题中将解决方案应用于这种情况。此外,我不希望在绘图之前总结数据,因为我必须每次使用不同的数据多次制作此图表,并且不希望每次都必须汇总数据。

2 个答案:

答案 0 :(得分:1)

我不确定如何在不转换数据的情况下创建所需的绘图。但是,如果要为多个数据集重用相同的代码,可以编写一个函数来转换数据并同时生成图:

plot.fun <- function (original.data) {
    newDF <- reshape2::melt(apply(table(original.data), 1, prop.table))
    Plot <- ggplot(newDF, aes(x=Value, y=value)) + 
            geom_bar(aes(fill=SchoolYear), stat="identity", position="dodge") +
            geom_text(aes(group=SchoolYear, label=scales::percent(value)), stat="identity", vjust=-0.25, size=2, position=position_dodge(width=0.85)) + 
            scale_y_continuous(labels=scales::percent) + 
            ylab("Percent") + xlab("Response") +   
            theme(axis.text.x = element_text(angle = 75, hjust = 1))
    return (Plot)
}
plot.fun(DF)

答案 1 :(得分:1)

重要免责声明:高度建议您事先汇总数据,而不是尝试在ggplot内进行这些计算。这不是ggplot的意思。此外,它不仅不必要地使您的代码复杂化,而且可以轻松地引入错误/意外结果。

鉴于此,看起来你想要的是可行的(没有先总结)。通过在ggplot中进行计算得到你想要的东西的一种非常hacky方式是:

#Store factor values
fac <- unique(DF$SchoolYear)

ggplot(DF, aes(x = Value, fill = SchoolYear)) +
  geom_bar(position = 'dodge', aes(y = (..count..)/stats::ave(..count.., get("fac", globalenv()), FUN = sum))) +   
  geom_text(aes(y = (..count..)/stats::ave(..count.., get("fac", globalenv()), FUN = sum), label = scales::percent((..count..)/stats::ave(..count.., get("fac", globalenv()), FUN = sum))),
            stat = "count", vjust = -0.25, size = 2, position = position_dodge(width = 0.9)) + 
  scale_y_continuous(labels = percent) + 
  ylab("Percent") + xlab("Response") +   
  theme(axis.text.x = element_text(angle = 75, hjust = 1))

enter image description here

这会获取..count..变量,并使用stats::ave将其除以其各自组中的总和。请注意,这可能很容易搞砸

最后,我们检查情节实际上是否给了我们想要的东西。

#Check to see we have the correct values
d2 <- DF
d2 <- setDT(d2)[, .(count = .N), by = .(SchoolYear, Value)][, percent := count/sum(count), by = SchoolYear]