将purrr和ggplot与group_by和nest()结合使用时,获取图的标题

时间:2019-02-22 14:57:57

标签: r ggplot2 dplyr purrr

我有以下示例:

df <- mtcars


plot <- df %>% 
  mutate(carb=as.character(carb)) %>% 
  group_by(carb) %>% 
    nest() %>% 
  mutate(plot=map(data, function(.x){ .x  %>%
      ggplot() +
      geom_bar(aes(mpg))
  }))

print(plot)

# A tibble: 6 x 3
  carb  data               plot    
  <chr> <list>             <list>  
1 4     <tibble [10 x 10]> <S3: gg>
2 1     <tibble [7 x 10]>  <S3: gg>
3 2     <tibble [10 x 10]> <S3: gg>
4 3     <tibble [3 x 10]>  <S3: gg>
5 6     <tibble [1 x 10]>  <S3: gg>
6 8     <tibble [1 x 10]>  <S3: gg>

for (i in 1:4){
  print(plots$plot[[i]])
}

问题: 1)如何避免for循环并使用map函数打印图? 2)如何为地块添加标题。

2 个答案:

答案 0 :(得分:3)

使ggplot对象的数据框列有点不寻常且麻烦,但是如果适合这种情况,它就可以工作。 (看来geom_bar对于这些数据实际上没有任何意义,所以我切换到了经过过滤的碳水化合物子集上的直方图)。

使用您的方法,创建图列,将数据框保存到变量中,然后在图的列表列和map2的向量上carb,在每个情节。然后,您可以从结果列表中打印任何项目,或使用mapwalk打印所有项目。

library(tidyverse)

df <- mtcars %>%
  filter(carb %in% c(1, 2, 4)) %>%
  mutate(carb = as.character(carb))

df_with_plots <- df %>% 
  group_by(carb) %>% 
  nest() %>% 
  mutate(plot = map(data, function(.x) { 
    .x  %>%
      ggplot() +
      geom_histogram(aes(mpg))
  }))

plots1 <- map2(df_with_plots$plot, df_with_plots$carb, ~(.x + labs(title = .y)))

# plots1[[1]] # would print out first plot in the list

walk(plots1, print)

为简洁起见,删除了其他地块

似乎更直接的另一种选择是将数据框分成数据框列表,然后创建图,但是您需要每个图。

一些优点:调用split会将carb的每个值作为相应列表项的名称,您可以使用imap轻松访问该列表项,并将其延续到{ {1}}列表(请参阅下文如何按名称打印图)。您也可以一步完成。我也很难处理嵌套数据,因为我希望能够看到数据框,您可以通过打印出数据框的拆分列表来做到这一点。

plots2

与第一种方法一样,您可以使用plots2 <- df %>% split(.$carb) %>% imap(function(carb_df, carb) { ggplot(carb_df) + geom_histogram(aes(mpg)) + labs(title = carb) }) plots2[["4"]] 打印所有图。

答案 1 :(得分:3)

您创建情节的代码没有多大意义,但是不管这是如何在不使用for循环的情况下给出标题并绘制图形的方式:

library(tidyverse)

mtcars %>% 
  group_split(carb) %>% 
  imap(~ ggplot(data = .x) + 
        geom_bar(aes(mpg)) +
        labs(title = paste("Plot:", .y, "Carb:", unique(.x$carb))))

reprex package(v0.2.1)于2019-02-22创建

编辑:我删除了图只是为了不使页面拥挤。在这种情况下,imap()允许我们在迭代时访问索引以及值。如果您不想在标题中包含地块编号,那么map()会很好。注意,我还使用了group_split()的最新版本中的library(dplyr)。同样,在您的示例中,如果要进行更复杂的编码,则将创建一小段ggplots,这既好又花哨,但是在仅创建绘图的情况下,上述方法就可以正常工作并且更易于理解。如果要开发更复杂的图,可以从ggplot函数外推map()并将其放在自己的函数中,如下所示:

plot_carb <- function(df){
  ggplot(data = df) + 
  geom_bar(aes(mpg)) + 
  labs(title = paste(Carb: unique(.x$carb))) + 
  theme_bw()
}

mtcars %>%
group_split(carb) %>%
map(plot_carb)