【问题标题】:R: facet_grid plot of differences between groups using ggplot2R:使用 ggplot2 的组间差异的 facet_grid 图
【发布时间】:2017-03-24 17:58:01
【问题描述】:

我正在尝试创建一系列图表来显示测量变量组之间的差异,并正在寻找一种有效的方法来使用 R 中 ggplot2facet_grid 功能。

这是一个说明性示例:

# sample input data
df <- data.frame(year=rep(c(2011:2015), 2), 
                 value=c(0:4, 1:5),
                 scenario=rep(c("a","b"), each=5))

# make a sample plot
p <- 
  ggplot(df, aes(x=year, y=value)) +
  geom_point() + geom_line() +
  facet_grid(scenario ~ scenario)

这将生成以下示例图,其中value 针对每个场景组合分别针对year 绘制:

(我假设第二行没有绘制,因为它与第一行相同)。

但是,我正在寻找的是一个情节,其中在每个方面,(顶部场景中的值)-(右侧场景中的值)按年份绘制。具体来说:

  • 对于所有年份,左上图将是(值 a)-(值 a)= 0。
  • 所有年份的右上图将是 (值 b) - (值 a) = 1。
  • 所有年份的左下图将是(值 a)-(值 b)= -1。
  • 所有年份的右下图将是(值 b)-(值 b)= 0

我无法找到facet_grid 的任何内置或自动差异命令。我最初的想法是将函数作为y 参数传递给ggplot,但鉴于数据框有一个value 列,我被难住了。我猜可能有一个使用dplyrreshape2 组合的解决方案,但我无法理解如何实现它。

【问题讨论】:

    标签: r plot ggplot2 reshape facet


    【解决方案1】:

    你想要类似下面的东西吗?

    dflist <- split(df, df$scenario)
    df <- rbind(merge(dflist$a, dflist$a, by='year'),
          merge(dflist$a, dflist$b, by='year'),
          merge(dflist$b, dflist$a, by='year'),
          merge(dflist$b, dflist$b, by='year'))
    df$value <- df$value.x - df$value.y
    ggplot(df, aes(x=year, y=value)) +
      geom_point() + geom_line() +
      facet_grid(scenario.x ~ scenario.y)
    

    【讨论】:

      【解决方案2】:

      这是一个选项,使用从tidyr 到首先spread 的数据来计算对比度,然后将gather 重新组合在一起以允许绘图:

      forPlotting <-
        df %>%
        spread(scenario, value) %>%
        mutate(`a - b` = a - b
               , `b - a` = b - a
               , `a - a` = 0
               , `b - b` = 0) %>%
        gather(Comparison, Difference, -(year:b) ) %>%
        separate(Comparison, c("First Val", "Second Val"), " - ")
      

      这样会返回一个 data.frame(只是这里的头部):

        year a b First Val Second Val Difference
      1 2011 0 1         a          b         -1
      2 2012 1 2         a          b         -1
      3 2013 2 3         a          b         -1
      4 2014 3 4         a          b         -1
      5 2015 4 5         a          b         -1
      6 2011 0 1         b          a          1
      

      你可以像这样绘制:

      ggplot(forPlotting
             , aes(x = year, y = Difference)) +
        geom_point() + geom_line() +
        facet_grid(`First Val` ~ `Second Val`)
      

      更大的问题是为什么你想这样做。我假设您已经知道将这两个集合绘制为不同的颜色线更容易可视化:

      ggplot(df, aes(x=year, y=value, col = scenario)) +
        geom_point() + geom_line()
      

      所以,我假设您有更复杂的数据 - 具体来说,有更多列要比较。因此,这里有一种方法可以自动化(并简化)多个列的上述许多步骤。方法基本相同,但它使用mutate_ 允许您传入包含您尝试创建的列的向量。

      df <-
        data.frame(
          year = 2011:2015
          , a = 0:4
          , b = 1:5
          , c = 2:6
          , d = 3:7
        )
      
      allContrasts <-
        outer(colnames(df)[-1]
              , colnames(df)[-1]
              , paste
              , sep = " - ") %>%
        as.character() %>%
        setNames(., .) %>%
        as.list()
      
      forPlotting <-
        df %>%
        mutate_(.dots = allContrasts) %>%
        select(-(a:d)) %>%
        gather(Comparison, Difference, -year ) %>%
        separate(Comparison, c("First Val", "Second Val"), " - ") %>%
        filter(`First Val` != `Second Val`)
      
      ggplot(forPlotting
             , aes(x = year, y = Difference)) +
        geom_point() + geom_line() +
        facet_grid(`First Val` ~ `Second Val`) +
        theme(axis.text.x = element_text(angle = 90))
      

      给出这个:

      为什么我不能不理会这个?我只是太喜欢玩标准评估了。如果您有非解析列名(例如,带有空格的东西),上述将失败。因此,这里有一个这样的列名示例,显示了添加反引号以确保正确解析列。

      df <-
        data.frame(
          year = 2011:2015
          , value = c(0:4, 1:5, 2:6, 3:7)
          , scenario = rep(c("Unit 1", "Exam 2"
                             , "Homework", "Final Exam")
                           , each = 5)
        ) %>%
        spread(scenario, value)
      
      allContrasts <-
        outer(paste0("`", colnames(df)[-1], "`")
              , paste0("`", colnames(df)[-1], "`")
              , paste
              , sep = " - ") %>%
        as.character() %>%
        setNames(., .) %>%
        as.list()
      
      forPlotting <-
        df %>%
        mutate_(.dots = allContrasts) %>%
        select_(.dots = paste0("-`", colnames(df)[-1], "`")) %>%
        gather(Comparison, Difference, -year ) %>%
        separate(Comparison, c("First Val", "Second Val"), " - ") %>%
        filter(`First Val` != `Second Val`) %>%
        mutate_each(funs(gsub("`", "", .)), `First Val`, `Second Val`)
      
      ggplot(forPlotting
             , aes(x = year, y = Difference)) +
        geom_point() + geom_line() +
        facet_grid(`First Val` ~ `Second Val`) +
        theme(axis.text.x = element_text(angle = 90))
      

      【讨论】:

      • 太棒了,谢谢马克 - 你说得对,我的原因是我的真实数据中有更多的列和行。自动化解决方案看起来不错,我会在真实数据集上尝试一下!
      • 很高兴它有帮助。我刚刚添加了一个编辑以说明可能导致问题的列名(例如空格或特殊字符)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-13
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 2013-08-12
      • 2017-08-08
      • 1970-01-01
      相关资源
      最近更新 更多