【问题标题】:How to add a line in boxplot?如何在箱线图中添加一条线?
【发布时间】:2018-08-09 14:36:35
【问题描述】:

我想在箱线图中的“均值”之间添加线条。

我的代码:

library(ggplot2)
library(ggthemes)

Gp=factor(c(rep("G1",80),rep("G2",80)))
Fc=factor(c(rep(c(rep("FC1",40),rep("FC2",40)),2)))
Z <-factor(c(rep(c(rep("50",20),rep("100",20)),4)))
Y <- c(0.19 , 0.22 , 0.23 , 0.17 , 0.36 , 0.33 , 0.30 , 0.39 , 0.35 , 0.27 , 0.20 , 0.22 , 0.24 , 0.16 , 0.36 , 0.30 , 0.31 , 0.39 , 0.33 , 0.25 , 0.23 , 0.13 , 0.16 , 0.18 ,  0.20 , 0.16 , 0.15 , 0.09 , 0.18 , 0.21 , 0.20 , 0.14 , 0.17 , 0.18 , 0.22 , 0.16 , 0.14 , 0.11 , 0.18 , 0.21 , 0.30 , 0.36 , 0.40 , 0.42 , 0.26 , 0.23 , 0.25 , 0.30 ,  0.27 , 0.15 , 0.29 , 0.36 , 0.38 , 0.42 , 0.28 , 0.23 , 0.26 , 0.29 , 0.24 , 0.17 , 0.24 , 0.14 , 0.17 , 0.16 , 0.15 , 0.21 , 0.19 , 0.15 , 0.16 , 0.13 , 0.25 , 0.12 ,  0.15 , 0.15 , 0.14 , 0.21 , 0.20 , 0.13 , 0.14 , 0.12 , 0.29 , 0.29 , 0.29 , 0.24 , 0.21 , 0.23 , 0.25 , 0.33 , 0.30 , 0.27 , 0.31 , 0.27 , 0.28 , 0.25 , 0.22 , 0.23 , 0.23 , 0.33 , 0.29 , 0.28 , 0.12 , 0.28 , 0.22 , 0.19 , 0.22 , 0.14 , 0.15 , 0.15 , 0.21 , 0.25 , 0.11 , 0.27 , 0.22 , 0.17 , 0.21 , 0.15 , 0.16 , 0.15 , 0.20 , 0.24 ,  0.24 , 0.25 , 0.36 , 0.24 , 0.34 , 0.22 , 0.27 , 0.26 , 0.23 , 0.28 , 0.24 , 0.23 , 0.36 , 0.23 , 0.35 , 0.21 , 0.25 , 0.26 , 0.23 , 0.28 , 0.24 , 0.23 , 0.09 , 0.16 , 0.16 , 0.14 , 0.18 , 0.18 , 0.18 , 0.12 , 0.22 , 0.23 , 0.09 , 0.17 , 0.15 , 0.13 , 0.17 , 0.19 , 0.17 , 0.11)
X <- factor(c(rep(c(rep("B1",10),rep("B2",10)),8)))
DATA=data.frame(Y,X,Z,Fc,Gp)
p <- qplot(X, Y, data=DATA, geom="boxplot", fill=Z, na.rm = TRUE, 
                    outlier.size = NA, outlier.colour = NA)  +
          facet_grid(Gp ~ Fc)+ theme_light()+scale_colour_gdocs()+
          theme(legend.position="bottom") + 
          stat_summary(fun.y=mean, geom="point", shape=23, position = position_dodge(width = .75))

我有:

以及我想要的预期情节:

我试过了

p + stat_summary(fun.y=mean, geom="line", aes(group = factor(Z)))

还有这个

p + stat_summary(fun.y=mean, geom="line", aes(group = factor(X)))

但上述方法均无效。相反,我收到以下错误消息:

geom_path:每个组仅包含一个观察值。你需要 调整群体审美? geom_path:每组只包含一个 观察。需要调整群体审美吗?几何路径: 每组仅包含一个观察值。是否需要调整 群体审美? geom_path:每组只包含一个 观察。需要调整群体审美吗?

感谢您的帮助!

