【问题标题】:with nested loops, creating several one-page aggregates of ggplots使用嵌套循环,创建几个 ggplots 的一页聚合
【发布时间】:2021-04-14 11:47:43
【问题描述】:

这是@Duck 非常有帮助地回答了上一个问题。 (R ggpot: Arranging on one page several ggplots created with a loop / name each plot differenly)。我希望将几个由循环创建的 ggplots 放在一页上。我做了一个模型循环,@Duck 提供了一种方法来做到这一点。它工作得非常好,以至于我的胃口更大,现在想将整个事情嵌套在另一个循环中,创建几个这样的页面(每个页面都显示来自不同年份的数据)。但是效果不好。

这是@Duck 建议的,在一页上的几个情节:

  library(dplyr)
  library(ggplot2)
  library(patchwork)
  #Create list
  List <- list()
  cylinder<-unique(mtcars$cyl)
  #Loop
  for (value in seq_along(cylinder)) {
    m<-mtcars%>%
      filter(cyl==cylinder[value])%>%
      group_by (gear)%>%
      summarise(number=n(), average=mean(mpg), se=sd(mpg))
    print(m) # reporting the numbers
    
    a<-m%>%
      mutate(gear=factor(gear, levels=unique(gear)))%>%
      ggplot()+
      geom_bar(aes(x=gear, y=average), stat = 'identity', fill ='red') +
      geom_errorbar( aes(x= gear, ymin=average-se, ymax=average+se), width=0.2, colour="black", alpha=1, size=1) +
      xlab("gears") + ylab("average mpg") +
      ggtitle (paste( "cyliner:", value ))+
      theme(axis.ticks.x=element_blank())  
    print(a)
    List[[value]]<-a}
  #Wrap plots
  wrap_plots(List,nrow = 1)
   

不错!现在,为了简单起见,假设我们只想要三个相同的。这是我尝试嵌套它的方法。


  library(dplyr)
  library(ggplot2)
  library(patchwork)
repeats<-c(1,2,3)  # for the outer loop. 
  List <- list()
  cylinder<-unique(mtcars$cyl)

    #Loop 1:
  
  for (pic in seq_along(repeats)) {
    
    # loop 2:
  
  for (value in seq_along(cylinder)) 
# same code:
    m<-mtcars%>%
      filter(cyl==cylinder[value])%>%
      group_by (gear)%>%
      summarise(number=n(), average=mean(mpg), se=sd(mpg))
    print(m) # reporting the numbers
    
    a<-m%>%
      mutate(gear=factor(gear, levels=unique(gear)))%>%
      ggplot()+
      geom_bar(aes(x=gear, y=average), stat = 'identity', fill ='red') +
      geom_errorbar( aes(x= gear, ymin=average-se, ymax=average+se), width=0.2, colour="black", alpha=1, size=1) +
      xlab("gears") + ylab("average mpg") +
      ggtitle (paste( "cyliner:", value ))+
      theme(axis.ticks.x=element_blank())  
    print(a)
    List[[value]]<-a}
  #Wrap plots
  wrap_plots(List,nrow = 1)

    List[[value]]<-a }
  #Wrap plots
  wrap_plots(List,nrow = 1)

      print (List) #reporter
  List <- list()
  print(List) #reporter
  
  }  

判断列表被填充多少次,然后归零,编译正确地通过循环。但是只制作了 6 个单图(不是 9 个),并且没有包含三个包裹图的页面。建议?

