Code Club S02E09: Combining Plots - Part 2
Learning objectives
- Continue to practice creating plots with ggplot
- Compare the ggplot functions
facet_grid()
andfacet_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-sideplot1 / plot2
stacks two plots verticallyplot1 / (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')