library(ggplot2)Custom ggplot themes
I often want to consistently theme my ggplots across projects. I’ve developed some custom themes, but they’re usually ad-hoc, and don’t work particularly well in packages, because the simple way to do it isn’t a function.
For example, we might have a theme that’s good for publication, as in Saving and theming plots, where we specify size, backgrounds, and text. We load new fonts first.
# Load local functions
devtools::load_all()ℹ Loading galenR
showtext::showtext_auto()
pubfont <- 'Cambria'
loadfonts(fontvec = pubfont)pubtheme <- theme_bw(base_size = 10) +
theme(strip.background = element_blank(),
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(family=pubfont))Here, the theme is essentially hardcoded, and we can add it to a figure.
ggplot(iris, aes(x = Sepal.Length, y = Petal.Width, color = Species)) +
geom_point() +
facet_wrap(~Species) +
pubtheme
What’s the problem?
First, we have to adjust the theme with + if we want to make changes.
Most importantly, probably, is that in packages that gets read in as an object, instead of a function (which yes, are objects, but packages like functions).
Making it a function
The solution is to make it a function. This matches how the built-in themes work too, e.g. we add theme_bw(), not theme_bw , and that lets us modify it in the arguments. As a simple case, this lets us use the base_size to have a theme that we can give larger fonts to for talks vs papers, for example, whereas in the past I’d have two different names for that.
theme_pub <- function(base_size = 10) {
ggplot2::theme_bw(base_size = base_size) +
theme(strip.background = element_blank(),
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(family=pubfont))
}This looks the same
ggplot(iris, aes(x = Sepal.Length, y = Petal.Width, color = Species)) +
geom_point() +
facet_wrap(~Species) +
theme_pub()
Now, maybe we also want to make the font an argument? Now, we can include loadfonts to load it if it’s not already.
theme_pubf <- function(base_size = 10, font) {
if (!(font %in% sysfonts::font_families())) {
loadfonts(font)
}
ggplot2::theme_bw(base_size = base_size) +
theme(strip.background = element_blank(),
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(family=font))
}Now let’s change the font
ggplot(iris, aes(x = Sepal.Length, y = Petal.Width, color = Species)) +
geom_point() +
facet_wrap(~Species) +
theme_pubf(base_size = 14, font = 'Calibri')
Can we pass other arguments?
If the goal is to enforce a style, we might not want to allow passing other arguments to theme, but can we with …?
theme_pub_dots <- function(base_size = 10, font, ...) {
if (!(font %in% sysfonts::font_families())) {
loadfonts(font)
}
ggplot2::theme_bw(base_size = base_size) +
theme(strip.background = element_blank(),
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(family=font),
...)
}ggplot(iris, aes(x = Sepal.Length, y = Petal.Width, color = Species)) +
geom_point() +
facet_wrap(~Species) +
theme_pub_dots(base_size = 8, font = 'Arial', legend.position = 'none')