【问题讨论】:

    标签: r ggplot2 line mean boxplot


    【解决方案1】:

    这里有一个替代方案:

    DATA$U <- paste(X, Z) # Extra interaction
    qplot(U, Y, data = DATA, geom = "boxplot", fill = Z, na.rm = TRUE, 
          outlier.size = NA, outlier.colour = NA) +
      facet_grid(Gp ~ Fc) + theme_light() + scale_colour_gdocs() +
      theme(legend.position = "bottom") + 
      stat_summary(fun.y = mean, geom = "point", shape = 23, position = position_dodge(width = .75)) +
      stat_summary(fun.y = mean, geom = "line", aes(group = X)) + # Lines
      scale_x_discrete(labels = rep(levels(X), each = 2)) + xlab("X") # Some fixes
    

    【讨论】:

    • 不错的选择!但在 x 轴上,我只想有 B1 和 B2,没有 B1 B1 和 B2 B2,我的意思是,我想将 B1 和 B2 的箱线图分组,正如我在问题中发表的那样。感谢您的帮助!
    • @Sh.student,我明白,但不幸的是,这是这种方法的副作用。
    • @Sh.student, stackoverflow.com/q/36240695/1320535 几乎是重复的,第二个答案提供了有关我的方法的更多详细信息。
    【解决方案2】:

    您也可以尝试 tidyverse 解决方案:

    library(tidyverse)
    DATA %>% 
       ggplot() + 
       geom_boxplot(aes(X, Y, fill=Z)) +
       stat_summary(aes(X, Y,fill=Z),fun.y = mean, geom = "point",
                    position=position_nudge(x=c(-0.185,0.185))) +
       geom_segment(data=. %>%
                      group_by(X, Z, Gp , Fc) %>% 
                      summarise(M=mean(Y)) %>% 
                      ungroup() %>% 
                      mutate(Z=paste0("C",Z)) %>% 
                      spread(Z, M), aes(x = as.numeric(X)-0.185, y = C100, 
                        xend = as.numeric(X)+0.185, yend = C50)) +
       facet_grid(Gp ~ Fc)
    

    这个想法与 d.b. 的答案相同。为 geom_segment 调用创建一个 data.frame 。优点是 dplyr 工作流程。所以一切都在一次运行中完成。

    DATA %>% 
      group_by(X, Z, Gp , Fc) %>% 
      summarise(M=mean(Y)) %>% 
      ungroup() %>% 
      mutate(Z=paste0("C",Z)) %>% 
      spread(Z, M) 
    # A tibble: 8 x 5
           X     Gp     Fc  C100   C50
    * <fctr> <fctr> <fctr> <dbl> <dbl>
    1     B1     G1    FC1 0.169 0.281
    2     B1     G1    FC2 0.170 0.294
    3     B1     G2    FC1 0.193 0.270
    4     B1     G2    FC2 0.168 0.269
    5     B2     G1    FC1 0.171 0.276
    6     B2     G1    FC2 0.161 0.292
    7     B2     G2    FC1 0.188 0.269
    8     B2     G2    FC2 0.163 0.264
    

    或者,与朱利叶斯的回答相比,您可以尝试一种稍微不同的方法。添加中断和标签以获得预期的输出,并在数字X2 和 boxplot 函数中的宽度参数上进行一些偏移,以将框绘制在一起。

    DATA %>% 
      mutate(X2=as.numeric(interaction(Z, X))) %>% 
      mutate(X2=ifelse(Z==100, X2 + 0.2, X2 - 0.2)) %>% 
      ggplot(aes(X2, Y, fill=Z, group=X2)) + 
       geom_boxplot(width=0.6) +
       stat_summary(fun.y = mean, geom = "point") +
       stat_summary(aes(group = X),fun.y = mean, geom = "line") +
       facet_grid(Gp ~ Fc) +
       scale_x_continuous(breaks = c(1.5,3.5), labels = c("B1","B2"),
                            minor_breaks = NULL, limits=c(0.5,4.5))
    

    【讨论】:

    • 感谢@Jimbou 的帮助和明确的回答!但我不明白你为什么要添加 X2+0.2 和 X2-0.2 和 break = c (1.5,3.5) ?
    • breaks = c (1.5,3.5) 设置为您想要 B1 和 B2 的分组箱线图。因此,这是介于两者之间的值。选择+/-0.2width=0.6 的偏移量,然后将 F100 和 F50 的框紧密并排绘制。
    • @Sh.student 省略scale_x_continuous部分,应该清楚。
    • 使用您的代码,我们可以消除或不显示异常值吗?使用例如:outlier.size = NA, outlier.colour = NA ...
    • 当然可以。在箱线图函数中添加outlier.color = NA
    【解决方案3】:

    这并不优雅,但试试这个

    tmp1 = aggregate(Y~., DATA[DATA$Z == 100,], mean)
    tmp2 = aggregate(Y~., DATA[DATA$Z == 50,], mean)
    tmp1$X2 = tmp2$X
    tmp1$Y2 = tmp2$Y
    
    graphics.off()
    ggplot(DATA, aes(x = factor(X), y = Y, fill = Z)) +
        geom_boxplot(width = 0.5, outlier.shape = NA) +
        geom_segment(data = tmp1,
                     aes(x = as.numeric(factor(X)) - 0.125, y = Y,
                         xend = as.numeric(factor(X2)) + 0.125, yend = Y2)) +
        facet_grid(Gp ~ Fc)
    

    【讨论】:

      【解决方案4】:

      另一种方法,诚然有点令人费解,但希望它可以避免一些硬编码。

      这个想法是构建一个包含stat_summary 调用的绘图对象。从中获取要用于线条的相关数据 (ggplot_build(p)$data[[2]])。第二个数据槽([[2]])对应于绘图调用中的第二层,即stat_summary生成的xy

      获取面板 (PANEL) 和 x 类别 (group) 的 xy 位置和索引。

      在来自绘图对象的数据中,'PANEL' 和 'group' 变量没有明确给出它们的名称,而是作为与 facet 变量的不同组合相对应的数字,以及最终将生成数字的变量x 位置(这里是“真实的”xfill)。

      但是,因为分类变量在ggplot 中是按字典顺序排列的,所以我们可以将数字与它们对应的变量进行匹配。 data.table 中的.GRP 函数在这里很方便。

      然后可以使用此数据在均值之间绘制geom_line

      # dodge value
      pos <- position_dodge(width = 0.75)
      
      # initial plot
      p <- ggplot(data = DATA, aes(x = X, y = Y, fill = Z)) +
        geom_boxplot(outlier.size = NA, outlier.colour = NA, 
                     position = pos) +
        stat_summary(fun.y = mean, geom = "point", shape = 23, position = pos) +
        facet_grid(Gp ~ Fc)
      
      # grab relevant data
      d <- ggplot_build(p)$data[[2]][ , c("PANEL", "group", "x", "y")]
      
      library(data.table)
      setDT(DATA)
      
      # select unique combinations of facet and x variables
      # here x includes the fill variable 'Z'
      d2 <- unique(DATA[ , .(Gp, Fc, Z, X)])
      
      # numeric index of facet combinations
      d2[ , PANEL := .GRP, by = .(Gp, Fc)]
      
      # numeric index of x combinations
      d2[ , group := .GRP, by = .(Z, X)]
      
      # add x and y positions by joining on PANEL and group
      d2 <- d2[d, on = .(PANEL, group)]
      
      # plot!
      p + geom_line(data = d2, aes(x = x, y = y))
      

      【讨论】:

        【解决方案5】:

        我有办法做到这一点,肯定类似于已经做过的事情,但使用 geom_lineposition_dodge 和 data.table

        library(data.table)
        DATA=data.table(Y,X,Z,Fc,Gp)
        
         qplot(X, Y, data=DATA, geom="boxplot", fill=Z, na.rm = TRUE, 
                   outlier.size = NA, outlier.colour = NA)  +
           geom_line(data = DATA[,list(Y = mean(Y)), by = .(X,Z,Fc,Gp)][X == "B1"],aes(X,Y,color = Z),group =1, position = position_dodge(width = .75),color = "black") +
           geom_line(data = DATA[,list(Y = mean(Y)), by = .(X,Z,Fc,Gp)][X == "B2"],aes(X,Y,color = Z),group =1, position = position_dodge(width = .75),color = "black") +
          facet_grid(Gp ~ Fc)+ theme_light()+
          theme(legend.position="bottom") +
          stat_summary(fun.y=mean, geom="point", shape=23, position = position_dodge(width = .75))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-03-25
          • 2016-01-26
          • 1970-01-01
          • 2020-05-22
          • 1970-01-01
          • 2012-06-28
          • 1970-01-01
          相关资源
          最近更新 更多