【问题标题】:Stacked percentage barplot with error bars in ggplot2ggplot2中带有误差条的堆叠百分比条形图
【发布时间】:2017-02-19 16:36:38
【问题描述】:

我正在尝试创建一个堆积条形图,显示数据框两列中呈现的值的百分比。

我的代码生成的堆积条形图有两个问题,我认为它们是相互关联的。

  1. ggplot2 不会让我显示 %,而是将输入值显示为 1.0 的份额。我无法用我在 SO 上环顾四周时发现的scale_y_continuous(labels = percent_format()) 修复它,所以我不知道如何解决这个问题?

  2. 我的误差线非常长。也许这是因为 SEM 是按百分比计算的,但我的图表显示的是 1.0 之外的份额。所以所有值都是我的数据框中的值的 1/100?

我的数据框:

ID Group Labeled Unlabeled
A     0       2        98
B     0       2        98
C     0       4        96
D     0       4        96
E     0       4        96
A     1      50        50
B     1      40        60
C     1      50        50
D     1      40        60
E     1      30        70
A     2      30        70
B     2      30        70
C     2      20        80
D     2      20        80
E     2      20        80
A     3      10        90
B     3      10        90
C     3       5        95
D     3      10        90
E     3       5        95
A     4       2        98
B     4       2        98
C     4       1        99
D     4       1        99
E     4       0       100

我的代码:

library(ggplot2)
library(plyr)
library(reshape2)


#Calculate means for both groups
melted <- melt(data, id.vars=c("ID", "Group"))
means <- ddply(melted, c("variable", "Group"), summarise,
           mean=mean(value))

#Draw bar plot with ggplot2
plot <- ggplot(data=means, aes(x=Group, y=mean, fill=variable)) + 
  geom_bar(stat="identity",
       position="fill",
       width = 0.4) +                           
  xlab(" ") + ylab("Percentage (%)") + 
  theme_classic(base_size = 16, base_family = "Helvetica") + 
  theme(axis.text.y=element_text(size=16, face="bold")) + 
  theme(axis.title.y=element_text(size=16, face="bold", vjust=1)) + 
  theme(axis.text.x=element_text(angle=45,hjust=1,vjust=1, size=16, face="bold")) +
  theme(legend.position="right")

# Calc SEM  
means.sem <- ddply(melted, c("variable", "Group"), summarise,
               mean=mean(value), sem=sd(value)/sqrt(length(value)))
means.sem <- transform(means.sem, lower=mean-sem, upper=mean+sem)

