Saving graphs with for loop in ggplot2

2019-07-10 00:00发布

问题:

I am kind of stuck with the for loop in ggplot2.

I am trying to adding Species and categ names to each plot title as well as the file name through the for loop in ggplot2. Somehow, the loop seems to taking only one Species name to title.

library(dplyr)
data_iris <- iris%>%
  mutate(categ=ifelse(Petal.Width<0.4,"A",ifelse(Petal.Width>=0.4&Petal.Width<=1.0, "B","C")))

> head(data_iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species categ
1          5.1         3.5          1.4         0.2  setosa     A
2          4.9         3.0          1.4         0.2  setosa     A
3          4.7         3.2          1.3         0.2  setosa     A
4          4.6         3.1          1.5         0.2  setosa     A
5          5.0         3.6          1.4         0.2  setosa     A
6          5.4         3.9          1.7         0.4  setosa     B

PLOT PART

for (i in unique(data_iris$Species)) {

for (j in unique(data_iris$categ)) {

  p = ggplot(data_iris[data_iris$categ==j,], aes(x=Sepal.Length, y=Sepal.Width)) +
    geom_point(size=3, aes(colour=categ))+

    labs(title=paste( i,j, "species_categ",sep="_")) #this part is not working!!!

  plot_list[[j]] = p
}
}  

# Save plots to tiff. Makes a separate file for each plot.


library(ggplot2)

for (i in unique(data_iris$Species)) {

for (j in unique(data_iris$categ)) {
  file_name = paste(i,j, "iris_plot_", ".tiff", sep="_")
  tiff(file_name)
  print(plot_list[[j]])
  dev.off()
}
}

ant the output is like this (I didn't add all plots and names. But you will see them in working directory)

So, as we can see the problem is here I can't get the correct Species name for each plot. I could not get it? Why this is happening ?

回答1:

Try this. Your indexing is wrong. I would probably store the plots differently in the first place - maybe in a list of lists.

ind <- 1 # initialise the index for storing

for (i in unique(data_iris$Species)) {
  for (j in unique(data_iris$categ)) {

    p <- ggplot(data_iris[data_iris$categ==j,], aes(x=Sepal.Length, y=Sepal.Width)) +
      geom_point(size=3, aes(colour=categ))+

      labs(title=paste( i,j, "species_categ",sep="_")) 

    plot_list[[ind]] <- p  # stor the plot
    ind <- ind + 1         # increment   
  }
}  

ind <- 1
for (i in unique(data_iris$Species)) {
  for (j in unique(data_iris$categ)) {

    file_name = paste(i,j, "iris_plot_", ".tiff", sep="_")
    tiff(file_name)
    print(plot_list[[ind]]) # use the same index to retrieve the plot
    ind <- ind + 1
    dev.off()
  }
}

setosa_A_iris_plot__

setosa_B_iris_plot__



回答2:

A solution using purrr::map, walk & iwalk in the tidyverse framework

library(tidyverse)

data_iris <- iris%>%
  as_tibble() %>% 
  mutate(categ = ifelse(Petal.Width < 0.4, "A",
                        ifelse(Petal.Width >= 0.4 & Petal.Width <= 1.0, "B", "C")))
data_iris

#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species categ
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <chr>
#>  1          5.1         3.5          1.4         0.2 setosa  A    
#>  2          4.9         3            1.4         0.2 setosa  A    
#>  3          4.7         3.2          1.3         0.2 setosa  A    
#>  4          4.6         3.1          1.5         0.2 setosa  A    
#>  5          5           3.6          1.4         0.2 setosa  A    
#>  6          5.4         3.9          1.7         0.4 setosa  B    
#>  7          4.6         3.4          1.4         0.3 setosa  A    
#>  8          5           3.4          1.5         0.2 setosa  A    
#>  9          4.4         2.9          1.4         0.2 setosa  A    
#> 10          4.9         3.1          1.5         0.1 setosa  A    
#> # ... with 140 more rows

# Split based on species and categories
# Remove lists having 0 row
data_iris %>% 
  split(list(.$Species, .$categ)) %>% 
  discard(function(x) nrow(x) == 0) -> df_split

# For all species and categories
plots <- map(df_split,  
             ~ ggplot(.x, aes(x = Sepal.Length, y = Sepal.Width)) +
               geom_point(size = 3, aes(colour = categ))+
               theme_bw(base_size = 16) +
               labs(title = paste0("Species: ", .x$Species, " | Category: ", .x$categ)))

# Check the 1st plot
plots[[1]]

# Display all plots using purrr::walk
walk(plots, print) 

# Save all plots using purrr::iwalk
iwalk(plots,  
     ~ ggsave(plot = .x,
              filename = paste0("./img/", .y, ".tiff"))
     )

Created on 2018-05-16 by the reprex package (v0.2.0).



回答3:

I figured out just adding Species_categ column and run it through the loop is seems to be less complex.

data_iris <- iris%>%
  mutate(categ=ifelse(Petal.Width<0.4,"A",ifelse(Petal.Width>=0.4&Petal.Width<=1.0, "B","C")))%>%
  unite(Species_categ,Species,categ,remove=F) #added this line

plot_list = list()

for (i in unique(data_iris$Species_categ)) {

  p = ggplot(data_iris[data_iris$Species_categ==i,], aes(x=Sepal.Length, y=Sepal.Width)) +
    geom_point(size=3, aes(colour=categ))+

    labs(title=paste( i, "species_categ",sep="_"))

  plot_list[[i]] = p
}


    # Save plots to tiff. Makes a separate file for each plot.
    for (i in unique(data_iris$Species_categ)) {

      file_name = paste(i, "iris_plot_2", ".tiff", sep="_")
      tiff(file_name)
      print(plot_list[[i]])
      dev.off()
    }