ggplot внутри для цикла

#r #for-loop #ggplot2

#r #для цикла #ggplot2

Вопрос:

Я хочу просмотреть шесть похожих фреймов данных и распечатать шесть графиков, используя ggplot.

Мой код работает, когда я запускаю графики отдельно, но я не могу заставить ggplot запускаться шесть раз, используя цикл for. Мои шесть фреймов данных — это шесть животных, перечисленных в 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)
}
  

Ответ №1:

В вашем примере gg_pets — это просто вектор строк. Вам необходимо объединить фреймы данных, чтобы выполнить итерацию по ним в цикле for. Вы можете сделать это с помощью списка. Следующим образом. Вы можете использовать имена элементов в качестве заголовка.

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

Комментарии:

1. Это идеально, спасибо. Как я могу отобразить все шесть фигур в одном окне? Добавление par(mfrow = c(2,3)) перед циклом for и только внутри цикла for не работает.

2. @Bex также сохраняет графики цикла for в списке. ` графики <- list() для (i в 1: длина (gg_pets)) { графики[[i]] <- ggplot(данные = gg_pets[[i]], … ` Затем используйте grid.arrange из пакета gridExtra, чтобы соединить их по своему усмотрению. Вот пример: gridExtra::grid.arrange(plots[[1]], plots[[2]], plots[[1]], plots[[2]], layout_matrix = rbind(c(1,2),c(3,4)))

Ответ №2:

Я думаю, вам нужно

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

но, вероятно, было бы более идиоматичным / лучшей практикой поместить ваши наборы данных в именованный список ( my_data_list <- list(cat=cat, dog=dog, ...) или даже my_data_list <- mget(gg_pets) ) и использовать data = my_data_list[[i]]

Ответ №3:

Альтернативой list подходу, упомянутому в других ответах, было бы сначала иметь все в одном и том же data.frame , поскольку, по-видимому, все таблицы имеют одинаковые переменные; а затем иметь еще одну переменную, указывающую, какому типу домашних животных соответствует наблюдение. Следующим образом:

 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
  

Затем на каждой итерации цикла вам нужно фильтровать только один data.frame . Например:

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