## packages
library(tidyverse) ## data science package collection (incl. the ggplot2 package)
library(systemfonts) ## use custom fonts (need to be installed on your OS)
library(paletteer) ## scico and many other colour palettes palettes(http://www.fabiocrameri.ch/colourmaps.php) in R
library(ggtext) ## add improved text rendering to ggplot2
library(ggforce) ## add missing functionality to ggplot2
library(concaveman) ## Needed by ggforce for plot annotation hulls
library(ggdist) ## add uncertainty visualizations to ggplot2
library(ggformula) ## Formula interface to ggplot
library(magick) ## load images into R
library(patchwork) ## combine outputs from ggplot2
library(palmerpenguins)
library(showtext) ## add google fonts to plots
knitr::opts_chunk$set(
error = TRUE,
comment = NA,
warning = FALSE,
errors = FALSE,
message = FALSE,
tidy = FALSE,
cache = FALSE,
echo = TRUE,
warning = FALSE,
# from the vignette for the showtext package
fig.showtext = TRUE,
fig.retina = 1,
fig.path = "figs/"
# fig.height = 3.09,
# fig.width = 5
)
Lab-7: The Lobster Quadrille
Fonts and other Wizardy in ggplot
Introduction
We will add icing and froth to our vanilla ggplots: fonts, annotations, highlights and even pictures!!
Goals
- Appreciate that a publication-worth graphic takes a lot of work!!
- Adding annotations, pictures and references to graphs is necessary for good understanding
- Judicious use of colour and scales can enhance comprehension.
Pedagogical Note
The method followed will be based on PRIMM:
- PREDICT Inspect the code and guess at what the code might do, write predictions
- RUN the code provided and check what happens
-
INFER what the
parameters
of the code do and write comments to explain. What bells and whistles can you see? -
MODIFY the
parameters
code provided to understand theoptions
available. Write comments to show what you have aimed for and achieved. - MAKE : take an idea/concept of your own, and graph it.
Let’s load up a few packages that we need to start:
Using Google Fonts
We will want to add a few new fonts to our graphs. The best way (currently) is to use the showtext
package (which we loaded above) to bring into our work fonts from Google. To view and select the fonts you might want to work with, spend some time looking over:
library(sysfonts)
library(showtext)
sysfonts::font_add_google("Roboto", "roboto")
font_add_google("Noto Sans", "noto")
font_add_google("Open Sans", "open")
font_add_google("Anton", "anton")
font_add_google("Tangerine", "tangerine")
# set the google fonts as default
showtext::showtext_auto(enable = TRUE)
We will work with a familiar dataset, so that we can concentrate on the chart aesthetics, without having to spend time getting used to the data: the penguins
dataset again, from the palmerpenguins
package.
ggformula
and ggplot
worlds do intersect!
It seems we can mix `ggformula` code with `ggtext` code, using the `+` sign!! What joy !!! Need to find out if this works for other `ggplot` extensions as well !!!
Data
Always start your work with a table of the data:
Basic Plot
A basic scatter plot, which we will progressively dress up.
## simple plot: data + mappings + geometry
## no colour or fill yet
gf <- gf_point(bill_depth_mm ~ bill_length_mm,
data = penguins,
alpha = 0.6, size = 3.5)
gf
## simple plot: data + mappings + geometry
## no colour or fill yet
gg <- ggplot(penguins, aes(x = bill_length_mm,
y = bill_depth_mm)) +
geom_point(alpha = .6, size = 3.5)
gg
Customized Plot
Let us set some ggplot theme aspects now!! Here is a handy picture showing (most of) the theme-able aspects of a ggplot plot.
For more info, type ?theme
in your console.
## change global theme settings (for all following plots)
my_theme <- theme_set(theme_classic(base_size = 12,
base_family = "roboto"
)) +
## modify plot elements globally (for all following plots)
theme_update(
axis.ticks = element_line(color = "grey92"),
axis.ticks.length = unit(.5, "lines"),
panel.grid.minor = element_blank(),
legend.title = element_text(size = 12),
legend.text = element_text(color = "grey30"),
plot.title = element_text(size = 18, face = "bold"),
plot.subtitle = element_text(size = 12, color = "grey30"),
plot.caption = element_text(size = 9, margin = margin(t = 15))
)
Since we know what the basic plot looks like, let’s add titles, labels and colours. We will also set limits and scales.
theme_set(my_theme)
gf1 <- penguins %>%
gf_point(bill_depth_mm ~ bill_length_mm,
# colour by continuous variable
color = ~ body_mass_g,
alpha = .6, size = 3.5) %>%
## custom axes scaling
gf_refine(
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)),
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)),
## custom colors from the scico package
## using the paletteer super package
paletteer:: scale_color_paletteer_c(`"scico::bamako"`,
direction = -1),
## custom labels
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) PLoS ONE',
x = 'Bill Length (mm)',
y = 'Bill Depth (mm)',
## See this!
color = 'Body mass (g)'
))
gf1
Note this neat way of naming a scale and the legend in the labs
command above!
theme_set(my_theme)
gg1 <- penguins %>%
ggplot(aes(y = bill_depth_mm, x = bill_length_mm),
alpha = .6) +
geom_point(aes(colour = body_mass_g), size = 3.5) +
## custom axes scaling
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
## custom colors from the scico package
paletteer:: scale_color_paletteer_c(`"scico::bamako"`,
direction = -1) +
## custom labels
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (Pygoscelis)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) PLoS ONE',
x = 'Bill Length (mm)',
y = 'Bill Depth (mm)',
color = 'Body mass (g)'
)
gg1
Using {ggtext}
From Claus Wilke’s website → www.wilkelab.org/ggtext
The
ggtext
package provides simple Markdown and HTML rendering for ggplot2. Under the hood, the package uses thegridtext
package for the actual rendering, and consequently it is limited to the feature set provided bygridtext
.
Support is provided for Markdown both in theme elements (plot titles, subtitles, captions, axis labels, legends, etc.) and in geoms (similar togeom_text()
). In both cases, there are two alternatives, one for creating simple text labels and one for creating text boxes with word wrapping.
NOTE: on some machines, the ggtext
package may not work as expected. In this case, please do as follows, using your Console:
- remove gridtext:
remove.packages(gridtext)
. - Install development version of
gridtext
:install.packages(remotes)
remotes::install_github("wilkelab/gridtext")
Using element_markdown()
We can use our familiar markdown syntax right inside the titles and captions of the plot. element_markdown()
is a theme-ing command made available by the ggtext
package.
element_markdown()
→ formatted text elements, e.g. titles, caption, axis text, striptext.
theme_set(my_theme)
gf2 <- penguins %>% gf_point(bill_depth_mm ~ bill_length_mm,
color = ~ body_mass_g,
alpha = 0.6, size = 3.5) %>%
gf_refine(
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)),
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)),
## custom colors from the scico package
paletteer:: scale_color_paletteer_c("scico::bamako",
direction = -1),
## custom labels using element_markdown()
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)')
) %>%
# New code from here
# Enables markdown titles, captions and labels
gf_theme(theme(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
))
gf2
theme_set(my_theme)
gg2 <- ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
paletteer:: scale_color_paletteer_c(`"scico::bamako"`,
direction = -1) +
## New code starts here: Two Step Procedure with ggtext
## 1. Markdown formatting of labels and title, using asterisks
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)'
) +
## 2. Add theme related commands from ggtext
## render respective text elements
theme(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
gg2
element_markdown()
in combination with HTML
This allows us to change fonts in titles, labels, and captions.
theme_set(my_theme)
## use HTML syntax to change text color
gf2 %>%
# html in labels
gf_labs(title = 'Bill Dimensions of Brush-Tailed Penguins
<i style = "color:#28A87D;">Pygoscelis </i>'
)
## use HTML syntax to change font and text size
gf2 %>%
gf_labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:tangerine;">Pygoscelis</b>')
theme_set(my_theme)
## use HTML syntax to change text color
gg2 +
labs(title = 'Bill Dimensions of Brush-Tailed Penguins <i style="color:#28A87D;">Pygoscelis</i>') +
theme(plot.margin = margin(t = 15))
## use HTML syntax to change font and text size
gg2 +
labs(title = 'Bill Dimensions of Brush-Tailed Penguins <b style="font-size:32pt;font-family:tangerine;">Pygoscelis</b>')
Annotations with geom_richtext()
and geom_textbox()
Further ggplot annotations can be achieved using geom_richtext()
and geom_textbox()
. geom_richtext()
also allows formatted text labels with 360° rotation. One needs to pass a tibble to geom_richtext()
giving the location, colour, rotation etc of the label annotation.
# Create a label tibble
# Three rich text labels,
# so three sets of locations x and y, and angle of rotation
labels <- tibble(
x = c(34, 56, 54),
y = c(20, 18.5, 14.5),
angle = c(12, 20, 335),
species = c("Adelie", "Chinstrap", "Gentoo"),
lab = c("<b style='font-family:anton;font-size:24pt;'>Adélie</b><br><i style='color:darkgrey;'>P. adéliae</i>",
"<b style='font-family:anton;font-size:24pt;'>Chinstrap</b><br><i style='color:darkgrey;'>P. antarctica</i>",
"<b style='font-family:anton;font-size:24pt;'>Gentoo</b><br><i style='color:darkgrey;'>P. papua</i>"))
labels
theme_set(my_theme)
gf_rich <- penguins %>%
gf_point(bill_depth_mm ~ bill_length_mm,
color = ~ species,
alpha = 0.6, size = 3.5, data = penguins) +
## add text annotations for each species
ggtext::geom_richtext(
data = labels,
# Now pass the data variables as aesthetics
aes(x, y, label = lab, color = species, angle = angle),
size = 4, fill = NA, label.color = NA,
lineheight = .3) +
# show.legend = FALSE else we get some unusual legends!
# fill = NA makes the labels' fill transparent
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
scale_colour_paletteer_d(palette = `"rcartocolor::Bold"`,
guide = "none") +
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)'
) +
# Use theme and element_markdown() to format axes and titles as usual
theme(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
plot.margin = margin(25, 6, 15, 6)
)
gf_rich
Note the plus sign usage here!!We are combining the ggformula and ggplot syntax, and it works!
theme_set(my_theme)
gg_rich <- ggplot(penguins, aes(x = bill_length_mm,
y = bill_depth_mm)) +
geom_point(aes(color = species), alpha = .6, size = 3.5) +
## add text annotations for each species
ggtext::geom_richtext(
data = labels,
# Now pass the data variables as aesthetics
aes(x, y, label = lab, color = species, angle = angle),
size = 4, fill = NA, label.color = NA,
lineheight = .3) +
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
scale_colour_paletteer_d(`"rcartocolor::Bold"`, guide = "none")+
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)'
) +
# Use theme and element_markdown() to format axes and titles as usual
theme(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
plot.margin = margin(25, 6, 15, 6)
)
gg_rich
Formatted Text boxes on plots
element_textbox()
and element_textbox_simple()
→ formatted text boxes with word wrapping.
theme_set(my_theme)
gf_box <- penguins %>%
gf_point(bill_depth_mm ~ bill_length_mm,
color = ~ species,
alpha = 0.6, size = 3.5, data = penguins) +
## add text annotations for each species
ggtext::geom_richtext(
data = labels,
# Now pass the data variables as aesthetics
aes(x, y, label = lab, color = species, angle = angle),
size = 4, fill = NA, label.color = NA,
lineheight = .3) +
# show.legend = FALSE else we get some unusual legends!
# fill = NA makes the labels' fill transparent
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
scale_colour_paletteer_d(palette = `"rcartocolor::Bold"`,
guide = "none") +
# Now for the Plot Titles and Labels, as before
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)'
) +
# Add the ggtext theme related commands
theme(
## turn title into filled textbox
plot.title = ggtext::element_textbox_simple(
color = "white",
fill = "#28A78D",
size = 28,
padding = margin(8, 4, 8, 4),
margin = margin(b = 5),
lineheight = .9
),
plot.subtitle = ggtext::element_textbox_simple(
size = 10,
padding = margin(5.5, 5.5, 5.5, 5.5),
margin = margin(0, 0, 5.5, 0),
fill = "orange1"
),
## add round outline to caption
plot.caption = ggtext::element_textbox_simple(
width = NULL,
linetype = 1,
fill = "grey",
padding = margin(4, 8, 4, 8),
margin = margin(t = 15),
r = grid::unit(8, "pt")
),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
plot.margin = margin(25, 6, 15, 6)
)
gf_box
theme_set(my_theme)
gg_box <- ggplot(penguins,
aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species),
alpha = .6, size = 3.5) +
## add text annotations for each species
ggtext::geom_richtext(data = labels,
# Now pass the data variables as aesthetics
aes(x, y, label = lab, color = species, angle = angle),
size = 4, fill = NA, label.color = NA,
lineheight = .3) +
# show.legend = FALSE else we get some unusual legends!
# fill = NA makes the labels' fill transparent
scale_x_continuous(breaks = 3:6 * 10, limits = c(30, 60)) +
scale_y_continuous(breaks = seq(12.5, 22.5, by = 2.5),
limits = c(12.5, 22.5)) +
scale_colour_paletteer_d(palette = `"rcartocolor::Bold"`,
guide = "none") +
# Now for the Plot Titles and Labels, as before
labs(
title = 'Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)',
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = 'Data: Gorman, Williams & Fraser (2014) *PLoS ONE*',
x = '**Bill Length** (mm)',
y = '**Bill Depth** (mm)',
color = 'Body mass (g)'
) +
# Add the ggtext theme related commands
theme(
## turn title into filled textbox
plot.title = ggtext::element_textbox_simple(
color = "white",
fill = "#28A78D",
size = 28,
padding = margin(8, 4, 8, 4),
margin = margin(b = 5),
lineheight = .9
),
plot.subtitle = ggtext::element_textbox_simple(
size = 10,
padding = margin(5.5, 5.5, 5.5, 5.5),
margin = margin(0, 0, 5.5, 0),
fill = "orange1"
),
## add round outline to caption
plot.caption = ggtext::element_textbox_simple(
width = NULL,
linetype = 1,
fill = "grey",
padding = margin(4, 8, 4, 8),
margin = margin(t = 15),
r = grid::unit(8, "pt")
),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
plot.margin = margin(25, 6, 15, 6)
)
gg_box
Using geom_texbox()
for formatted text boxes with word wrapping
theme_set(my_theme)
text_box <- tibble(x = 34, y = 13.7, label = "<span style='font-size:12pt;font-family:anton;'>Lorem Ipsum Dolor Sit Amet</span><br><br>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
gf_box +
## add textbox with long paragraphs
ggtext::geom_textbox(
data = text_box,
aes(x, y,
label = label),
size = 2.2, family = "sans",
fill = "cornsilk",
colour = "black",
# This is ESSENTIAL !!!
# It appears that the original colour aesthetic mapping in `gf_box` and a possible colour aesthetic with `geom_textbox` have a clash, *only* with ggformula. No such issues below with the ggplot.
# So declaring a colour here is essential
box.color = "cornsilk3",
#box.padding = c(2,2,2,2),
width = unit(11, "lines")
) +
coord_cartesian(clip = "off") # ensure no clipping of labels near the edge
theme_set(my_theme)
gg_box +
## add textbox with long paragraphs
ggtext::geom_textbox(
data = text_box,
aes(x, y, label = label),
size = 2.2, family = "sans",
fill = "cornsilk", box.color = "cornsilk3",
width = unit(11, "lines")
) +
coord_cartesian(clip = "off") # ensure no clipping of labels near the edge
Using {ggforce}
From Thomas Lin Pedersen’s website → www.ggforce.data-imaginist.com
ggforce
is a package aimed at providing missing functionality toggplot2
through the extension system introduced withggplot2
v2.0.0. Broadly speakingggplot2
has been aimed primarily at explorative data visualization in order to investigate the data at hand, and less at providing utilities for composing custom plots a laD3.js
.ggforce
is mainly an attempt to address these “shortcomings” (design choices might be a better description). The goal is to provide a repository of geoms, stats, etc. that are as well documented and implemented as the official ones found inggplot2
.
We will start with the basic plot, with the ggtext
related work done up to now:
## use ggtext rendering for the following plots
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## plot that we will annotate with ggforce afterwards
gf3 <- penguins %>%
gf_point(bill_depth_mm ~ bill_length_mm,
color = ~ body_mass_g,
alpha = .6,
size = 3.5) +
coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +
# Add Colour scales
scale_color_paletteer_c(`"grDevices::Lajolla"`,
direction = -1) +
# Add labels
labs(
title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
x = "**Bill Length** (mm)",
y = "**Bill Depth** (mm)",
color = "Body mass (g)",
fill = "Species"
)
## ellipsoids for all groups
gf3 +
ggforce::geom_mark_ellipse(
aes(fill = species,
label = species),
color = "black",
# This is good to include
# Else ellipses get coloured too
alpha = .15,
show.legend = FALSE
)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## plot that we will annotate with ggforce afterwards
gg3 <- ggplot(penguins,
aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = body_mass_g),
alpha = .6,
size = 3.5) +
coord_cartesian(xlim = c(25, 65), ylim = c(10, 25)) +
# Add Colour scales
scale_color_paletteer_c(`"grDevices::Lajolla"`,
direction = -1) +
# Add labels
labs(
title = "Bill Dimensions of Brush-Tailed Penguins (*Pygoscelis*)",
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
x = "**Bill Length** (mm)",
y = "**Bill Depth** (mm)",
color = "Body mass (g)",
fill = "Species"
)
## ellipsoids for all groups
gg3 +
ggforce::geom_mark_ellipse(
aes(fill = species,
label = species),
alpha = .15,
show.legend = FALSE
)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## ellipsoids for specific subset
gg3 +
ggforce::geom_mark_ellipse(
aes(fill = species, label = species,
filter = species == 'Gentoo'),
alpha = 0, show.legend = FALSE
) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## circles
gg3 +
ggforce::geom_mark_circle(
aes(fill = species, label = species,
filter = species == 'Gentoo'),
alpha = 0, show.legend = FALSE
) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## rectangles
gg3 +
ggforce::geom_mark_rect(
aes(fill = species, label = species,
filter = species == 'Gentoo'),
alpha = 0, show.legend = FALSE
) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown()
)
## hull
gg3 +
ggforce::geom_mark_hull(
aes(fill = species, label = species,
filter = species == 'Gentoo'),
alpha = 0, show.legend = FALSE
) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5)
ggplot tricks
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
gg0 <-
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
ggforce::geom_mark_ellipse(aes(fill = species,
label = species),
alpha = .15,
show.legend = FALSE) +
geom_point(aes(color = body_mass_g), alpha = .6, size = 3.5) +
scale_x_continuous(breaks = seq(25, 65, by = 5),
limits = c(25, 65)) +
scale_y_continuous(breaks = seq(12, 24, by = 2),
limits = c(12, 24)) +
scico::scale_color_scico(palette = "bamako", direction = -1) +
labs(
title = "**Bill Dimensions of Brush-Tailed Penguins** (*Pygoscelis*)",
subtitle = 'A scatter plot of bill depth versus bill length.',
caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE*",
x = "**Bill Length** (mm)",
y = "**Bill Depth** (mm)",
color = "**Body mass** (g)"
)
gg0
Left-Aligned Title
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
(gg1 <- gg0 + theme(plot.title.position = "plot"))
Legend Design
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
gg1b + theme(legend.position = "top")
#ggsave("06a_legend_position.pdf", width = 9, height = 8, device = cairo_pdf)
gg1b +
theme(legend.position = "top") +
guides(color = guide_colorbar(title.position = "top",
title.hjust = .5,
barwidth = unit(20, "lines"),
barheight = unit(.5, "lines")))
Add Images
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
## read PNG file from web
png <- magick::image_read("images/culmen_depth.png")
## turn image into `rasterGrob`
img <- grid::rasterGrob(png, interpolate = TRUE)
gg5 <-
gg1 +
annotation_custom(img, ymin = 18, ymax = 28,
xmin = 58, xmax = 65) +
labs(caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* • Illustration: Allison Horst") +
coord_cartesian(clip = "off") # ensure no clipping of labels near the edge
gg5
Using {patchwork}
The goal of
patchwork
is to make it ridiculously simple to combine separate ggplots into the same graphic. As such it tries to solve the same problem asgridExtra::grid.arrange()
andcowplot::plot_grid
but using an API that incites exploration and iteration, and scales to arbitrarily complex layouts.
→ https://patchwork.data-imaginist.com/
Let us make two plots and combine them into a single patchwork plot.
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
## calculate bill ratio
penguins_stats <- penguins %>%
mutate(bill_ratio = bill_length_mm / bill_depth_mm) %>%
filter(!is.na(bill_ratio))
## create a second chart
gg6 <-
ggplot(penguins_stats,
aes(
y = bill_ratio,
x = species,
fill = species,
color = species
)) + geom_violin() +
labs(
y = "Bill ratio",
x = "Species",
subtitle = "",
caption = "Data: Gorman, Williams & Fraser (2014) *PLoS ONE* • Illustration: Allison Horst"
) +
theme(
panel.grid.major.x = element_line(linewidth = .35),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 13),
axis.ticks.length = unit(0, "lines"),
plot.title.position = 'plot',
plot.subtitle = element_text(margin = margin(t = 5, b = 10)),
plot.margin = margin(10, 25, 10, 25)
)
Now to combine both plots into one using simple operators:
For the special case of putting plots besides each other or on top of each other patchwork provides 2 shortcut operators.
|
will place plots next to each other while/
will place them on top of each other.
First we stack up the graphs side by side:
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
## combine both plots
gg5 | (gg6 + labs(title = "Bill Ratios of Brush-Tailed Penguins",
subtitle = "Violin Plots of Bill Ration versus species"))
We can place them in one column:
theme_set(my_theme)
theme_update(
plot.title = ggtext::element_markdown(),
plot.caption = ggtext::element_markdown(),
axis.title.x = ggtext::element_markdown(),
axis.title.y = ggtext::element_markdown(),
legend.title = ggtext::element_markdown()
)
gg5 / (gg6 + labs(title = "Bill Ratios of Brush-Tailed Penguins",
subtitle = "Violin Plots of Bill Ration versus species")) +
plot_layout(heights = c(0.4, 0.4))
References
1. Thomas Lin Pedersen, https://www.data-imaginist.com/. The creator of ggforce
, and patchwork
packages.
2. Claus Wilke, cowplot – Streamlined plot theme and plot annotations for ggplot2, https://wilkelab.org/cowplot/index.html
3. Claus Wilke, Spruce up your ggplot2 visualizations with formatted text, https://clauswilke.com/talk/rstudio_conf_2020/. Slides, Code, and Video !
4. Robert Kabacoff, ggplot theme cheatsheet, https://rkabacoff.github.io/datavis/modifyingthemes.pdf
5. Zuguang Gu, Circular Visualization in R, https://jokergoo.github.io/circlize_book/book/
R Package Citations
Package | Version | Citation |
---|---|---|
ggdist | 3.3.2 | @ggdist2024a; @ggdist2024b |
ggforce | 0.4.2 | @ggforce |
ggtext | 0.1.2 | @ggtext |
grid | 4.4.0 | @grid |
magick | 2.8.3 | @magick |
paletteer | 1.6.0 | @paletteer |
patchwork | 1.2.0 | @patchwork |
scico | 1.5.0 | @scico |
showtext | 0.9.7 | @showtext |
sysfonts | 0.8.9 | @sysfonts |
systemfonts | 1.1.0 | @systemfonts |