【问题标题】:Plot quantiles of distribution in ggplot2 with facets用刻面绘制 ggplot2 中的分布分位数
【发布时间】:2015-08-14 15:21:00
【问题描述】:

我目前正在从 ggplot 中的许多回归模型中绘制许多不同的一阶差异分布。为了便于解释差异,我想标记每个分布的 2.5% 和 97.5% 百分位数。由于我将绘制很多图,并且因为数据是按二维(模型和类型)分组的,所以我想在 ggplot 环境中定义和绘制相应的百分位数。使用构面绘制分布可以让我准确地到达我想要的位置,除了百分位数。我当然可以更手动地执行此操作,但理想情况下,我希望找到一个我仍然能够使用facet_grid 的解决方案,因为这让我在尝试将不同的情节组合在一起时省去了很多麻烦。

这是一个使用模拟数据的示例:

df.example <- data.frame(model = rep(c("a", "b"), length.out = 500), 
                      type = rep(c("t1", "t2", "t2", "t1"), 
                      length.outh = 250), value = rnorm(1000))

 ggplot(df.example, aes(x = value)) +
 facet_grid(type ~ model) +
 geom_density(aes(fill = model, colour = model))

我尝试通过两种方式添加分位数。第一个产生错误消息:

 ggplot(df.example, aes(x = value)) +
 facet_grid(. ~ model) +
 geom_density(aes(fill = model, colour = model)) +
 geom_vline(aes(x = value), xintercept = quantile(value, probs = c(.025, .975)))
Error in quantile(value, probs = c(0.025, 0.975)) : object 'value' not found

而第二个给我的是完整变量的分位数,而不是子密度的分位数。也就是说,绘制的分位数对于所有四种密度都是相同的。

 ggplot(df.example, aes(x = value)) +
 facet_grid(type ~ model) +
 geom_density(aes(fill = model, colour = model)) +
 geom_vline(xintercept = quantile(df.example$value, probs = c(.025, .975)))

因此,我想知道是否有办法为 ggplot2 环境中的每个子组绘制特定分位数?

非常感谢任何意见。

【问题讨论】:

    标签: r ggplot2 quantile density-plot


    【解决方案1】:

    使用 plyr(或 dplyr、data.table)预计算这些值 ...

    set.seed(1)
    # ...
    
    df.q <- ddply(df.example, .(model, type),
                  summarize, q=quantile(value, c(.025, .975)))    
    p + geom_vline(aes(xintercept=q), data=df.q)
    

    【讨论】:

    • 很好的建议。谢谢!
    【解决方案2】:

    您可以预先计算分位数。

    使用您的示例数据:

    library (dplyr)
    d2 <- df.example %>%
      group_by(model, type) %>%
      summarize(lower = quantile(value, probs = .025),
                upper = quantile(value, probs = .975))
    

    然后像这样绘制:

    ggplot(df.example, aes(x = value)) +
      facet_grid(type ~ model) +
      geom_density(aes(fill = model, colour = model)) +
      geom_vline(data = d2, aes(xintercept = lower)) +
      geom_vline(data = d2, aes(xintercept = upper))
    

    【讨论】:

    • 很好的建议。谢谢!
    【解决方案3】:

    现在,可以使用 stat_summary()orientation 选项 无需预先计算即可获得相同的结果。

    为每个面板定义一个虚拟 y 值,以将观察结果与 orientation = "y"。然后使用自定义fun 计算向量 stat_summary() 中每个面板的所需分位数。显示结果 作为垂直线,指定geom = "vline" 及其所需的xintercept 从美学中计算出的x 值和xintercept = after_stat(x) 规范,现在使用fun 计算的结果。

    library(ggplot2)
    
    set.seed(1)
    
    df.example <- data.frame(
      model = rep(c("a", "b"), length.out = 500),
      type = rep(c("t1", "t2", "t2", "t1"),
        length.outh = 250
      ), value = rnorm(1000)
    )
    
    ggplot(df.example, aes(x = value)) +
      facet_grid(type ~ model) +
      geom_density(aes(fill = model, colour = model)) +
      stat_summary(
        geom = "vline",
        orientation = "y",
        # y is a required aesthetic, so use a dummy value
        aes(y = 1, xintercept = after_stat(x)),
        fun = function(x) {
          quantile(x, probs = c(0.025, 0.975))
        }
      )
    

    【讨论】:

    • (+1) 如果你使用fun 而不是fun.data,你可以让它稍微简单一点:stat_summary(aes(y = 1, xintercept = after_stat(x)), fun = function(x) quantile(x, probs = c(0.025, 0.975)), geom = "vline", orientation = "y")
    • stat_summary(aes(y = 1, xintercept = after_stat(x)), fun = quantile, fun.args = list(probs = c(0.025, 0.975)), geom = "vline", orientation = "y")
    • @Axeman 啊,是的,感谢您指出这一点。那会更简单。现在想到的另一种方法是保留fun.data,但将数据框更改为有一个名为yintercept 的列,并将xintercept = stat(x)aes() 中完全删除。
    • 也就是说,我认为fun 方法确实更容易记住。我已经对其进行了编辑,仍然偏爱匿名函数,因为我个人觉得它更具可读性。再次感谢!
    【解决方案4】:

    好问题。同一个问题的更一般的版本是:在使用构面时如何调用子集数据集上的函数?这似乎是一个非常有用的功能,所以我四处搜索,但找不到任何关于它的信息。

    已经给出的答案非常好。另一种选择是使用multiplot() 作为手动进行分面的一种方式。

    【讨论】:

    • 我同意。两种解决方案都非常简洁,但是,正如您所指出的,并不能真正解决我在问题中提出的问题。这确实是 ggplot 的一个非常有趣的功能。
    猜你喜欢
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多