#------------------------------------------------------------------------------#
# #
# Graphic Design with ggplot2: #
# How to Create Engaging and Complex Visualizations in R #
# #
# Working with Labels and Annotations #
# #
# Dr. Cédric Scherer #
# rstudio::conf(2022) workshop #
# July 25-26th, 2022 #
# #
#------------------------------------------------------------------------------#
## -----------------------------------------------------------------------------
library(tidyverse)
bikes <- readr::read_csv(
here::here("data", "london-bikes-custom.csv"),
col_types = "Dcfffilllddddc"
)
bikes$season <- forcats::fct_inorder(bikes$season)
theme_set(theme_light(base_size = 14, base_family = "Roboto Condensed"))
theme_update(
panel.grid.minor = element_blank(),
legend.position = "top"
)
## -----------------------------------------------------------------------------
g <- ggplot(
bikes,
aes(x = temp_feel, y = count,
color = season)
) +
geom_point(
alpha = .5
) +
labs(
x = "Feels-like temperature (°F)",
y = "Reported bike shares",
title = "TfL bike sharing trends",
subtitle = "Reported bike rents versus feels-like temperature in London",
caption = "Data: TfL",
color = "Season:",
tag = "1."
)
g
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
axis.text = element_text(
color = "grey40"
)
)
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
axis.text = element_text(
color = "grey40",
family = "Tabular",
face = "italic",
hjust = 1,
vjust = 0,
angle = 45,
lineheight = 1.3, ## no effect here
margin = margin(10, 0, 20, 0)
)
)
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
axis.text = element_text(
color = "grey40",
family = "Tabular",
face = "italic",
colour = NULL,
size = NULL,
hjust = 1,
vjust = 0,
angle = 45,
lineheight = 1.3, ## no effect here
margin = margin(10, 0, 20, 0) ## no effect here
),
axis.text.x = element_text(
margin = margin(10, 0, 20, 0) ## trbl
)
)
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
axis.text = element_text(
color = "grey40",
family = "Tabular",
face = "italic",
colour = NULL,
size = NULL,
hjust = 1,
vjust = 0,
angle = 45,
lineheight = 1.3, ## no effect here
margin = margin(10, 0, 20, 0) ## no effect here
),
plot.tag = element_text(
margin = margin(0, 12, -8, 0) ## trbl
)
)
## -----------------------------------------------------------------------------
g + theme(
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
axis.text = element_text(
color = "grey40",
family = "Tabular",
face = "italic",
colour = NULL,
size = NULL,
hjust = 1,
vjust = 0,
angle = 45,
lineheight = 1.3, ## no effect here
margin = margin(10, 0, 20, 0), ## no effect here
debug = TRUE
),
plot.tag = element_text(
margin = margin(0, 12, -8, 0), ## trbl
debug = TRUE
)
)
## -----------------------------------------------------------------------------
g <- g + labs(title = NULL, subtitle = NULL, tag = NULL)
g +
scale_y_continuous(
breaks = 0:4*15000
)
## -----------------------------------------------------------------------------
g +
scale_y_continuous(
breaks = 0:4*15000,
labels = scales::comma_format()
)
## -----------------------------------------------------------------------------
g +
scale_y_continuous(
breaks = 0:4*15000,
labels = scales::comma_format(
suffix = " bikes"
),
name = NULL
)
## -----------------------------------------------------------------------------
g +
scale_y_continuous(
breaks = 0:4*15000,
labels = scales::comma_format(
suffix = "\nbikes shared"
),
name = NULL
) +
theme(
axis.text.y = element_text(
hjust = .5
)
)
## -----------------------------------------------------------------------------
g +
scale_y_continuous(
breaks = 0:4*15000,
labels = scales::comma_format(
scale = .001
),
name = "Reported bike shares in thousands"
)
## -----------------------------------------------------------------------------
g +
scale_y_continuous(
breaks = 0:4*15000,
labels = function(y) y / 1000,
name = "Reported bike shares in thousands",
)
## -----------------------------------------------------------------------------
g +
scale_x_continuous(
labels = function(y) paste0(y, "°F"),
name = "Feels-Like Temperature"
)
## -----------------------------------------------------------------------------
ggplot(
bikes,
aes(x = season, y = count)
) +
geom_boxplot() +
scale_x_discrete()
## -----------------------------------------------------------------------------
ggplot(
bikes,
aes(x = season, y = count)
) +
geom_boxplot() +
scale_x_discrete(
name = NULL,
labels = stringr::str_to_title
)
## -----------------------------------------------------------------------------
g +
scale_color_discrete(
name = NULL,
labels = stringr::str_to_title
)
## -----------------------------------------------------------------------------
g +
ggtitle("**TfL bike sharing trends by _season_**")
## -----------------------------------------------------------------------------
# install.packages("ggtext")
g +
ggtitle("**TfL bike sharing trends by _season_**") +
theme(
plot.title = ggtext::element_markdown()
)
## -----------------------------------------------------------------------------
# install.packages("ggtext")
g +
ggtitle("TfL bike sharing trends by season") +
theme(
plot.title = ggtext::element_markdown()
)
## -----------------------------------------------------------------------------
g +
facet_wrap(
~ day_night,
labeller = label_both
)
## -----------------------------------------------------------------------------
g +
facet_wrap(
~ is_workday + day_night,
labeller = label_both
)
## -----------------------------------------------------------------------------
g +
facet_wrap(
~ is_workday + day_night,
labeller = labeller(
day_night = stringr::str_to_title
)
)
## -----------------------------------------------------------------------------
codes <- c(
`TRUE` = "Workday",
`FALSE` = "Weekend or Holiday"
)
g +
facet_wrap(
~ is_workday + day_night,
labeller = labeller(
day_night = stringr::str_to_title,
is_workday = codes
)
)
## -----------------------------------------------------------------------------
codes <- c(
`TRUE` = "Workday",
`FALSE` = "Weekend or Holiday"
)
g +
facet_wrap(
~ is_workday + day_night,
labeller = labeller(
.default = stringr::str_to_title,
is_workday = codes
)
)
## -----------------------------------------------------------------------------
g +
facet_grid(
day_night ~ is_workday,
scales = "free",
space = "free",
labeller = labeller(
day_night = stringr::str_to_title,
is_workday = codes
)
)
## -----------------------------------------------------------------------------
ggplot(
bikes,
aes(x = weather_type,
y = count)
) +
geom_boxplot()
## -----------------------------------------------------------------------------
ggplot(
bikes,
aes(x = stringr::str_wrap(weather_type, 6),
y = count)
) +
geom_boxplot()
## -----------------------------------------------------------------------------
g +
ggtitle("TfL bike sharing trends in 2015 and 2016 by season for day and night periods") +
theme(
plot.title = element_text(size = 20),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
g +
ggtitle("TfL bike sharing trends in 2015 and 2016 by season for day and night periods") +
theme(
plot.title =
ggtext::element_textbox_simple(size = 20),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
g +
ggtitle("TfL bike sharing trends in 2015 and 2016 by season for day and night periods") +
theme(
plot.title = ggtext::element_textbox_simple(
margin = margin(t = 12, b = 12),
lineheight = .9
),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
g +
ggtitle("TfL bike sharing trends in 2015 and 2016 by season for day and night periods") +
theme(
plot.title = ggtext::element_textbox_simple(
margin = margin(t = 12, b = 12),
fill = "grey90",
lineheight = .9
),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
g +
ggtitle("TfL bike sharing trends in 2015 and 2016 by season for day and night periods") +
theme(
plot.title = ggtext::element_textbox_simple(
margin = margin(t = 12, b = 12),
padding = margin(rep(12, 4)),
fill = "grey90",
box.color = "grey40",
r = unit(9, "pt"),
halign = .5,
face = "bold",
lineheight = .9
),
plot.title.position = "plot"
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext"
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
color = "firebrick",
fontface = "bold",
lineheight = .9
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = c(90, 50),
y = c(27.5, 3.5),
label = c("Text A", "Text B"),
color = c("black", "firebrick"),
size = c(5, 10),
fontface = c("plain", "bold")
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "rect",
xmin = -Inf,
xmax = 60,
ymin = 20,
ymax = Inf,
fill = "#663399"
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
annotate(
geom = "rect",
xmin = -Inf,
xmax = 60,
ymin = 20,
ymax = Inf,
fill = "#663399"
) +
geom_point(size = 2, color = "grey")
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
lineheight = .9
) +
annotate(
geom = "segment",
x = 90, xend = 82,
y = 25, yend = 18.5
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
lineheight = .9
) +
annotate(
geom = "curve",
x = 90, xend = 82,
y = 25, yend = 18.5
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
lineheight = .9
) +
annotate(
geom = "curve",
x = 90, xend = 82,
y = 25, yend = 18.5,
curvature = -.3,
arrow = arrow()
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
lineheight = .9
) +
annotate(
geom = "curve",
x = 90, xend = 82,
y = 25, yend = 18.5,
curvature = -.3,
arrow = arrow(
length = unit(10, "pt"),
type = "closed",
ends = "both"
)
)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(humidity, temp)) +
geom_point(size = 2, color = "grey") +
annotate(
geom = "text",
x = 90,
y = 27.5,
label = "Some\nadditional\ntext",
size = 6,
lineheight = .9
) +
annotate(
geom = "curve",
x = 94, xend = 82,
y = 26, yend = 18.5,
curvature = -.8,
angle = 140,
arrow = arrow(
length = unit(10, "pt"),
type = "closed"
)
)
## -----------------------------------------------------------------------------
g <- ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
geom_text(
aes(label = season),
nudge_x = .3,
hjust = 0
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
geom_label(
aes(label = season),
nudge_x = .3,
hjust = 0
)
## -----------------------------------------------------------------------------
set.seed(20220726)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = season)
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = str_to_title(season))
) +
scale_color_manual(
values = c("firebrick", "black"),
guide = "none"
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = str_to_title(season)),
## space between points + labels
box.padding = .4,
## always draw segments
min.segment.length = 0
) +
scale_color_manual(
values = c("firebrick", "black"),
guide = "none"
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = str_to_title(season)),
## force to the right
xlim = c(NA, 35), hjust = 1
) +
scale_color_manual(
values = c("firebrick", "black"),
guide = "none"
) +
xlim(25, NA)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = str_to_title(season)),
## force to the right
xlim = c(NA, 35),
## style segment
segment.curvature = .01,
arrow = arrow(length = unit(.02, "npc"), type = "closed")
) +
scale_color_manual(
values = c("firebrick", "black"),
guide = "none"
) +
xlim(25, NA)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp >= 27),
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point(size = 2.5) +
ggrepel::geom_text_repel(
aes(label = str_to_title(season)),
## force to the right
xlim = c(NA, 35),
## style segment
segment.curvature = .001,
segment.inflect = TRUE
) +
scale_color_manual(
values = c("firebrick", "black"),
guide = "none"
) +
xlim(25, NA)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp > 20 & season != "summer"),
aes(x = humidity, y = temp,
color = season)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point() +
scale_color_brewer(
palette = "Dark2",
guide = "none"
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp > 20 & season != "summer"),
aes(x = humidity, y = temp,
color = season)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point() +
ggforce::geom_mark_rect(
aes(label = str_to_title(season))
) +
scale_color_brewer(
palette = "Dark2",
guide = "none"
)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp > 20 & season != "summer"),
aes(x = humidity, y = temp,
color = season)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point() +
ggforce::geom_mark_rect(
aes(label = str_to_title(season))
) +
scale_color_brewer(
palette = "Dark2",
guide = "none"
) +
ylim(NA, 35)
## -----------------------------------------------------------------------------
ggplot(
filter(bikes, temp > 20 & season != "summer"),
aes(x = humidity, y = temp,
color = season)
) +
geom_point(
data = bikes,
color = "grey65", alpha = .3
) +
geom_point() +
ggforce::geom_mark_rect(
aes(label = str_to_title(season)),
expand = unit(5, "pt"),
radius = unit(0, "pt"),
con.cap = unit(0, "pt"),
label.buffer = unit(15, "pt"),
con.type = "straight",
label.fill = "transparent"
) +
scale_color_brewer(
palette = "Dark2",
guide = "none"
) +
ylim(NA, 35)
## -----------------------------------------------------------------------------
ggplot(
bikes,
aes(x = humidity, y = temp,
color = season == "summer")
) +
geom_point(alpha = .4) +
ggforce::geom_mark_hull(
aes(label = str_to_title(season),
filter = season == "summer",
description = "June to August"),
expand = unit(10, "pt")
) +
scale_color_manual(
values = c("grey65", "firebrick"),
guide = "none"
)
## -----------------------------------------------------------------------------
url <- "https://d33wubrfki0l68.cloudfront.net/dbb07b06a7b3fe056db386fef0b158cc2fd33cb9/8b491/assets/img/2022conf/logo-rstudio-conf.png"
img <- magick::image_read(url)
img <- magick::image_negate(img)
img
## -----------------------------------------------------------------------------
ggplot(bikes, aes(date, temp_feel)) +
annotation_custom(
grid::rasterGrob(
image = img
)
) +
geom_point(color = "#71a5d4")
## -----------------------------------------------------------------------------
ggplot(bikes, aes(date, temp_feel)) +
annotation_custom(
grid::rasterGrob(
image = img,
x = .5,
y = .9,
width = .9
)
) +
geom_point(color = "#71a5d4") +
ylim(NA, 37)
## -----------------------------------------------------------------------------
ggplot(bikes, aes(date, temp_feel)) +
annotation_custom(
grid::rasterGrob(
image = img,
x = .47,
y = 1.15,
width = .9
)
) +
geom_point(color = "#71a5d4") +
coord_cartesian(clip = "off") +
theme(
plot.margin = margin(90, 10, 10, 10)
)