# Add SEM & change appearance of barplot
plotSEM <- plot + geom_errorbar(data=means.sem, aes(ymax=upper,  ymin=lower), position="fill", width=0.15) 

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    这也应该有效(您只需要调整 Labeled 变量的误差线)并且默认位置堆栈应该有效。

    plot <- ggplot(data=means, aes(x=Group, y=mean, fill=variable)) + 
      geom_bar(stat="identity",
               width = 0.4) +                           
      xlab(" ") + ylab("Percentage (%)") + 
      theme_classic(base_size = 16, base_family = "Helvetica") + 
      theme(axis.text.y=element_text(size=16, face="bold")) + 
      theme(axis.title.y=element_text(size=16, face="bold", vjust=1)) + 
      theme(axis.text.x=element_text(angle=45,hjust=1,vjust=1, size=16, face="bold")) +
      theme(legend.position="right")
    
    # Calc SEM  
    means.sem <- ddply(melted, c("variable", "Group"), summarise,
                       mean=mean(value), sem=sd(value)/sqrt(length(value)))
    means.sem <- transform(means.sem, lower=mean-sem, upper=mean+sem)
    means.sem[means.sem$variable=='Labeled',5:6] <- means.sem[means.sem$variable=='Labeled',3] + means.sem[means.sem$variable=='Unlabeled',5:6]
    
    # Add SEM & change appearance of barplot
    plotSEM <- plot + geom_errorbar(data=means.sem, aes(ymax=upper,  ymin=lower), 
                                    width=0.15)
    

    【讨论】:

    • 谢谢!由于与我写的内容接近,您的回答特别有用,因此我可以更轻松地看到我犯错的地方。当我同时运行您的代码和另一个回复的代码时,我会生成一个图表,其中“标记”部分向下,“未标记”部分向上,但误差线与您的回复中的位置相同(=倒置与图的关系)。我实际上想要“标记”分数,但我无法移动错误栏以匹配它们。我尝试使用“位置”变量,但没有任何成功。你知道我哪里失败了吗?
    • 如果是这种情况,那么您需要将means.sem[means.sem$variable=='Labeled',5:6] &lt;- means.sem[means.sem$variable=='Labeled',3] + means.sem[means.sem$variable=='Unlabeled',5:6]这一行替换为means.sem[means.sem$variable=='Unlabeled',5:6] &lt;- means.sem[means.sem$variable=='Unlabeled',3] + means.sem[means.sem$variable=='Labeled',5:6]
    【解决方案2】:
    1. 您通常需要 scales 包才能使 format_percent() 工作,但我们将为此使用自定义函数
    2. 我稍微调整了您的代码,但主要区别在于:
      1. position = 'stack' 在酒吧而不是 fill
      2. position = 'identity'stat = 'identity' 用于错误栏
      3. 每组只显示一个错误栏

    数据:

    df <- read.table(text = "ID Group Labeled Unlabeled
                 A     0       2        98
                 B     0       2        98
                 C     0       4        96
                 D     0       4        96
                 E     0       4        96
                 A     1      50        50
                 B     1      40        60
                 C     1      50        50
                 D     1      40        60
                 E     1      30        70
                 A     2      30        70
                 B     2      30        70
                 C     2      20        80
                 D     2      20        80
                 E     2      20        80
                 A     3      10        90
                 B     3      10        90
                 C     3       5        95
                 D     3      10        90
                 E     3       5        95
                 A     4       2        98
                 B     4       2        98
                 C     4       1        99
                 D     4       1        99
                 E     4       0       100", header = T)
    

    代码:

    library(ggplot2)
    library(dplyr)
    library(scales)
    
    df %>% 
      gather('key','value',-ID, -Group) %>% 
      group_by(Group, key) %>% 
      summarise(mean = mean(value),
                sem = sd(value) / sqrt(n()),
                lower = (mean - sem),
                upper = (mean + sem))-> newdf
    
    #Draw bar plot with ggplot2
    plot <- ggplot(data=newdf, aes(x=Group, y=mean, fill=key)) + 
      geom_bar(stat="identity",
               position="stack",
               width = 0.4) +
      geom_errorbar(data = filter(newdf, key == 'Unlabeled'), aes(ymax=upper,  ymin=lower), stat = 'identity', position = 'identity', width=0.15) +
      xlab(" ") + 
      ylab("Percentage (%)") +
      scale_y_continuous(labels = function(bs) {paste0(bs, '%')}) +
      theme_classic(base_size = 16, base_family = "Helvetica") + 
      theme(axis.text.y=element_text(size=16, face="bold"), 
            axis.title.y=element_text(size=16, face="bold"),
            axis.text.x=element_text(angle=45,hjust=1,vjust=1, size=16, face="bold"),
            legend.position="right")
    

    结果:

    【讨论】:

    • 谢谢你,这是一个非常有帮助的答案,我学到了很多东西,因为我从查看其他用户的问题中不明白如何使用的 scales 建议。当我运行此代码时,出于某种原因,我生成了一个图表,其中“标记”部分向下,“未标记”部分向上,但误差线与您的回复中的位置相同。我实际上想要“标记”部分,但我在将误差线置于相同位置时遇到问题。我尝试使用“位置”变量,但答案似乎不存在?
    • 这适用于 2 个类别,但不适用于多个类别。错误栏出现在错误的位置。