Code Club S02E09: Combining Plots - Part 2


Learning objectives

  • Continue to practice creating plots with ggplot
  • Compare the ggplot functions facet_grid() and facet_wrap()
  • Arrange multiple plots of different types on a single figure


1 – Intro

In the previous session we worked with the facet_wrap() function from ggplot, which allowed us to use some variable (column) in the dataset to partition data into multiple panels of a single plot. In this session, we’ll see how the facet_wrap() approach compares to a similar function, facet_grid(), and also explore the patchwork package, which offers more control and flexibility in arranging multiple plots in a single figure.

We’ll continue to use tidyverse functions and data from palmerpenguins, so install those if you need to. If you already have them installed, just load them into your current R session with the library() functions below…

install.packages("tidyverse")
install.packages("palmerpenguins")

And now let’s preview/explore the penguins dataset just to remind ourselves of what’s in there…

head(penguins)

#> # A tibble: 6 x 8
#>   species island bill_length_mm bill_depth_mm flipper_length_… body_mass_g sex  
#>   <fct>   <fct>           <dbl>         <dbl>            <int>       <int> <fct>
#> 1 Adelie  Torge…           39.1          18.7              181        3750 male 
#> 2 Adelie  Torge…           39.5          17.4              186        3800 fema…
#> 3 Adelie  Torge…           40.3          18                195        3250 fema…
#> 4 Adelie  Torge…           NA            NA                 NA          NA NA   
#> 5 Adelie  Torge…           36.7          19.3              193        3450 fema…
#> 6 Adelie  Torge…           39.3          20.6              190        3650 male 
#> # … with 1 more variable: year <int>

summary(penguins)

#>       species          island    bill_length_mm  bill_depth_mm  
#>  Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
#>  Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
#>  Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
#>                                  Mean   :43.92   Mean   :17.15  
#>                                  3rd Qu.:48.50   3rd Qu.:18.70  
#>                                  Max.   :59.60   Max.   :21.50  
#>                                  NA's   :2       NA's   :2      
#>  flipper_length_mm  body_mass_g       sex           year     
#>  Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
#>  1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
#>  Median :197.0     Median :4050   NA's  : 11   Median :2008  
#>  Mean   :200.9     Mean   :4202                Mean   :2008  
#>  3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
#>  Max.   :231.0     Max.   :6300                Max.   :2009  
#>  NA's   :2         NA's   :2

2 – Review Of facet_wrap()

Last week we started with a plot Michael Broe had previously constructed…

penguins %>% 
  drop_na() %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm, color = species)) +
  geom_point() +
  geom_smooth(method = "lm")

#> `geom_smooth()` using formula 'y ~ x'

We then used facet_wrap() to present the data for the three species in separate panels, in place of using color…

penguins %>% 
  drop_na() %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_wrap(vars(species))

#> `geom_smooth()` using formula 'y ~ x'

Then as part of the breakout rooms, we tried faceting on more than one variable - we subsetted the dataset for only Adelie penguins, then plotted the relationship between bill length and bill depth faceted across both island and sex

penguins %>% 
  drop_na() %>%
  filter(species == "Adelie") %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_wrap(vars(island, sex))

#> `geom_smooth()` using formula 'y ~ x'

3 – facet_grid()

While you can use facet_wrap() as above, facet_grid() is often a better option when faceting on two variables. Here’s what the example above looks like with facet_grid()

penguins %>% 
  drop_na() %>%
  filter(species == "Adelie") %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_grid(rows = vars(sex), cols = vars(island))

#> `geom_smooth()` using formula 'y ~ x'

Notice that with facet_grid() we specify which variable defines the rows and which variable defines the columns.


Breakout Rooms I: Facet Grids

Exercise 1

Try analyzing the relationship between Adelie penguin bill length and bill depth separately for each combination of year and sex. Make the columns represent male/female, and the rows represent the different years (in this case, 2007-2009).

Hint (click here)


Use filter() to select out Adelie penguins, then create a scatter plot similar to the one in the facet_grid() example. Assign the rows as year and the columns as sex.

Solution (click here)
penguins %>% 
  drop_na() %>%
  filter(species == "Adelie") %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_grid(rows = vars(year), cols = vars(sex))

