Exercises for session 5
The codeblocks here are interactive and can be executed in the browser. You can also copy them over and solve the exercises locally. In the existing code ______ denotes areas that need to be substituted with your own code to solve the exercise.
Each exercise has one or more hints, as well as a full solution if you click through all the hints. Do try to solve the exercises on your own first.
5.1 Patchwork Composition
Combine the three plots into a single figure using patchwork. Place two plots side by side in the top row, and the third plot centered below them. Try to solve it both by only using + as well as by using other operators.
Remember that:
/arranges plots vertically (top/bottom)|arranges plots horizontally (left/right)- You can use parentheses to group plots
If you only use + you need to use `plot_layout() to define how they combine
(p1 | p2) / p3
# and
(p1 + p2) + p3 + plot_layout(ncol = 1)Combine the two plots below. Then use the patchwork operator syntax to add a geom to both plots simultaneously.
In patchwork, you can add a geom (or another element) to all plots at once using & or *. Read ?plot_arithmetic to figure out the difference between the two.
For this exercise, try adding a smoothing line with geom_smooth() to both plots.
p1 + p2 & geom_smooth(method = "lm")Create a multi-panel figure with 4 plots using wrap_plots(), and customize the width of the plots so that the first column take up 1/3 of the width and the last column take up 2/3 of the width.
The wrap_plots() function has a widths argument that control the relative or absolute width of panels in each column.
# Create four different plots
p1 <- ggplot(penguins) +
geom_point(aes(x = flipper_len, y = bill_len, color = species))
p2 <- ggplot(penguins) +
geom_histogram(aes(flipper_len, fill = species))
p3 <- ggplot(penguins) +
geom_boxplot(aes(species, bill_len, fill = species))
p4 <- ggplot(penguins) +
geom_bar(aes(species, fill = sex), position = "dodge")
# Combine with custom widths
wrap_plots(p1, p2, p3, p4, ncol = 2, widths = c(1, 2))Use the 4 plots from 5.1.3 and arrange them in a custom layout using the text-based design approach. Make a layout where the first plot spans the entire top row, two plots following plots share the middle row, and the last plot take up the right half side of the last row.
Once you’ve succeeded, recreate the layout using area() specifications
For the text-based design: - Each letter represents a plot - Each character position represents a cell in the grid - The same letter in multiple positions means that plot spans those cells - # represents an empty cell
For a layout with the first plot spanning the top row and the other two sharing the bottom row, your layout might look something like:
AAA
BCC
# Create a text-based layout design
layout <- "
AA
BC
#D
"
# Combine plots with the layout
p1 + p2 + p3 + p4 +
plot_layout(design = layout)
# Replicate with area()
layout <- c(
area(1, 1, 1, 1),
area(1, 2, 1, 2),
area(2, 1, 2, 2),
area(3, 2, 3, 2)
)
# Plotting code is the same as before
p1 + p2 + p3 + p4 +
plot_layout(design = layout)5.2 Layout Modifiers
Use the two plots below and add them together in a way so the histogram is placed on top of the scatterplot in the top-right corner.
Use inset_element() to place p2 as an inset in p1. You’ll need to specify the position with left, bottom, right, and top parameters.
# Add p2 as an inset to p1
p1 + inset_element(
p2,
left = 0.6,
bottom = 0.6,
right = 0.95,
top = 0.95
)Stack the three plots on top of each other. Experiment with free() to minimize the amount of empty space while preserving as much alignment as possible between the panels
The free() function allows a plot to extend beyond its allocated space. You can specify which side of the plot should be freed using the side parameter.
There are many combinations of free() that will eliminate the whitespace but if you want to ensure alignment where possible, free should be applied to the plots and sides that are causing the issues
free(p1, side = "l") /
free(p2, side = "r") /
p3Use free() to allow the long y-axis text to extend into the empty area next to it in the composition below where we reuse the plots from 5.2.2. We have not covered this mode of free() so look at the documentation for the function.
The type argument of the free() function controls the behavior. Read the docs and experiment with the different modes.
p3 + p2 +
plot_spacer() + free(p1, type = "space", side = "l")5.3 Annotations and Tagging
Create a composition of three plots and add a title, subtitle, and caption to the entire composition using plot_annotation(). Use markdown formatting in your text and apply a custom theme to the annotation.
Use plot_annotation() with: - title: The main title with markdown formatting - subtitle: A subtitle with markdown formatting - caption: A caption with markdown formatting - theme: A theme to apply to the annotation - try using marquefy_theme() from the marquee package
:::
## Solution
::: {.solution exercise="ex_5_3_1"}
```r
(p1 | p2 / p3) +
plot_annotation(
title = "**Penguin** _Measurements_ Analysis",
subtitle = "*Exploring* relationships between bill and flipper dimensions",
caption = "Source: The `penguins` dataset in R",
theme = marquee::marquefy_theme(theme_minimal())
)
Create a multi-panel figure with nested plots and add automatic tagging with different levels for the main plots and nested plots.
For the nested layout, use something like:
(p1 | (p2 / p3)) / p4To mark a nested area for different tag levels:
plot_layout(tag_level = "new")For the tagging annotation, use:
plot_annotation( tag_levels = c("1", "a"), tag_suffix = ")" )
# Create a nested layout
p_nested <- ((p1 | (p2 / p3)) + plot_layout(tag_level = "new")) / p4
# Add tagging to the entire composition
p_nested +
plot_annotation(
tag_levels = c("1", "a"),
tag_suffix = ")"
)5.4 Guide Handling
Create two plots that share the same color aesthetic. Combine them and collect their legends into a single legend.
Use the plot_layout(guides = "collect") function to collect the legends from both plots into a single legend.
# Combine plots and collect legends
(p1 / p2) + plot_layout(guides = "collect")Create two plots with shared x-axis categories. Combine them vertically and use plot_layout() to collect the axes so that the x-axis appears only once at the bottom. Also try to make it so that the axis titles are collected at the bottom while the ticks and labels are kept in each plot.
Use the axes argument in plot_layout() to collect shared axes. The axis_titles argument works the same way but only for the title
# Combine plots vertically and collect x-axis
(p1 / p2) + plot_layout(axes = "collect")
# To only collect the titles, use the `axis_titles` argument instead
(p1 / p2) + plot_layout(axis_titles = "collect")5.5 Other Objects
Combine the plot and the table in a way where the table ends up making up for the x-axis of the plot
If the table should make it out for the axis, then it needs to be placed below and the plot needs to have its x-axis removed.
To align the table and the plot the species column needs to be moved out of the panel area. By default, row and column names are placed outside the panel region.
# First we create the gt table with the rownames defined by the attribute
# column
summary_table <- gt::gt(summary, rowname_col = "attribute")
# Then we modify p1 so it does not have an x axis and remove expansion
# of the x scale to ensure proper alignment
p1 <- p1 +
theme(axis.title.x = element_blank(), axis.text.x = element_blank()) +
coord_cartesian(expand = FALSE)
# Then we combine it all. We free the left label so it is kept together
# with the y axis
free(p1, "label", "l") /
wrap_table(summary_table, space = "fixed")It’s possible to add much more styling to the table so it feels more like a part of the plot but that is more about gt than patchwork so we’ll leave it at this
Create a scatter plot and add an image file in the lower right corner. For this exercise, use the patchwork logo image.
Use the png::readPNG() function to read the image file so that can be used in patchwork. Remember to set raster = TRUE.
Use inset() to place it on top of the plot
p1 +
inset_element(logo, 0.65, 0.05, 0.95, 0.2)
# Consider setting a transparent background on the inset
p1 +
inset_element(logo, 0.65, 0.05, 0.95, 0.2) +
theme_void()