Using a For Loop to Make ggplot2 Plots and Save Them

Hi there, I am having a lot of trouble getting my for loop to work for this dataset (df called my_data) of 26 columns. I am trying to make a graph for each of 23 variables that are arranged as 23 columns, following 3 columns for intervention(Arm), ID, and timepoint (Time).
When I execute the code I get an error (I've gotten many, but as my code stands now this is the error):
Error in aes_string(x = Time, y = i, group = Arm, color = Arm, fill = Arm) :
object 'Arm' not found

I've tried using aes alone and aes_string. I've tried using my_data$ before all my variables too, but that did not solve the problem. I know my plot command is working because when i try individually plugging in my variables it generates the plot that I want. But trying to be a good programmer and not copy paste dozens of times...

This is the general structure below. I'm masking my arm variable. All the variables I want plotted, e.g. LowEnergy, Yawning, have the same numeric structure(21 more than shown here). I've never asked a question in this type of format, but hopefully the information here is enough for a reproducible example which I got by using dput() of a random sample of my data.

library(ggplot2)
my_data <- structure(list(Arm = c("Pe", "Sel", "Pe", "Sel","Sel"), ID = c(30, 1, 32, 1, 29), Time = c(3, 0, 3, 3, 2),LowEnergy = c(1, 1, 1, 1, 1), Yawning = c(1, 1, 1, 1, 1), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame")))

loop.list <- names(my_data[, c(-1,-2,-3)]) #note that this index would only work with my full dataset, where I was attempting to tell it to skip my Arm/ID/Time and go through the list of variables (LowEnergy, Yawning, and all those that come after it).

for (i in seq_along(loop.list)) { 

plot <- ggplot(my_data, aes_string(x = Time, y = i, group= Arm, color = Arm, fill=Arm)) + geom_bar(position="dodge", stat="identity") + facet_wrap(~ID, ncol=10) +ylim(0,5) +xlab("Time Point")+ylab("")+ggtitle("")+ theme(legend.title = element_blank(), legend.position = "top", panel.background = element_blank(),axis.line = element_line(colour = "darkgrey"))

pdf(paste0("10.13.20_",loop.list[i],".pdf"))
print(plot)
dev.off()
}

Insight would be so, very appreciated. Thank you. UPDATE!
Somehow... when I re-run the exact same code in base R the code works and saves/names my files appropriately BUT most of my plots came out blank (18 of the 23), and the rest came out with all individuals for each variable to have the same exact values(wrong). Any other ideas??

Note: saving worked with this original method:
pdf(paste0("10.15.20_",loop.list[i],".pdf"))
print(plot)
dev.off()

Try using ggsave instead of pdf. That might be all you need.

Edit
Yep, just confimed using ggsave(paste0("10.13.20_", loop.list[1], ".pdf")) results in

image

Somehow... when I re-run the exact same code in base R the code works and saves/names my files appropriately BUT most of my plots came out blank (18 of the 23), and the rest came out with all individuals for each variable to have the same exact values(wrong).

Note: saving worked with this original method:
pdf(paste0("10.15.20_",loop.list[i],".pdf"))
print(plot)
dev.off()

This is another option using nested dataframes and purrr::walk2() instead of a loop

library(tidyverse)

my_data <- data.frame(
  stringsAsFactors = FALSE,
               Arm = c("Pe", "Sel", "Pe", "Sel", "Sel"),
                ID = c(30, 1, 32, 1, 29),
              Time = c(3, 0, 3, 3, 2),
         LowEnergy = c(1, 1, 1, 1, 1),
           Yawning = c(1, 1, 1, 1, 1)
)

my_data %>% 
    gather(variable, value, LowEnergy:Yawning) %>% 
    group_nest(variable) %>% 
    mutate(plot = map(data, ~ggplot(.x, aes(x = Time, y = value, group = Arm, color = Arm, fill = Arm)) +
               geom_col(position = "dodge") +
               facet_wrap(~ID, ncol=10) + 
               ylim(0,5) + 
               xlab("Time Point") + 
               ylab("") + 
               ggtitle("") + 
               theme(legend.title = element_blank(),
                     legend.position = "top",
                     panel.background = element_blank(),
                     axis.line = element_line(colour = "darkgrey")
                     )
               )
           ) %>% 
    walk2(.x = .$variable,
          .y = .$plot,
          .f = ~ ggsave(filename = paste0("10.13.20_", .x, ".pdf"),
                        plot = .y)
          )

Hi Andres thanks for the suggestion. Ideally someone will still respond about solving this in a for loop so that I can understand what the problem is.

I would be happy to learn another method too. Could you walk me through some of this. You call variable and value but I don't see those defined anywhere. Also, what was the purpose of the group_nest() command?

I define those when I reshape your data frame into a long format

my_data %>% 
    gather(variable, value, LowEnergy:Yawning)
#>    Arm ID Time  variable value
#> 1   Pe 30    3 LowEnergy     1
#> 2  Sel  1    0 LowEnergy     1
#> 3   Pe 32    3 LowEnergy     1
#> 4  Sel  1    3 LowEnergy     1
#> 5  Sel 29    2 LowEnergy     1
#> 6   Pe 30    3   Yawning     1
#> 7  Sel  1    0   Yawning     1
#> 8   Pe 32    3   Yawning     1
#> 9  Sel  1    3   Yawning     1
#> 10 Sel 29    2   Yawning     1

The purpose of this is to make nested data frames by each one of the selected variables, think of this as a data frame of data frames.

my_data %>% 
    gather(variable, value, LowEnergy:Yawning) %>% 
    group_nest(variable)
#> # A tibble: 2 x 2
#>   variable                data
#>   <chr>     <list<tbl_df[,4]>>
#> 1 LowEnergy            [5 × 4]
#> 2 Yawning              [5 × 4]
1 Like

Thanks for clarifying, that makes a lot of sense now!