2

I want to run through six similar dataframes and print out six plots using ggplot.

My code works when I run the plots separately but I can't get ggplot to run six times using a for loop. My six dataframes are the six animals listed in gg_pets.

cat <- data.frame(Breed = c("American Shorthair","Ragdoll","Persian","Sphynx","Maine Coon"), 
Longevity = c("17","19","15","17","20"))

dog <- data.frame(Breed = c("Havanese","Bulldog","Beagle","Chihuahua","Poodle"), 
Longevity = c("20","11","12","15","16"))

#etc for types of birds, fish, snakes, and ferrets

#the following works
plot <- ggplot(data = cat, aes(x = Breed, y = Longevity, fill = Breed)) + 
  geom_bar(stat = "identity", position = position_dodge()) +
  xlab("Breed") +
  ylab("Longevity") +
  ggtitle("cat") +
  geom_text(aes(label = Longevity), vjust = -0.3, color = "black", size = 3.5) +
  theme(axis.line = element_line(color = "black"), axis.text = element_text(color = "black"), 
        legend.position = "none", plot.title = element_text(hjust = .5),
        panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
        panel.border = element_rect(color = "black", fill = NA, size = 0.8),
        panel.background = element_rect(fill = NA), text = element_text(size=10))
print(plot)

gg_pets <- c("cat","dog","bird","fish","snake","ferret")

#the following does not work
for (i in 1:length(gg_pets)){
    plot <- ggplot(data = [i], aes(x = Breed, y = Longevity, fill = Breed)) + 
    geom_bar(stat = "identity", position = position_dodge()) +
    xlab("Breed") +
    ylab("Longevity") +
    ggtitle([i]) +
    geom_text(aes(label = Longevity), vjust = -0.3, color = "black", size = 3.5) +
    theme(axis.line = element_line(color = "black"), axis.text = element_text(color = "black"), 
          legend.position = "none", plot.title = element_text(hjust = .5),
          panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
          panel.border = element_rect(color = "black", fill = NA, size = 0.8),
          panel.background = element_rect(fill = NA), text = element_text(size=10))
    print(plot)
}

3 Answers 3

3

In your example gg_pets is just a vector of strings. You need to concatenate the data frames in order to iterated over them in the for-loop. You can do it with a list. As follows. You can use the names of the items as a title.

...
gg_pets <- list(cat=cat, dog=dog)

#the following does not work
for (i in 1:length(gg_pets)) {
  plot <- ggplot(data = gg_pets[[i]], aes(x = Breed, y = Longevity, fill = Breed)) + 
    geom_bar(stat = "identity", position = position_dodge()) +
    xlab("Breed") +
    ylab("Longevity") +
    ggtitle(names(gg_pets)[i]) +
    geom_text(aes(label = Longevity), vjust = -0.3, color = "black", size = 3.5) +
    theme(axis.line = element_line(color = "black"), axis.text = element_text(color = "black"), 
          legend.position = "none", plot.title = element_text(hjust = .5),
          panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
          panel.border = element_rect(color = "black", fill = NA, size = 0.8),
          panel.background = element_rect(fill = NA), text = element_text(size=10))
  print(plot)
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is perfect, thank you. How can I plot all six figures in the same window? Adding par(mfrow = c(2,3)) before the for loop and just inside the for loop doesn't work.
@Bex save the plots of the for-loop in a list too. ` plots <- list() for (i in 1:length(gg_pets)) { plots[[i]] <- ggplot(data = gg_pets[[i]], ...` Then use grid.arrange from gridExtra package to put them together as you wish. Here is an example: gridExtra::grid.arrange(plots[[1]], plots[[2]], plots[[1]], plots[[2]], layout_matrix = rbind(c(1,2),c(3,4)))
1

I think you need

ggplot(data = get(i), ...)

but it would probably be more idiomatic/better practice to put your data sets in a named list (my_data_list <- list(cat=cat, dog=dog, ...) or even my_data_list <- mget(gg_pets) ) and use data = my_data_list[[i]] ...

Comments

1

An alternative to the list approach mentioned in the other answers would be to first have everything in the same data.frame, since apparently all the tables have the same variables; and then have one more variable indicating what kind of pet does the observation correspond to. As follows:

pets_df <- bind_rows(cat %>% add_column(pet = 'cat'),
                     dog %>% add_column(pet = 'dog'))

> pets_df
                Breed Longevity pet
1  American Shorthair        17 cat
2             Ragdoll        19 cat
3             Persian        15 cat
4              Sphynx        17 cat
5          Maine Coon        20 cat
6            Havanese        20 dog
7             Bulldog        11 dog
8              Beagle        12 dog
9           Chihuahua        15 dog
10             Poodle        16 dog

Then, in each iteration of the loop you only have to filter the one data.frame. For example:

for (i in 1:length(gg_pets)) {
  plot <- ggplot(data = filter(pets_df, pet == gg_pets[i]), 
                 aes(x = Breed, y = Longevity, fill = Breed)) + 
    geom_bar(stat = "identity", position = position_dodge()) +
    xlab("Breed") +
    ylab("Longevity") +
    ggtitle(gg_pets[i]) +
    geom_text(aes(label = Longevity), vjust = -0.3, color = "black", size = 3.5) +
    theme(axis.line = element_line(color = "black"), axis.text = element_text(color = "black"), 
          legend.position = "none", plot.title = element_text(hjust = .5),
          panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
          panel.border = element_rect(color = "black", fill = NA, size = 0.8),
          panel.background = element_rect(fill = NA), text = element_text(size=10))
  print(plot)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.