Working with Themes
= stylistic changes of non-data elements
theme_*()
theme()
bikes |>
dplyr::group_by(
month = lubridate::month(date, label = TRUE),
day_night, year
) |>
dplyr::summarize(count = sum(count))
# A tibble: 48 × 4
# Groups: month, day_night [24]
month day_night year count
<ord> <chr> <fct> <int>
1 Jan day 2015 398555
2 Jan day 2016 423622
3 Jan night 2015 148084
4 Jan night 2016 158896
5 Feb day 2015 398429
6 Feb day 2016 438254
7 Feb night 2015 145165
8 Feb night 2016 154656
9 Mar day 2015 511860
10 Mar day 2016 487395
# ℹ 38 more rows
g <- bikes |>
dplyr::group_by(month = lubridate::month(date, label = TRUE), day_night, year) |>
dplyr::summarize(count = sum(count)) |>
ggplot(aes(x = month, y = count, color = day_night)) +
geom_line(aes(group = day_night)) +
geom_point(size = 2) +
facet_wrap(~year, ncol = 1, scales = "free_x") +
coord_cartesian(clip = "off") +
scale_y_continuous(
limits = c(0, 830000), expand = c(0, 0),
labels = scales::label_comma(scale = 1/10^3, suffix = "K")
) +
scale_color_manual(values = c(day = "#FFA200", night = "#757BC7")) +
labs(
x = NULL, y = "# rented bikes", color = NULL,
title = "TfL Bike Shares per Month and Year",
caption = "Data: TfL (Transport for London)"
)
locates installed fonts and provides font-related utilities to graphic devices
# A tibble: 1,808 × 9
path index name family style weight width italic monospace
<chr> <int> <chr> <chr> <chr> <ord> <ord> <lgl> <lgl>
1 /System/Library/Fonts… 0 Note… Notew… Light normal norm… FALSE FALSE
2 /System/Library/Fonts… 0 Msht… Mshta… Regu… normal norm… FALSE FALSE
3 /Users/cedric/Library… 0 Inpu… Input… Ligh… normal cond… TRUE FALSE
4 /Users/cedric/Library… 13 Iose… Iosev… Exte… normal norm… TRUE TRUE
5 /System/Library/Fonts… 3 Kohi… Kohin… Bold bold norm… FALSE FALSE
6 /Users/cedric/Library… 0 Fami… Famil… Medi… medium norm… TRUE FALSE
7 /Users/cedric/Library… 0 Lite… Liter… Bold… bold norm… TRUE FALSE
8 /System/Library/Fonts… 4 ITFD… ITF D… Medi… medium norm… FALSE FALSE
9 /Users/cedric/Library… 0 Open… Open … Bold… bold semi… TRUE FALSE
10 /Users/cedric/Library… 0 Kola… Kolage Extr… normal norm… FALSE FALSE
# ℹ 1,798 more rows
system_fonts() |>
dplyr::filter(family == "Asap SemiCondensed") |>
dplyr::select(name) |>
dplyr::arrange(name)
# A tibble: 18 × 1
name
<chr>
1 AsapSemiCondensed-Black
2 AsapSemiCondensed-BlackItalic
3 AsapSemiCondensed-Bold
4 AsapSemiCondensed-BoldItalic
5 AsapSemiCondensed-ExtraBold
6 AsapSemiCondensed-ExtraBoldItalic
7 AsapSemiCondensed-ExtraLight
8 AsapSemiCondensed-ExtraLightItalic
9 AsapSemiCondensed-Italic
10 AsapSemiCondensed-Light
11 AsapSemiCondensed-LightItalic
12 AsapSemiCondensed-Medium
13 AsapSemiCondensed-MediumItalic
14 AsapSemiCondensed-Regular
15 AsapSemiCondensed-SemiBold
16 AsapSemiCondensed-SemiBoldItalic
17 AsapSemiCondensed-Thin
18 AsapSemiCondensed-ThinItalic
theme_set(theme_minimal(base_family = "Asap SemiCondensed", base_size = 13))
theme_update(
panel.grid.minor = element_blank(),
strip.text = element_text(face = "bold", size = rel(1.1)),
plot.title = element_text(face = "bold", size = rel(1.3)),
plot.title.position = "plot",
plot.caption.position = "plot"
)
function (base_size = 11, base_family = "", base_line_size = base_size/22,
base_rect_size = base_size/22)
{
half_line <- base_size/2
t <- theme(line = element_line(colour = "black", linewidth = base_line_size,
linetype = 1, lineend = "butt"), rect = element_rect(fill = "white",
colour = "black", linewidth = base_rect_size, linetype = 1),
text = element_text(family = base_family, face = "plain",
colour = "black", size = base_size, lineheight = 0.9,
hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(),
debug = FALSE), axis.line = element_blank(), axis.line.x = NULL,
axis.line.y = NULL, axis.text = element_text(size = rel(0.8),
colour = "grey30"), axis.text.x = element_text(margin = margin(t = 0.8 *
half_line/2), vjust = 1), axis.text.x.top = element_text(margin = margin(b = 0.8 *
half_line/2), vjust = 0), axis.text.y = element_text(margin = margin(r = 0.8 *
half_line/2), hjust = 1), axis.text.y.right = element_text(margin = margin(l = 0.8 *
half_line/2), hjust = 0), axis.text.r = element_text(margin = margin(l = 0.8 *
half_line/2, r = 0.8 * half_line/2), hjust = 0.5),
axis.ticks = element_line(colour = "grey20"), axis.ticks.length = unit(half_line/2,
"pt"), axis.ticks.length.x = NULL, axis.ticks.length.x.top = NULL,
axis.ticks.length.x.bottom = NULL, axis.ticks.length.y = NULL,
axis.ticks.length.y.left = NULL, axis.ticks.length.y.right = NULL,
axis.minor.ticks.length = rel(0.75), axis.title.x = element_text(margin = margin(t = half_line/2),
vjust = 1), axis.title.x.top = element_text(margin = margin(b = half_line/2),
vjust = 0), axis.title.y = element_text(angle = 90,
margin = margin(r = half_line/2), vjust = 1), axis.title.y.right = element_text(angle = -90,
margin = margin(l = half_line/2), vjust = 1), legend.background = element_rect(colour = NA),
legend.spacing = unit(2 * half_line, "pt"), legend.spacing.x = NULL,
legend.spacing.y = NULL, legend.margin = margin(half_line,
half_line, half_line, half_line), legend.key = NULL,
legend.key.size = unit(1.2, "lines"), legend.key.height = NULL,
legend.key.width = NULL, legend.key.spacing = unit(half_line,
"pt"), legend.text = element_text(size = rel(0.8)),
legend.title = element_text(hjust = 0), legend.ticks.length = rel(0.2),
legend.position = "right", legend.direction = NULL, legend.justification = "center",
legend.box = NULL, legend.box.margin = margin(0, 0, 0,
0, "cm"), legend.box.background = element_blank(),
legend.box.spacing = unit(2 * half_line, "pt"), panel.background = element_rect(fill = "grey92",
colour = NA), panel.border = element_blank(), panel.grid = element_line(colour = "white"),
panel.grid.minor = element_line(linewidth = rel(0.5)),
panel.spacing = unit(half_line, "pt"), panel.spacing.x = NULL,
panel.spacing.y = NULL, panel.ontop = FALSE, strip.background = element_rect(fill = "grey85",
colour = NA), strip.clip = "inherit", strip.text = element_text(colour = "grey10",
size = rel(0.8), margin = margin(0.8 * half_line,
0.8 * half_line, 0.8 * half_line, 0.8 * half_line)),
strip.text.x = NULL, strip.text.y = element_text(angle = -90),
strip.text.y.left = element_text(angle = 90), strip.placement = "inside",
strip.placement.x = NULL, strip.placement.y = NULL, strip.switch.pad.grid = unit(half_line/2,
"pt"), strip.switch.pad.wrap = unit(half_line/2,
"pt"), plot.background = element_rect(colour = "white"),
plot.title = element_text(size = rel(1.2), hjust = 0,
vjust = 1, margin = margin(b = half_line)), plot.title.position = "panel",
plot.subtitle = element_text(hjust = 0, vjust = 1, margin = margin(b = half_line)),
plot.caption = element_text(size = rel(0.8), hjust = 1,
vjust = 1, margin = margin(t = half_line)), plot.caption.position = "panel",
plot.tag = element_text(size = rel(1.2), hjust = 0.5,
vjust = 0.5), plot.tag.position = "topleft", plot.margin = margin(half_line,
half_line, half_line, half_line), complete = TRUE)
ggplot_global$theme_all_null %+replace% t
}
<bytecode: 0x129e7c850>
<environment: namespace:ggplot2>
function (base_size = 11, base_family = "", base_line_size = base_size/22,
base_rect_size = base_size/22)
{
theme_bw(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) %+replace%
theme(axis.ticks = element_blank(), legend.background = element_blank(),
legend.key = element_blank(), panel.background = element_blank(),
panel.border = element_blank(), strip.background = element_blank(),
plot.background = element_blank(), complete = TRUE)
}
<bytecode: 0x10c1ffe40>
<environment: namespace:ggplot2>
theme_asap <- function(base_size = 13, base_family = "Asap SemiCondensed",
base_line_size = base_size/22, base_rect_size = base_size/22) {
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) %+replace%
theme(
# add your theme changes here
)
}
theme_asap <- function(base_size = 13, base_family = "Asap SemiCondensed",
base_line_size = base_size/22, base_rect_size = base_size/22) {
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) %+replace%
theme(
plot.title = element_text(size = rel(1.3), margin = margin(b = base_size/2),
family = "Asap SemiCondensed Extrabold", hjust = 0),
plot.title.position = "plot",
plot.caption = element_text(color = "grey30", margin = margin(t = base_size),
size = rel(0.8), hjust = 1, vjust = 1),
plot.caption.position = "plot",
axis.title.x = element_text(hjust = 0, vjust = 0, margin = margin(t = base_size/3)),
axis.title.y = element_text(hjust = 1, vjust = 0, angle = 90, margin = margin(r = base_size/3)),
panel.background = element_rect(fill = "white", color = "grey20"),
panel.border = element_rect(fill = NA, color = "grey20"),
plot.background = element_rect(fill = "grey85", color = NA),
legend.justification = "top",
strip.text = element_text(size = rel(1.05), margin = margin(base_size/2, 0, base_size/2, 0)),
panel.grid.minor = element_blank(),
complete = TRUE
)
}
%+replace%
replaces the entire element; any element of a theme not specified in e2 will not be present in the resulting theme (i.e. NULL).
Thus this operator can be used to overwrite an entire theme.
+
updates the elements of e1 that differ from elements specified (not NULL) in e2.
Thus this operator can be used to incrementally add or modify attributes of a ggplot theme.
theme_asap_plus <- function(base_size = 13, base_family = "Asap SemiCondensed",
base_line_size = base_size/22, base_rect_size = base_size/22) {
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) +
theme(
plot.title = element_text(size = rel(1.3), hjust = 0,
family = "Asap SemiCondensed Extrabold"),
plot.title.position = "plot",
plot.caption = element_text(color = "grey30", margin = margin(t = base_size)),
plot.caption.position = "plot",
axis.title.x = element_text(hjust = 0, margin = margin(t = base_size/3)),
axis.title.y = element_text(hjust = 1, margin = margin(r = base_size/3)),
panel.background = element_rect(fill = "white", color = "grey20"),
panel.border = element_rect(fill = NA, color = "grey20"),
plot.background = element_rect(fill = "grey85", color = NA),
legend.justification = "top",
strip.text = element_text(size = rel(1.05), margin = margin(base_size/2, 0, base_size/2, 0)),
panel.grid.minor = element_blank()
)
}
theme_asap_title <- function(base_size = 13, base_family = "Asap SemiCondensed",
title_family = "Asap SemiCondensed Extrabold",
base_line_size = base_size/22, base_rect_size = base_size/22) {
if (title_family == "Asap SemiCondensed Extrabold") {
register_variant(name = "Asap SemiCondensed Extrabold",
family = "Asap SemiCondensed",
weight = "ultrabold")
}
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) +
theme(
plot.title = element_text(size = rel(1.3), hjust = 0, family = title_family),
# fill in other theme adjustments here
)
}
theme_fonts <- function(base_size = 12, base_line_size = base_size/22,
base_rect_size = base_size/22) {
unavailable <- vector("character")
if (sum(grepl("Hepta Slab", systemfonts::system_fonts()$family)) > 0) {
systemfonts::register_variant(
name = "Hepta Slab Extrabold",
family = "Hepta Slab",
weight = "ultrabold"
)
title_family <- "Hepta Slab Extrabold"
} else {
title_family <- ""
unavailable <- c(unavailable, "Hepta Slab")
}
if (sum(grepl("Spline Sans", systemfonts::system_fonts()$family)) > 0) {
base_family <- "Spline Sans"
} else {
base_family <- ""
unavailable <- c(unavailable, "Spline Sans")
}
if (length(unavailable) > 0) {
unavailable <- data.frame(
name = unavailable,
url = paste0("https://fonts.google.com/specimen/", sub(" ", "+", unavailable))
)
message(paste(
"Using system default typefaces.",
"For proper use, please install the following typeface(s):",
paste0(" - ", unavailable$name, ": ", unavailable$url, collapse = "\n"),
"Then restart your R session.",
sep = "\n"
))
}
theme_asap(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) +
theme(
plot.title = element_text(size = rel(1.3), hjust = 0, family = title_family)
)
}
Using system default typefaces.
For proper use, please install the following typeface(s):
- Hepta Slab: https://fonts.google.com/specimen/Hepta+Slab
- Spline: https://fonts.google.com/specimen/Spline+Sans
Then restart your R session.
Pro: Users don’t have to use theme()
.
Con: Users don’t have to use theme()
.
Pro: Users don’t have to use theme()
.
Con: Users don’t have to use theme()
.
theme_asap_grid <- function(base_size = 13, base_family = "Asap SemiCondensed", grid = "xy",
base_line_size = base_size/22, base_rect_size = base_size/22) {
out <-
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) +
theme(
panel.grid.major = element_blank(),
axis.ticks = element_line(color = "grey20"),
axis.ticks.length = unit(base_size/2, "pt"),
# fill in other theme adjustments here
)
if (stringr::str_detect(grid, "x|X")) {
out <- out + theme(panel.grid.major.x = element_line(color = "grey87"),
axis.ticks.x = element_blank(),
axis.ticks.length.x = unit(base_size/6, "pt"))
}
if (stringr::str_detect(grid, "y|Y")) {
out <- out + theme(panel.grid.major.y = element_line(color = "grey87"),
axis.ticks.y = element_blank(),
axis.ticks.length.y = unit(base_size/4, "pt"))
}
return(out)
}
theme_asap_grid <- function(base_size = 13, base_family = "Asap SemiCondensed", grid = "xy",
base_line_size = base_size/22, base_rect_size = base_size/22) {
if(!stringr::str_detect(grid, "none|x|X|y|Y")) stop('grid must be a character: "none" or any combination of "X", "Y", "x" and "y".')
out <-
theme_minimal(base_size = base_size, base_family = base_family,
base_line_size = base_line_size, base_rect_size = base_rect_size) +
theme(
panel.grid.major = element_blank(),
axis.ticks = element_line(color = "grey20"),
axis.ticks.length = unit(base_size/2, "pt"),
# fill in other theme adjustments here
)
if (stringr::str_detect(grid, "x|X")) {
out <- out + theme(panel.grid.major.x = element_line(color = "grey87"),
axis.ticks.x = element_blank(),
axis.ticks.length.x = unit(base_size/6, "pt"))
}
if (stringr::str_detect(grid, "y|Y")) {
out <- out + theme(panel.grid.major.y = element_line(color = "grey87"),
axis.ticks.y = element_blank(),
axis.ticks.length.y = unit(base_size/4, "pt"))
}
return(out)
}
Error in theme_asap_grid(grid = “all”) :
grid must be a character: “none” or any combination of “X”, “Y”, “x” and “y”.
theme_*()
and modify theme defaults via theme()
theme_set()
and theme_update()
{systemfonts}
allows to use non-default typefaces and register font variantstheme_*
function.theme_*
function.Cédric Scherer // posit::conf(2023)