R Ladies Rome | Code-along Workshop | 30th November 2023
đź‘© Cara Thompson
👩‍💻 Love for patterns in music & language, and a fascination with the human brain %>%
Psychology PhD %>%
Analysis of postgraduate medical examinations %>%
Data Visualisation Consultant
đź’™ Helping others maximise the impact of their expertise
Find out more: cararthompson.com/about
{bakeoff}
by Alison Presmanes Hill
package::function("blah")
hello@cararthompson.com
Some data…
library(tidyverse)
all_the_bakes <- bakeoff::challenges %>%
select(-technical) %>%
pivot_longer(c(signature, showstopper)) %>%
pull(value) %>%
tolower()
key_components <- tibble(
component = c("Chocolate",
"Raspberry",
"GĂ©noise or Sponge",
"Rhubarb"),
count = c(sum(grepl("chocolat", all_the_bakes)),
sum(grepl("raspberr", all_the_bakes)),
sum(grepl("sponge|genoise|génoise", all_the_bakes)),
sum(grepl("rhubarb", all_the_bakes)))
)
key_components
# A tibble: 4 x 2
component count
<chr> <int>
1 Chocolate 206
2 Raspberry 76
3 GĂ©noise or Sponge 12
4 Rhubarb 30
A plot!
Mini tip - theme_minimal()
!
Let’s add a bit of text…
key_components %>%
ggplot(aes(x = component,
y = count,
fill = component)) +
geom_bar(stat = "identity") +
labs(title = "Everybody loves chocolate",
subtitle = "Out of our four key cake components, selected arbitrarily for the purpose of this demonstration, chocolate stood out as the most frequently used by far. No huge surprises there!") +
theme_minimal()
Let’s add a bit of text…
key_components %>%
ggplot(aes(x = component,
y = count,
fill = component)) +
geom_bar(stat = "identity") +
labs(title = "Everybody loves chocolate",
subtitle = "Out of our four key cake components, selected arbitrarily for the purpose of this demonstration, chocolate stood out as the most frequently used by far. No huge surprises there!") +
theme_minimal(base_size = 18)
Mini tip! Get the bars in order
key_components %>%
arrange(count) %>%
mutate(component = factor(component,
levels = component)) %>%
ggplot(aes(x = component,
y = count,
fill = component,
colour = component)) +
geom_bar(stat = "identity") +
labs(title = "Everybody loves chocolate",
subtitle = "Out of our four key cake components, selected arbitrarily for the purpose of this demonstration, chocolate stood out as the most frequently used by far. No huge surprises there!") +
theme_minimal(base_size = 18)
Mini tip! Avoid giving everyone a sore neck
key_components %>%
arrange(count) %>%
mutate(component = factor(component,
levels = component)) %>%
ggplot(aes(x = component,
y = count,
fill = component,
colour = component)) +
geom_bar(stat = "identity") +
labs(title = "Everybody loves chocolate",
subtitle = "Out of our four key cake components, selected arbitrarily for the purpose of this demonstration, chocolate stood out as the most frequently used by far. No huge surprises there!") +
theme_minimal(base_size = 18) +
coord_flip()
Mini tip! Use plain English
key_components %>%
arrange(count) %>%
mutate(component = factor(component,
levels = component)) %>%
ggplot(aes(x = component,
y = count,
fill = component,
colour = component)) +
geom_bar(stat = "identity") +
labs(title = "Everybody loves chocolate",
subtitle = "Out of our four key cake components, selected arbitrarily for the purpose of this demonstration, chocolate stood out as the most frequently used by far. No huge surprises there!",
y = "Number of bakes") +
theme_minimal(base_size = 18) +
coord_flip()
Perfectly functional - but…
Find out more: en.wikipedia.org/wiki/Bouba/kiki_effect
Predicted by sound properties - Passi & Arun, 2022
A mouth-watering palette!
Where we were…
Use text colour based on “anchor” colour
Override theme_minimal()
’s axis text colour
Use text colour(s) based on “anchor” colour
Increase difference between title and subtitle
Add some personality!
basic_bar_plot +
scale_fill_manual(values = component_colours) +
theme(text = element_text(family = "Cabin",
colour = "#4C3232"),
legend.position = "none",
axis.title.y = element_blank(),
plot.subtitle = element_text(size = 16),
plot.title = element_text(family = "OPTIAuvantGothic-DemiBold",
size = 24,
face = "bold",
colour = "#200000"),
axis.text = element_text(colour = "#4C3232"))
Getting fonts to work can be frustrating!
systemfonts::system_fonts() |> View()
.ttf
filesGetting fonts to work can be frustrating!
Install fonts locally, restart R Studio + 📦
{systemfonts}
({ragg}
+{textshaping}
) + Set graphics device to “AGG” + 🤞
knitr::opts_chunk$set(dev = “ragg_png”)
I ❤️ {ggtext}
basic_bar_plot +
scale_fill_manual(values = component_colours) +
theme(text = element_text(family = "Cabin",
colour = "#4C3232"),
legend.position = "none",
axis.title.y = element_blank(),
plot.subtitle = ggtext::element_textbox_simple(size = 16),
plot.title = element_text(family = "OPTIAuvantGothic-DemiBold",
size = 24,
face = "bold",
colour = "#200000"),
axis.text = element_text(colour = "#4C3232"))
I ❤️ {ggtext}
- but watch that alignment!
basic_bar_plot +
scale_fill_manual(values = component_colours) +
theme(text = element_text(family = "Cabin",
colour = "#4C3232"),
legend.position = "none",
axis.title.y = element_blank(),
plot.subtitle = ggtext::element_textbox_simple(size = 16,
vjust = 1),
plot.title = element_text(family = "OPTIAuvantGothic-DemiBold",
size = 24,
face = "bold",
colour = "#200000"),
axis.text = element_text(colour = "#4C3232"))
Allow some breathing space
basic_bar_plot +
scale_fill_manual(values = component_colours) +
theme(text = element_text(family = "Cabin",
colour = "#4C3232"),
legend.position = "none",
axis.title.y = element_blank(),
plot.subtitle = ggtext::element_textbox_simple(size = 16,
vjust = 1,
margin = margin(0, 0, 12, 0)),
plot.title = element_text(family = "OPTIAuvantGothic-DemiBold",
size = 24,
face = "bold",
colour = "#200000",
margin = margin(12, 0, 12, 0)),
axis.text = element_text(colour = "#4C3232"))
plot +
theme_minimal() +
theme(text = element_text(family = "Cabin",
size = 12,
colour = "#4C3232"),
legend.position = "none",
axis.title.y = element_blank(),
plot.subtitle = ggtext::element_textbox_simple(size = 16,
vjust = 1,
margin = margin(0, 0, 12, 0)),
plot.title = element_text(family = "OPTIAuvantGothic-DemiBold",
size = 24,
face = "bold",
colour = "#200000",
margin = margin(12, 0, 12, 0)),
axis.text = element_text(colour = "#4C3232"))
theme_nhsr_demo <- function(base_size = 12,
dark_text = "#1A242F") {
mid_text <- monochromeR::generate_palette(dark_text, "go_lighter", n_colours = 5)[2]
light_text <- monochromeR::generate_palette(dark_text, "go_lighter", n_colours = 5)[3]
theme_minimal(base_size = base_size) +
theme(text = element_text(colour = mid_text, family = "BrandonText", lineheight = 1.1),
plot.title = element_text(colour = dark_text, family = "EnriquetaSB", size = rel(1.6), margin = margin(12, 0, 8, 0)),
plot.subtitle = element_text(size = rel(1.1), margin = margin(4, 0, 0, 0)),
axis.text.y = element_text(colour = light_text, size = rel(0.8)),
axis.title.y = element_text(size = 12, margin = margin(0, 4, 0, 0)),
axis.text.x = element_text(colour = mid_text, size = 12),
axis.title.x = element_blank(),
legend.position = "top",
legend.justification = 1,
panel.grid = element_line(colour = "#F3F4F5"),
plot.caption = element_text(size = rel(0.8), margin = margin(8, 0, 0, 0)),
plot.margin = margin(0.25, 0.25, 0.25, 0.25,"cm"))
}
Find out more: Variation on a ggtheme
palmerpenguins::penguins %>%
ggplot() +
geom_point(aes(x = bill_length_mm,
y = flipper_length_mm,
colour = species,
size = body_mass_g)) +
labs(x = "Bill length (mm)",
y = "Flipper length (mm)",
title = "Let's try some *italics* in the title",
subtitle = "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.",
caption = "Data from {palmerpenguins}") +
guides(size = "none")
palmerpenguins::penguins %>%
ggplot() +
geom_point(aes(x = bill_length_mm,
y = flipper_length_mm,
colour = species,
size = body_mass_g)) +
labs(x = "Bill length (mm)",
y = "Flipper length (mm)",
title = "Let's try some *italics* in the title",
subtitle = "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.",
caption = "Data from {palmerpenguins}") +
guides(size = "none") +
ophelia::theme_ophelia()
palmerpenguins::penguins %>%
ggplot() +
geom_point(aes(x = bill_length_mm,
y = flipper_length_mm,
colour = species,
size = body_mass_g)) +
labs(x = "Bill length (mm)",
y = "Flipper length (mm)",
title = "Let's try some *italics* in the title",
subtitle = "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.",
caption = "Data from {palmerpenguins}") +
guides(size = "none") +
ophelia::scale_colour_ophelia() +
ophelia::theme_ophelia()
Our starting point
Mind the gap!
I ❤️ {ggtext}
Debugging mode
Debugging mode
Conditional alignments!
Conditional alignments & colour
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = component,
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
size = 7,
fill = "white")
Conditional alignments & colour
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = component,
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
size = 7,
fill = "white") +
scale_colour_identity()
Bring in our fonts and colours
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = component,
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity()
Do we need that text?
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = component,
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity() +
theme(axis.text.y = element_blank())
Could we make our labels more informative?
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = paste0(component,
"<br><span style='font-size:32pt'>",
count,
"</span>"),
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity() +
theme(axis.text.y = element_blank())
Alignment tweak
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = paste0(component,
"<span style='font-size:32pt'><br>",
count,
"</span>"),
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
vjust = 0.45,
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity() +
theme(axis.text.y = element_blank())
Do we need the rest of this?
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = paste0(component,
" bakes<span style='font-size:32pt'><br>",
count,
"</span>"),
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
vjust = 0.45,
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity() +
theme(axis.text.y = element_blank(),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
panel.grid = element_blank())
How would I actually say that?
bar_plot_text_hierarchy +
scale_y_continuous(expand = expansion(c(0, 0.02))) +
ggtext::geom_textbox(aes(label = paste0("<span style='font-size:32pt'><br>",
count,
"<br></span>",
component, " bakes"),
hjust = case_when(count < 50 ~ 0,
TRUE ~ 1),
halign = case_when(count < 50 ~ 0,
TRUE ~ 1),
colour = case_when(count < 50 ~ "#4C3232",
TRUE ~ "white")),
vjust = 0.45,
fill = NA,
box.colour = NA,
family = "Cabin",
size = 7,
fontface = "bold") +
scale_colour_identity() +
theme(axis.text.y = element_blank(),
plot.title.position = "plot",
axis.text.x = element_blank(),
axis.title.x = element_blank(),
panel.grid = element_blank())
“But that was easy, there was so little data!”
Try facets?
Try facets on less data?
Enter {gghighlight}
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = baker),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1) +
facet_grid(. ~ series) +
theme_minimal()
Enter {gghighlight}
- calculate_per_facet
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = baker),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
facet_grid(. ~ series) +
theme_minimal()
Enter {gghighlight}
- calculate_per_facet
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7) +
facet_grid(. ~ series) +
theme_minimal()
I ❤️ {geomtextpath}
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,
text_only = TRUE,
hjust = 0.3) +
theme_minimal()
And some more {ggtext}
fun!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3) +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = technical)) +
theme_minimal()
And some more {ggtext}
fun!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3) +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = technical,
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0))) +
theme_minimal()
And some more {ggtext}
fun!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3) +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_minimal()
And some more {ggtext}
fun!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_minimal()
Format the facet titles
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series,
labeller = as_labeller(function(x)
paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16))
Format the facet titles
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(16, 0, 0, 0))))
Very subtle decluttering - NA colours!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params =
list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(16, 0, 0, 0))))
Adjust text hierarchy
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params = list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
size = 7,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
size = 6,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(12, 0, 0, 0))))
Use colour!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params = list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
size = 7,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
size = 6,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(12, 0, 0, 0))))
Use colour!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params = list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker,
colour = series),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
size = 7,
family = "Cabin") +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0)),
box.colour = NA,
size = 6,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(12, 0, 0, 0))))
Use colour!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params = list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker,
colour = series),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
size = 7,
family = "Cabin",
show.legend = FALSE) +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0),
colour = series),
box.colour = NA,
size = 6,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(12, 0, 0, 0))))
Use colour!
bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
ggplot(aes(x = episode,
y = -technical)) +
geom_path(aes(colour = series),
show.legend = FALSE) +
gghighlight::gghighlight(series_winner == 1,
calculate_per_facet = TRUE,
unhighlighted_params = list(color = "#D2CCCC")) +
scale_colour_gradient2(low = "#e04121", mid = "#f7238a",
high = "#ed9e00", midpoint = 7.1) +
facet_grid(. ~ series, labeller = as_labeller(function(x) paste("Series", x))) +
geomtextpath::geom_textpath(aes(label = baker,
colour = series),
vjust = -0.2,text_only = TRUE,
hjust = 0.3,
size = 7,
family = "Cabin",
show.legend = FALSE) +
ggtext::geom_textbox(data = bakeoff::bakes_raw %>%
filter(series %in% c(6:8)) %>%
left_join(bakeoff::bakers %>%
filter(series_winner == 1)) %>%
filter(series_winner == 1,
episode %in% c(1, 10)),
aes(label = paste0("#", technical),
hjust = case_when(episode == 1 ~ 1,
TRUE ~ 0),
halign = case_when(episode == 1 ~ 1,
TRUE ~ 0),
colour = series),
box.colour = NA,
size = 6,
family = "Cabin",
fill = NA) +
scale_x_continuous(expand = expansion(0.2)) +
theme_void() +
theme(strip.text = element_text(family = "Cabin", colour = "#200000",
size = 16,
margin = margin(c(12, 0, 0, 0))),
legend.position = "none")
Starting point
Sources: {bakeoff} + www.krishthebaker.com/bake-off-technicals
Reduce cognitive load: Plain English headers
Reduce cognitive load: Plain English dates - oops!
Reduce cognitive load: Plain English dates
Make numbers easy to compare: formatting
Make numbers easy to compare: monospace
Add text hierarchy: AvoiD Too MaNy CapiTalS!
Add text hierarchy: colour & size
Add text hierarchy and personality!
Make it easy to follow a line: stripe
Make it easy to follow a line: stripe or hover?
Reduce unnecessary eye movements: alignments
Reduce unnecessary eye movements: row heights (no wrap)
Reduce unnecessary eye movements: column widths
Reduce unnecessary eye movements: what’s the story?
Show vs tell: conditional colours?
Show vs tell: so much easier to compare!
Show vs tell: meaningful colours
But we should probably specify their meaning…
Technical challenges, star bakers, and number of viewers for episodes hosted by Mel & Sue and Noel & Co
Time to get interactive! {ggiraph}
ggiraph::girafe()
A (relatively easy) technical challenge
bakeoff::challenges %>%
select(-technical) %>%
pivot_longer(c(signature, showstopper)) %>%
mutate(choc_raspberry = case_when(grepl("[Cc]hocolate", value) & grepl("[Rr]aspberr", value) ~ "Both",
grepl("[Cc]hocolate", value) == T ~ "Chocolate",
grepl("[Rr]aspberry", value) == T ~ "Raspberry")) %>%
filter(!is.na(choc_raspberry)) %>%
ggplot() +
geom_rect(aes(xmin = -Inf, ymin = -Inf, xmax = Inf, ymax = Inf), fill = "#300300") +
geom_jitter(aes(x = 1, y = 1),
alpha = 0.7,
shape = 21,
size = 10,
colour = "#ec3f24",
fill = "#b41504") +
coord_polar() +
scale_colour_identity() +
scale_y_discrete(expand = c(0.05, 0)) +
labs(title = "Chocolate & Raspberry Bakes") +
theme_void() +
theme(plot.title = element_text(family = "Cabin", size = 24,
colour = "#200000", hjust = 0.5,
lineheight = 1.3))
A (relatively easy) technical challenge
choc_raspberry_bakes <- bakeoff::challenges %>%
select(-technical) %>%
pivot_longer(c(signature, showstopper)) %>%
mutate(choc_raspberry = case_when(grepl("[Cc]hocolate", value) & grepl("[Rr]aspberr", value) ~ "Both",
grepl("[Cc]hocolate", value) == T ~ "Chocolate",
grepl("[Rr]aspberry", value) == T ~ "Raspberry")) %>%
filter(!is.na(choc_raspberry)) %>%
ggplot() +
geom_rect(aes(xmin = -Inf, ymin = -Inf, xmax = Inf, ymax = Inf), fill = "#300300") +
ggiraph::geom_jitter_interactive(aes(x = 1, y = 1,
tooltip = value),
alpha = 0.7,
shape = 21,
size = 5,
colour = "#ec3f24",
fill = "#b41504") +
coord_polar() +
scale_colour_identity() +
scale_y_discrete(expand = c(0.05, 0)) +
labs(title = "Chocolate & Raspberry Bakes") +
theme_void() +
theme(plot.title = element_text(family = "Cabin", size = 24,
colour = "#200000", hjust = 0.5,
lineheight = 1.3))
A (relatively easy) technical challenge
But don’t hide the cutlery!
choc_raspberry_bakes <-
choc_raspberry_bakes +
labs(subtitle = "<br>Hover over the raspberries to see **who** created **what** in **which episode**") +
theme(plot.subtitle = ggtext::element_textbox_simple(family = "Cabin",
colour = "#4C3232",
halign = 0.5,
size = 16))
ggiraph::girafe(ggobj = choc_raspberry_bakes)
bakeoff::challenges %>%
select(-technical) %>%
pivot_longer(c(signature, showstopper)) %>%
mutate(tidy_full_ingredients = gsub("(.+?[^ |\\(])([A-Z].)", "\\1\n\\2", value),
tooltip_content = paste0(ifelse(!is.na(tidy_full_ingredients),
tidy_full_ingredients,
""),
"<br><br><span style='font-weight:bold'>", baker, " - S",
str_pad(series, 2, pad = "0"),
" E", str_pad(episode, 2, pad = "0"),
"</span>")) %>%
pull(tooltip_content) %>%
head(5)
[1] "Light Jamaican Black Cakewith Strawberries and Cream<br><br><span style='font-weight:bold'>Annetha - S01 E01</span>"
[2] "Red, White & Blue Chocolate Cake with Cigarellos, Fresh Fruit, and Cream<br><br><span style='font-weight:bold'>Annetha - S01 E01</span>"
[3] "Chocolate Orange Cake<br><br><span style='font-weight:bold'>David - S01 E01</span>"
[4] "Black Forest Floor Gateaux with Moulded Chocolate Leaves, Fallen Fruit and Chocolate Mushrooms Moulded from eggs<br><br><span style='font-weight:bold'>David - S01 E01</span>"
[5] "Caramel Cinnamon and Banana Cake<br><br><span style='font-weight:bold'>Edd - S01 E01</span>"
choc_raspberry_bakes <- bakeoff::challenges %>%
select(-technical) %>%
pivot_longer(c(signature, showstopper)) %>%
mutate(tidy_full_ingredients = gsub("(.+?[^ |\\(])([A-Z].)", "\\1\n\\2", value),
tooltip_content = paste0(ifelse(!is.na(tidy_full_ingredients),
tidy_full_ingredients,
""),
"<br><br><span style='font-weight:bold'>", baker, " - S",
str_pad(series, 2, pad = "0"),
" E", str_pad(episode, 2, pad = "0"),
"</span>")) %>%
mutate(choc_raspberry = case_when(grepl("[Cc]hocolate", value) & grepl("[Rr]aspberr", value) ~ "Both",
grepl("[Cc]hocolate", value) == T ~ "Chocolate",
grepl("[Rr]aspberry", value) == T ~ "Raspberry")) %>%
filter(!is.na(choc_raspberry)) %>%
ggplot() +
geom_rect(aes(xmin = -Inf, ymin = -Inf, xmax = Inf, ymax = Inf), fill = "#300300") +
ggiraph::geom_jitter_interactive(aes(x = 1, y = 1,
tooltip = tooltip_content),
alpha = 0.7,
shape = 21,
size = 5,
colour = "#ec3f24",
fill = "#b41504") +
labs(subtitle = "<br>Hover over the raspberries to see **who** created **what** in **which episode**") +
coord_polar() +
scale_colour_identity() +
scale_y_discrete(expand = c(0.05, 0)) +
labs(title = "Chocolate & Raspberry Bakes") +
theme_void() +
theme(plot.title = element_text(family = "Cabin", size = 24,
colour = "#200000", hjust = 0.5,
lineheight = 1.3),
plot.subtitle = ggtext::element_textbox_simple(family = "Cabin",
colour = "#4C3232",
halign = 0.5,
size = 16))
ggiraph::girafe(ggobj = choc_raspberry_bakes)
Starting point: our colours
Add padding
Fix the max width
Add lineheight spacing
🪄 Increase spacing between letters!
Back to the start
Add plot margin
Increase lineheight
Add margin under subtitle
hello@cararthompson.com | cararthomspon.com/talks