【问题讨论】:

    标签: r loops ggplot2


    【解决方案1】:

    这可以这样实现:

    1. 使用循环时,我更喜欢将绘图代码放在单独的函数中。使检查、调试和生成(在我看来)更清晰、更清晰的代码变得更容易。因此,我将绘图代码放在函数 make_plot 中。

    2. 我为您的内部循环做了同样的事情。我创建了一个函数

      inner_loop <- function(x) {
        # Create list
        List <- lapply(seq_along(cylinder), make_plot)
        # Wrap plots
        wrap_plots(List, nrow = 1)  
      }
      

    循环遍历cylinders,为每个值绘制一个图并将图粘合在一起。

    1. 在这些初始步骤之后,我们可以轻松地循环 repeats,调用函数 inner_loop,最后将生成的页面列表粘合在一起:
    repeats <- c(1,2,3)  # for the outer loop. 
    pages <- lapply(repeats, inner_loop)
    wrap_plots(pages, ncol = 1)  
    

    完全可重现的代码:

    library(dplyr)
    library(ggplot2)
    library(patchwork)
    
    cylinder <- unique(mtcars$cyl)
    
    make_plot <- function(value) {
      m <- mtcars %>%
        filter(cyl == cylinder[value]) %>%
        group_by(gear) %>%
        summarise(number = n(), average = mean(mpg), se = sd(mpg))
      #print(m) # reporting the numbers
      
      m %>%
        mutate(gear = factor(gear, levels = unique(gear))) %>%
        ggplot() +
        geom_bar(aes(x = gear, y = average), stat = "identity", fill = "red") +
        geom_errorbar(aes(x = gear, ymin = average - se, ymax = average + se), width = 0.2, colour = "black", alpha = 1, size = 1) +
        xlab("gears") +
        ylab("average mpg") +
        ggtitle(paste("cylinder:", value)) +
        theme(axis.ticks.x = element_blank())
    }
    
    inner_loop <- function(x) {
      # Create list
      List <- lapply(seq_along(cylinder), make_plot)
      # Wrap plots
      wrap_plots(List, nrow = 1)  
    }
    
    # Outer loop
    repeats <- c(1,2,3)  # for the outer loop. 
    pages <- lapply(repeats, inner_loop)
    
    wrap_plots(pages, ncol = 1)  
    

    编辑 我稍微修改了示例和代码。现在,外部循环在gears 上循环。 gear 的值作为参数传递给内部循环和绘图函数,可用于相应地过滤数据集。结果你有九个不同的情节。每个齿轮一排,圆柱为一列。

    library(dplyr)
    library(ggplot2)
    library(patchwork)
    
    make_plot <- function(value, .gear) {
      m <- mtcars %>%
        filter(cyl == cylinder[value], gear %in% .gear) %>%
        group_by(gear) %>%
        summarise(number = n(), average = mean(mpg), se = sd(mpg))
      
      m %>%
        mutate(gear = factor(gear, levels = unique(gear))) %>%
        ggplot() +
        geom_bar(aes(x = gear, y = average), stat = "identity", fill = "red") +
        geom_errorbar(aes(x = gear, ymin = average - se, ymax = average + se), width = 0.2, colour = "black", alpha = 1, size = 1) +
        xlab("gears") +
        ylab("average mpg") +
        ggtitle(paste("cylinder:", value)) +
        theme(axis.ticks.x = element_blank())
    }
    
    inner_loop <- function(gear) {
      # Create list
      List <- lapply(seq_along(cylinder), make_plot, .gear = gear)
      # Wrap plots
      wrap_plots(List, nrow = 1)  
    }
    
    # Outer loop
    cylinder <- unique(mtcars$cyl)
    gears <- unique(mtcars$gear)
     # for the outer loop. 
    pages <- lapply(gears, inner_loop)
    
    wrap_plots(pages, ncol = 1) 
    

    【讨论】:

    • 谢谢,斯特凡。但现在恐怕我的例子简单了。我试图让每个重复都对不同的年份进行相同的年龄分析,而不是重复相同的次数。也许一个更好的例子是,为每个齿轮重复圆柱效果。这就是为什么我的直觉是:以年为单位,以年龄组为单位……
    • 嗨,女孩。我已经猜到你的例子太简单了。我刚刚做了一个编辑。这有望向您展示使代码适应您的需求的一般方法。最佳 S.
    • 谢谢,斯特凡!不过,我的想法是每个齿轮一个情节。但我确实建立在你使用函数的想法之上!不是嵌套循环,而是。不同的方法,相同的最终结果——为不同的齿轮重复图表,而无需重新编写冗长的代码。我把代码作为自我回答。感谢您打开我(没有经验的)思维来使用函数!
    【解决方案2】:

    正如我所写,我最初要做的任务是在我的数据库中每年重复相同的操作;因此,我的例子可能过于简单化。更好的方法是查看汽缸 # 对每个齿轮 # 的 mpg 的影响。虽然这不是我认为的方向(循环内循环),但我可以通过将 Duck 的代码作为函数放入其中来避免重复每个齿轮的代码,正如 Stefan 所建议的那样。

    
    library(dplyr)
    library(ggplot2)
    library(patchwork)
    
    vls<-unique(mtcars$gear) #these are the values for the different plots.
    
    mltplot<-function(geer) {
      
     # the original code, with additional filtering for a specific gear:
        
      #Create list
      List <- list()
      cylinder<-unique(mtcars$cyl)
      #Loop
      for (value in seq_along(cylinder)) {
        m<-mtcars%>%
          filter(gear==geer)%>% # filtering, we look at one gear at a time.
          filter(cyl==cylinder[value])%>%
          group_by (gear)%>%
          summarise(number=n(), average=mean(mpg), se=sd(mpg))
        print(m) # reporting the numbers
        
        a<-m%>%
          mutate(gear=factor(gear, levels=unique(gear)))%>%
          ggplot()+
          geom_bar(aes(x=gear, y=average), stat = 'identity', fill ='red') +
          geom_errorbar( aes(x= gear, ymin=average-se, ymax=average+se), width=0.2, colour="black", alpha=1, size=1) +
          xlab("gears") + ylab("average mpg") +
          ggtitle (paste( "cyliner:", value ))+
          theme(axis.ticks.x=element_blank())  
        
        List[[value]]<-a}
      #Wrap plots
      wrap_plots(List,nrow = 1)
      
    }
    
    

    现在我可以要求:

    mltplot (vls[1])
    mlrplor{vls[2])
    mltplot{val[3[)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      • 2015-07-29
      • 1970-01-01
      相关资源
      最近更新 更多