Bex
Bex

Reputation: 201

ggplot inside for loop

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)
}

Upvotes: 2

Views: 3262

Answers (3)

mgiormenti
mgiormenti

Reputation: 833

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)
}

Upvotes: 1

Emer
Emer

Reputation: 3824

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)
}

Upvotes: 3

Ben Bolker
Ben Bolker

Reputation: 226801

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]] ...

Upvotes: 1

Related Questions