【问题标题】:Looping over variables in ggplot在ggplot中循环变量
【发布时间】:2011-06-18 21:58:58
【问题描述】:

我想使用 ggplot 循环遍历多个列以创建多个绘图,但是在 for 循环中使用占位符会改变 ggplot 的行为。

如果我有这个:

t <- data.frame(w = c(1, 2, 3, 4), x = c(23,45,23, 34), 
y = c(23,34,54, 23), z = c(23,12,54, 32))

这很好用:

ggplot(data=t, aes(w, x)) + geom_line()

但这不是:

i <- 'x'
ggplot(data=t, aes(w, i)) + geom_line()

如果我想最终遍历 x、y 和 z,这是一个问题。 有什么帮助吗?

【问题讨论】:

  • 一般ggplot2更适合长格式的data.frames,即m = melt(t, id="w") ; ggplot(subset(m, variable == "x"), aes(w, value)) + geom_line()p &lt;- ggplot(m, aes(w, value)) + geom_line(aes(colour=variable),或d_ply(m, .(variable), function(d) p %+% d, .print=TRUE)等。

标签: r for-loop ggplot2 tidyeval nse


【解决方案1】:

你只需要使用aes_string而不是aes,像这样:

ggplot(data=t, aes_string(x = "w", y = i)) + geom_line() 

注意w 也需要指定为字符串。

【讨论】:

    【解决方案2】:

    2018年7月发布的ggplot2 v3.0.0支持!!(砰砰)内aes()等整齐评价。所以我们可以做到以下几点:

    • 构建一个将 x- 和 y- 列名称作为输入的函数。注意rlang::sym & !! 的使用。

    • 然后使用purrr::map遍历每一列。

    library(rlang)
    library(tidyverse)
    
    dt <- data.frame(
      w = c(1, 2, 3, 4), x = c(23, 45, 23, 34),
      y = c(23, 34, 54, 23), z = c(23, 12, 54, 32)
    )
    

    定义一个接受字符串作为输入的函数

    plot_for_loop <- function(df, .x_var, .y_var) {
    
      # convert strings to variable
      x_var <- sym(.x_var)
      y_var <- sym(.y_var)
    
      # unquote variables using !! 
      ggplot(df, aes(x = !! x_var, y = !! y_var)) + 
        geom_point() + 
        geom_line() +
        labs(x = x_var, y = y_var) +
        theme_classic(base_size = 12)
    }
    

    遍历每一列

    plot_list <- colnames(dt)[-1] %>% 
      map( ~ plot_for_loop(dt, colnames(dt)[1], .x))
    
    # view all plots individually (not shown)
    plot_list
    
    # Combine all plots
    library(cowplot)
    plot_grid(plotlist = plot_list,
              ncol = 3)
    

    编辑:上面的函数也可以写成没有sym!!使用.data[[]]代词

    plot_for_loop2 <- function(df, x_var, y_var) {
    
      ggplot(df, aes(x = .data[[x_var]], y = .data[[y_var]])) + 
        geom_point() + 
        geom_line() +
        labs(x = x_var, y = y_var) +
        theme_classic(base_size = 12)
    }
    

    或者我们可以在将数据帧从宽格式转换为长格式后使用facet_grid/facet_wraptidyr::gather

    dt_long <- dt %>% 
      tidyr::gather(key, value, -w)
    dt_long
    #>    w key value
    #> 1  1   x    23
    #> 2  2   x    45
    #> 3  3   x    23
    #> 4  4   x    34
    #> 5  1   y    23
    #> 6  2   y    34
    #> 7  3   y    54
    #> 8  4   y    23
    #> 9  1   z    23
    #> 10 2   z    12
    #> 11 3   z    54
    #> 12 4   z    32
    
    ### facet_grid
    ggp1 <- ggplot(dt_long, 
           aes(x = w, y = value, color = key, group = key)) +
      facet_grid(. ~ key, scales = "free", space = "free") +
      geom_point() + 
      geom_line() +
      theme_bw(base_size = 14)
    ggp1
    

    ### facet_wrap
    ggp2 <- ggplot(dt_long, 
           aes(x = w, y = value, color = key, group = key)) +
      facet_wrap(. ~ key, nrow = 2, ncol = 2) +
      geom_point() + 
      geom_line() +
      theme_bw(base_size = 14)
    ggp2
    

    ### bonus: reposition legend
    # https://cran.r-project.org/web/packages/lemon/vignettes/legends.html
    library(lemon)
    reposition_legend(ggp2 + theme(legend.direction = 'horizontal'), 
                      'center', panel = 'panel-2-2')
    

    【讨论】:

    【解决方案3】:

    问题在于您如何访问数据框t。您可能知道,有几种方法可以做到这一点,但不幸的是,在ggplot 中使用字符显然不是其中之一。

    一种可行的方法是在您的示例中使用列的数字位置,例如,您可以尝试i &lt;- 2。但是,如果这项工作依赖于我从未使用过的 ggplot(但我知道 Hadley 的其他工作,我想它应该可以工作)

    另一种规避方法是在每次调用 ggplot 时创建一个新的临时数据框。例如:

    tmp <- data.frame(a = t[['w']], b = t[[i]])
    ggplot(data=tmp, aes(a, b)) + geom_line()
    

    【讨论】:

    • 我之前也使用过数字索引,这对于遍历数据集中的每一列非常有用。不过,每当我不得不假设 t$x 将永远是 t[ , 2] 时,我都会感到紧张。
    • 太好了,谢谢。我确定我将来需要这个解决方法。
    • 这不适用于更复杂的 ggplots(例如,那些使用构面的)。
    • @Gregor 如果您提出一个新问题,并提供一个可重现的示例,我想有人可以帮助您。
    • aes_string() 方法(在 Matt Parker 的回答中)适用于一般情况。我只是在评论,所以任何使用这个答案的人都知道它的局限性。
    【解决方案4】:

    根据您要执行的操作,我发现facet_wrapfacet_grid 可以很好地创建具有相同基本结构的多个绘图。这样的事情应该会让你进入正确的范围:

    t.m = melt(t, id="w")
    ggplot(t.m, aes(w, value)) + facet_wrap(~ variable) + geom_line()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多