#> `geom_smooth()` using formula 'y ~ x'

Exercise 2

Now let’s modify the plot you just created a bit. Add the title “Bill Dimensions Of Adelie Penguins”, and move the year labels from the right side to the left side of the plot.

Hint (click here)


Check out the switch option in the facet_grid() documentation for moving the year labels. For the title, consider labs() or ggtitle().

Solution (click here)
penguins %>% 
  drop_na() %>%
  filter(species == "Adelie") %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_grid(rows = vars(year), cols = vars(sex), switch = "y") +
  ggtitle("Bill Dimensions Of Adelie Penguins")

#> `geom_smooth()` using formula 'y ~ x'


4 – Multi-Panel Plots: Patchwork

Faceting with facet_wrap() or facet_grid() works when you want to partition the plots based on one or more variables in the dataset. But if you want to arrange multiple plots into one figure, possibly even different types of plots, one good option is the patchwork package. Let’s install and load it…

install.packages("patchwork")

With patchwork, you create and save each plot as a separate object. Then, once you’ve made the plots, you just tell patchwork how to arrange them. The syntax to define the layout is based on common mathematical operators.

Some examples:

  • plot1 + plot2 puts two plots side-by-side
  • plot1 / plot2 stacks two plots vertically
  • plot1 / (plot2 + plot3) gives plot1 on a top row, and plots 2 and 3 on a bottom row

In the examples above, plot1, plot2, and plot3 represent plots that have been saved as objects with those names.

Below is an example from palmerpenguins. First we create the plots, saving each as a new object…

avg_island_lgth <- penguins %>%
  drop_na() %>%
  group_by(island) %>%
  summarize("mean_bill_length" = mean(bill_length_mm)) %>%
  ggplot(aes(x = island, y = mean_bill_length)) +
  geom_col() +
  ggtitle("Average Penguin Bill Length")

mass_by_sex <- penguins %>%
  drop_na() %>%
  ggplot(aes(x = sex, y = body_mass_g)) +
  geom_boxplot() +
  ggtitle("Effect of Sex on Penguin Size")

lgth_by_depth <- penguins %>% 
  drop_na() %>%
  ggplot(aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_wrap("species") +
  ggtitle("Relationship Between Bill Length and Bill Depth")

Then we simply use the patchwork syntax to define how these 3 plots will be arranged. In this case, the first (faceted) plot on top, with the other two side-by-side below it…

lgth_by_depth / (avg_island_lgth + mass_by_sex)

#> `geom_smooth()` using formula 'y ~ x'


Breakout Rooms II: Combining Plots

Use the palmerpenguin data to try to create the plot below…

Hint 1 (Boxplot) (click here)


For the boxplot, use geom_boxplot().

Hint 2 (Boxplot) (click here)


Notice that R initially interprets the year variable as a continuous variable, but boxplots need a discrete x axis. Convert that variable to character or factor. You can use mutate along with as.character or as.factor.

Hint 3 (Plot Formatting) (click here)


For the formatting, try theme_classic()

Hint 4 (Labels 1) (click here)


The title and axis labels can be specified with labs(), among other options.

Hint 5 (Labels 2) (click here)


To get the ‘A’ and ‘B’ plot annotations, check out the help page for the plot_annotation() function within patchwork.

Solution (click here)
bill_flipper <- penguins %>%
  drop_na() %>%
  ggplot(aes(x = bill_length_mm, y = flipper_length_mm)) +
  geom_point() +
  facet_wrap("species") +
  geom_smooth(method = "lm") +
  theme_classic() +
  labs(title = "Relationship Between Bill Length and Flipper Length",
       x = "Bill Length (mm)",
       y = "Flipper Length (mm)")
  
mass_yr <- penguins %>%
  drop_na() %>%
  mutate("year" = as.character(year)) %>%
  ggplot(aes(x = year, y = body_mass_g)) +
  geom_boxplot() + 
  theme_classic() +
  labs(title = "Penguin Size Over Time",
       x = "Body Mass (g)",
       y = "Year")

bill_flipper / mass_yr + 
  plot_annotation(tag_levels = 'A')



Mike Sovic
Mike Sovic
Bioinformatician at CAPS