【问题标题】:Add group mean line to barplot with ggplot2使用 ggplot2 将组平均线添加到条形图
【发布时间】:2018-11-25 16:45:16
【问题描述】:

我使用 geom_col() 生成一个条形图,其中两个类由颜色分隔。然后我尝试为每个班级添加一条平均线。

这是我想要的:

但是在平均线下方的代码中,每个条都是独立的,我将其放入 group 参数中。

这是一个可重现的例子:

library(tidyverse)

df = data.frame(
  x = 1:10,
  y = runif(10),
  class = sample(c("a","b"),10, replace=T) %>% factor()
) %>% 
  mutate(x = factor(x, levels=x[order(class, -y)]))

ggplot(df, aes(x, y, fill=class)) +
geom_col() +
stat_summary(fun.y = mean, geom = "errorbar", 
             aes(ymax = ..y.., ymin = ..y.., group = class),
             width = 1, linetype = "solid")

请告诉我我做错了什么。或任何其他方式(使用ggplot)来实现这一点?

【问题讨论】:

    标签: r ggplot2 bar-chart


    【解决方案1】:

    我将 @bouncyball 的解决方案与我使用 `geom_errorbar 的原始方法相结合。

    代码如下:

    df.mean = df %>% 
      group_by(class) %>% 
      mutate(ymean = mean(y))
    
    ggplot(df, aes(x, y, fill=class)) +
      geom_col() +
      geom_errorbar(data=df.mean, aes(x, ymax = ymean, ymin = ymean),
                   size=0.5, linetype = "longdash", inherit.aes = F, width = 1)
    

    唯一的问题是,这种方法不是生成单线,而是生成许多线对象,在编辑绘图时可以看到这些对象,例如在 Adob​​e Illustrator 中。但我可以忍受它。

    更新

    另一种解决方案 - 更简单且没有上述问题。再次基于来自@bouncyball 的代码。

    df.mean = df %>% 
      group_by(class) %>% 
      summarise(ymean = mean(y), x1 = x[which.min(x)], x2 = x[which.max(x)]) %>% 
      ungroup()
    
    ggplot(df) +
      geom_col(aes(x, y, fill = class)) +
      geom_segment(data = df.mean,
                   aes(x = as.integer(x1) - 0.5, xend = as.integer(x2) + 0.5,
                       y = ymean, yend = ymean),
                   size=1, linetype = "longdash", inherit.aes = F)
    

    【讨论】:

      【解决方案2】:

      创建一个新的data.frame(添加一个组均值)并对其进行一些操作(使用top_ncbind),然后使用它们为geom_segment 提供必要的美感:

      # add group mean
      df_m <- df %>%
        group_by(class) %>%
        mutate(my = mean(y)) %>%
        arrange(class) # added from comment by @Yuk
      
      # select top and bottom x for each class group
      # use cbind to keep one row per group
      df_m2 <- df_m %>%
        top_n(1, x) %>%
        cbind(top_n(df_m, -1, x))
      
      ggplot(df) +
        geom_col(aes(x, y, fill=class))+
        geom_segment(data = df_m2,
                     aes(x = x, xend = x1,
                         y = my, yend = my1,
                         group = class))
      

      【讨论】:

      • 谢谢!不错的解决方案!两个问题。首先,top_n 可以按不同的顺序拾取类,并导致 cbind 的结果不正确。需要加dm %&gt;% arrange(class) %&gt;%。其次,有没有办法将线条扩大到左右整个条形?
      • @yuk 你说得对arrange,使用inner_join 可能比top_n 更安全...
      【解决方案3】:

      用你现有的 ggplot,试试这个代码:

      +
      geom_hline(data = [*name of data frame*], aes(yintercept = mean(*name of the variable*), color = "red")
      

      【讨论】:

      • 你真的试过这个代码吗? geom_hline 在整个地块上为每个类画线。我已经先测试过了。抱歉,这不是解决方案。
      • @yuk,实际上它对我有用。我建议对代码进行修改以使其更加明确。
      • @Tiny_hopper:我又试了一次,认为 ggplot2 可能有一些更新的行为。但不,是一样的。如果它对您有用,您能否发布整个代码以重现?也许作为结果图的另一个答案。
      • @yuk 请看下面的答案。
      【解决方案4】:

      我将此添加为答案,因为@Ryan 给出的先前答案似乎是部分答案,并且不包含@yuk 要求的整个代码块。

      如果 df2 是您的数据框,其中包含以下代码中使用的 sitespCount_site 列:

      library (ggplot2)
      p <- ggplot(data = df2, aes(x = site, y = spCount_site)) +
        geom_bar(stat = "identity", fill = rainbow(nrow(df2))) +
        geom_hline(yintercept = mean(df2$spCount_site), color="black") # a horizontal line of black color will be drawn at a height using the mean of `spCount_site` column
      p
      

      下面的图片是我根据自己的数据使用上面的代码创建的

      【讨论】:

      • 看,这正是我所说的——整个数据集只能得到一条水平线,而不是单个组。
      • @yuk 此代码块适用于一个水平条,但如果您需要多个组的多个条,那么第一个(顶部)答案应该可以工作。这只是操纵代码的问题。
      猜你喜欢
      • 2021-02-20
      • 2018-03-31
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-02
      相关资源
      最近更新 更多