Doug Fir
Doug Fir

Reputation: 21212

Display a list of plots in a grid with specified columns and rows based on grouping column values

I have read this post which seems to be the 'main' one for my question. However, I don't quite have what I need and wanted to see if there's any other solutions out there...

I have a list column data frame with some plots, similar to this:

exdata <- diamonds %>%
  group_by(cut) %>% 
  nest %>% 
  crossing(dummy = 1:3) %>% 
  mutate(plots = map(.x = data, ~ ggplot(.x, aes(x = x, y = y)) + geom_point()))

Looks like this:

exdata
# A tibble: 15 x 4
   cut       data                  dummy plots 
   <ord>     <list>                <int> <list>
 1 Fair      <tibble [1,610 × 9]>      1 <gg>  
 2 Fair      <tibble [1,610 × 9]>      2 <gg>  
 3 Fair      <tibble [1,610 × 9]>      3 <gg>  
 4 Good      <tibble [4,906 × 9]>      1 <gg>  
 5 Good      <tibble [4,906 × 9]>      2 <gg>  
 6 Good      <tibble [4,906 × 9]>      3 <gg>  
 7 Very Good <tibble [12,082 × 9]>     1 <gg>  
 8 Very Good <tibble [12,082 × 9]>     2 <gg>  
 9 Very Good <tibble [12,082 × 9]>     3 <gg>  
10 Premium   <tibble [13,791 × 9]>     1 <gg>  
11 Premium   <tibble [13,791 × 9]>     2 <gg>  
12 Premium   <tibble [13,791 × 9]>     3 <gg>  
13 Ideal     <tibble [21,551 × 9]>     1 <gg>  
14 Ideal     <tibble [21,551 × 9]>     2 <gg>  
15 Ideal     <tibble [21,551 × 9]>     3 <gg>  

Column exdata$plots is a list of ggplots.

I would like to plot these in a similar outcome to using facet_grid based on columns of cut and dummy of dummys. The first column would be all the plots for Fair, the second for Good, the third for Very good etc. The rows would be titled '1', '2' and '3' for each value in dummy. A 3 * 5 grid.

I tried the Patchwork package but this does not have a 'direct' way of doing this. Ideally I'd have the column titles clearly labelled with the corresponding cut and then the rows with the corresponding rows.

Note my particular use case prevents me from building a master data frame and wrangling it to use facet grid in the desired manner, I'm really stuck with a list column in a data frame like above.

[Edit based on comments]. Adding more detail to the above paragraph, I'm using a package to generate a model and then plot the model. CLVTools::plot(model) on each row in my df. So the plots are already generated by an existing model within a dplyr::mutate chunk. I don't create the plots myself, they are done by the package with some customizations that I'd rather not go into battle with R to replicate manually.

How can I assemble my list column of plots into a 3*5 grid with clear column and row titles, like with facet_grid?

Upvotes: 1

Views: 357

Answers (2)

Ian Campbell
Ian Campbell

Reputation: 24790

It's not very programmatic in nature, but at least it works. I was inspired by Allan Camerons's answer here.

We can use patchwork::wrap_plots to get the ggplot graphs into a grid.

Then we can use grid::grid.draw to draw some textGrobs manually. You can define the position on the final graph with the x= and y= arguments to textGrob. Since the position is different for each label, we can use purrr:walk2 to combine sets of parameters. (walk2 is like map2, but doen't return anything.) The rot= argument can turn the text depending on the axis.

library(patchwork); library(purrr); library(grid)
wrap_plots(plotlist = exdata$plots, ncol = 3, nrow = 5) +
  plot_annotation(title = " ")
walk2(seq(0.125,0.875,length.out = 5),unique(exdata$cut),
      ~grid.draw(textGrob(.y, x = 0.01, y = .x, rot = 90)))
walk2(seq(0.165,0.835,length.out = 3),unique(exdata$dummy),
      ~grid.draw(textGrob(.y, x = .x, y = 0.98, rot = 0)))

enter image description here

Upvotes: 2

B Williams
B Williams

Reputation: 2050

Since you have the data why not directly generate the figure (or do you just have a list of plots), instead of nesting them? Something like:

diamonds %>%
   group_by(cut) %>% 
   nest %>% 
   crossing(dummy = 1:3) %>% 
   ggplot(aes(x, y)) + 
   geom_point(data = . %>% unnest(data)) +
   facet_grid(dummy ~ cut)

Then you can adjust labels in the standard fashion.

Upvotes: 1

Related Questions