What Andreas said
Save time
{tidyverse}, which includes (among others):
{ggplot2}
{ragg}: high-quality graphic backend for R
{systemfonts}: finds the correct font file for a specific font and style (we'll see it in action later)
library(ggplot2)
library(ggplot2)library(palmerpenguins)
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm))
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 )
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 ) + labs( title = "Title", subtitle = "Subtitle", caption = "Caption" )
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 ) + labs( title = "Title", subtitle = "Subtitle", caption = "Caption" )p
The easiest way to extend ggplot2 is to make a new theme.
— Thomas Lin Pedersen, Extending your ability to extend ggplot2
theme()
functionp
p + theme_minimal( )
p + theme_minimal( base_size = 14, )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text( size = rel(1.5) ), )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text( size = rel(1.5) ), panel.grid.minor = element_blank() )
We can simply pack the regular R code for theming into a function and save ourselves from mindless repeating or copy-pasting!
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible") { theme_minimal(base_size = base_size, base_family = base_family) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text(size = rel(1.5)), panel.grid.minor = element_blank() )}
p
p + my_theme( )
p + my_theme( base_size = 20, )
p + my_theme( base_size = 20, base_family = "Menlo" )
p + my_theme( base_size = 20, base_family = "Menlo" ) + theme( plot.title = element_text( face = "bold" ) )
theme()
)(Inspired by hrbrthemes)
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible", grid = "XY") { t <- theme_minimal(base_size = base_size, base_family = base_family) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text(size = rel(1.5)) ) if (!grepl("X", grid)) t <- t + theme(panel.grid.major.x = element_blank()) if (!grepl("Y", grid)) t <- t + theme(panel.grid.major.y = element_blank()) if (!grepl("x", grid)) t <- t + theme(panel.grid.minor.x = element_blank()) if (!grepl("y", grid)) t <- t + theme(panel.grid.minor.y = element_blank()) t}
p + my_theme()
p + my_theme(grid = "Y")
p + my_theme(grid = "Xx")
p + my_theme(grid = "xy")
Applying an unavailable font just quietly falls back to default font (or throws errors depending on your OS and graphics device).
p + my_theme( base_family = "Expensive Designer Font" )
We can control this behaviour and make it explicit using systemfonts::system_fonts()
:
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible", grid = "XY") { if (!(base_family %in% systemfonts::system_fonts()$family)) { message("Font '", base_family, "' not installed.\nUsing system's default font.") base_family <- "" } [...]}
p + my_theme( base_family = "Expensive Designer Font" )
#> Font 'Expensive Designer Font' not installed.#> Using system's default font.
Tabular numbers are monospaced, which keeps their sizes consistent for display on axes
(Source: https://blog.datawrapper.de/fonts-for-data-visualization/)
library(systemfonts)register_font( "Atkinson Hyperlegible tnum", "/path/to/Atkinson-Hyperlegible.otf", features = font_feature(numbers = "tabular"))
The newly registered font can be found in registry_fonts()
(instead of system_fonts
). New fallback condition:
!(base_family %in% c( systemfonts::system_fonts()$family, systemfonts::registry_fonts()$family ))
p + my_theme(base_family = "Atkinson Hyperlegible", )
p + my_theme(base_family = "Menlo", )
p + my_theme(base_family = "Atkinson Hyperlegible tnum", )
p + my_theme(base_family = "Atkinson Hyperlegible", )
Check out the theme_correlaid()
function:
https://github.com/CorrelAid/correltools/blob/main/R/ggplot-theme.R
Create your own theme function! 💻🚀
#bcd259
#6fa07f
#214f8f
#f04451
#85638c
#214f8f
#bcd259
#6fa07f
#214f8f
#f04451
#85638c
#214f8f
#96c342
#3863a2
#f04451
#3c3c3b
#727375
#9e9fa3
#cdced0
Save the colour palette(s) as charactor vector(s)
Create a function factory that outputs a palette with the desired number of colours
Create a scale function by wrapping a scale constructor (e.g., ggplot2::continuous_scale()
) around the palette function in step 2
correlaid_colours <- list( gradient = c("#bcd259", "#6fa07f", "#214f8f"), gradient_x = c("#f04451", "#85638c", "#214f8f"), qualitative = c("#96c342", "#3863a2", "#f04451"), grey = c("#3c3c3b", "#727375", "#9e9fa3", "#cdced0"))
correlaid_pal <- function(direction = 1, option = "qualitative") { stopifnot(length(option) == 1 && option %in% names(correlaid_colours)) cols <- correlaid_colours[[option]] function(n) { cols <- grDevices::colorRampPalette(cols, space = "Lab", interpolate = "spline")(n) if (direction < 0) rev(cols) else cols }}
Takes two argument: option
(which colour palette?) and direction
(revert or not?)
Returns a function that takes the desired number of colours (e.g., number of categories) and produces as many colours by interpolation
correlaid_pal()(n = 2)
#96C341
#F04451
correlaid_pal(option = "gradient")(n = 7)
#BBD259
#A0C568
#86B475
#6E9F7F
#588786
#406C8B
#204E8E
correlaid_pal(direction = -1, option = "gradient")(n = 7)
#204E8E
#406C8B
#588786
#6E9F7F
#86B475
#A0C568
#BBD259
scale_colour_correlaid_d <- function(direction = 1, option = "qualitative", ...) { ggplot2::discrete_scale( aesthetics = "colour", scale_name = "correlaid", palette = correlaid_pal(direction, option), ... )}
scale_colour_correlaid_d <- function(direction = 1, option = "qualitative", ...) { ggplot2::discrete_scale( aesthetics = "colour", scale_name = "correlaid", palette = correlaid_pal(direction, option), ... )}
scale_fill_correlaid_d
scale_colour_correlaid_c <- function(direction = 1, option = "gradient", guide = "colourbar", ...) { ggplot2::continuous_scale( aesthetics = "colour", scale_name = "correlaid", palette = scales::gradient_n_pal(correlaid_pal(direction, option)(8)), guide = guide, ... )}
p + scale_colour_correlaid_d()
As expected, applying a continuous colour scale to a discrete variable throws an error:
p + scale_colour_correlaid_c()
#> Error in `scale_colour_correlaid_c()`:#> ! Discrete values supplied to continuous scale.#> ℹ Example values: Adelie, Adelie, Adelie, Adelie, and Adelie
Check out the scale_*_correlaid_*()
functions:
https://github.com/CorrelAid/correltools/blob/main/R/ggplot-scales.R
View the slides at https://lo-ng.netlify.app/slides/2024-05-28-correlaid-ggplot2-theming
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
o | Tile View: Overview of Slides |
Esc | Back to slideshow |
What Andreas said
Save time
{tidyverse}, which includes (among others):
{ggplot2}
{ragg}: high-quality graphic backend for R
{systemfonts}: finds the correct font file for a specific font and style (we'll see it in action later)
library(ggplot2)
library(ggplot2)library(palmerpenguins)
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm))
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 )
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 ) + labs( title = "Title", subtitle = "Subtitle", caption = "Caption" )
library(ggplot2)library(palmerpenguins)p <- ggplot( data = penguins, aes(bill_length_mm, bill_depth_mm)) + geom_point( aes(colour = species), size = 2 ) + labs( title = "Title", subtitle = "Subtitle", caption = "Caption" )p
The easiest way to extend ggplot2 is to make a new theme.
— Thomas Lin Pedersen, Extending your ability to extend ggplot2
theme()
functionp
p + theme_minimal( )
p + theme_minimal( base_size = 14, )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text( size = rel(1.5) ), )
p + theme_minimal( base_size = 14, base_family = "Atkinson Hyperlegible" ) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text( size = rel(1.5) ), panel.grid.minor = element_blank() )
We can simply pack the regular R code for theming into a function and save ourselves from mindless repeating or copy-pasting!
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible") { theme_minimal(base_size = base_size, base_family = base_family) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text(size = rel(1.5)), panel.grid.minor = element_blank() )}
p
p + my_theme( )
p + my_theme( base_size = 20, )
p + my_theme( base_size = 20, base_family = "Menlo" )
p + my_theme( base_size = 20, base_family = "Menlo" ) + theme( plot.title = element_text( face = "bold" ) )
theme()
)(Inspired by hrbrthemes)
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible", grid = "XY") { t <- theme_minimal(base_size = base_size, base_family = base_family) + theme( legend.position = "top", plot.title.position = "plot", plot.title = element_text(size = rel(1.5)) ) if (!grepl("X", grid)) t <- t + theme(panel.grid.major.x = element_blank()) if (!grepl("Y", grid)) t <- t + theme(panel.grid.major.y = element_blank()) if (!grepl("x", grid)) t <- t + theme(panel.grid.minor.x = element_blank()) if (!grepl("y", grid)) t <- t + theme(panel.grid.minor.y = element_blank()) t}
p + my_theme()
p + my_theme(grid = "Y")
p + my_theme(grid = "Xx")
p + my_theme(grid = "xy")
Applying an unavailable font just quietly falls back to default font (or throws errors depending on your OS and graphics device).
p + my_theme( base_family = "Expensive Designer Font" )
We can control this behaviour and make it explicit using systemfonts::system_fonts()
:
my_theme <- function(base_size = 14, base_family = "Atkinson Hyperlegible", grid = "XY") { if (!(base_family %in% systemfonts::system_fonts()$family)) { message("Font '", base_family, "' not installed.\nUsing system's default font.") base_family <- "" } [...]}
p + my_theme( base_family = "Expensive Designer Font" )
#> Font 'Expensive Designer Font' not installed.#> Using system's default font.
Tabular numbers are monospaced, which keeps their sizes consistent for display on axes
(Source: https://blog.datawrapper.de/fonts-for-data-visualization/)
library(systemfonts)register_font( "Atkinson Hyperlegible tnum", "/path/to/Atkinson-Hyperlegible.otf", features = font_feature(numbers = "tabular"))
The newly registered font can be found in registry_fonts()
(instead of system_fonts
). New fallback condition:
!(base_family %in% c( systemfonts::system_fonts()$family, systemfonts::registry_fonts()$family ))
p + my_theme(base_family = "Atkinson Hyperlegible", )
p + my_theme(base_family = "Menlo", )
p + my_theme(base_family = "Atkinson Hyperlegible tnum", )
p + my_theme(base_family = "Atkinson Hyperlegible", )
Check out the theme_correlaid()
function:
https://github.com/CorrelAid/correltools/blob/main/R/ggplot-theme.R
Create your own theme function! 💻🚀
#bcd259
#6fa07f
#214f8f
#f04451
#85638c
#214f8f
#bcd259
#6fa07f
#214f8f
#f04451
#85638c
#214f8f
#96c342
#3863a2
#f04451
#3c3c3b
#727375
#9e9fa3
#cdced0
Save the colour palette(s) as charactor vector(s)
Create a function factory that outputs a palette with the desired number of colours
Create a scale function by wrapping a scale constructor (e.g., ggplot2::continuous_scale()
) around the palette function in step 2
correlaid_colours <- list( gradient = c("#bcd259", "#6fa07f", "#214f8f"), gradient_x = c("#f04451", "#85638c", "#214f8f"), qualitative = c("#96c342", "#3863a2", "#f04451"), grey = c("#3c3c3b", "#727375", "#9e9fa3", "#cdced0"))
correlaid_pal <- function(direction = 1, option = "qualitative") { stopifnot(length(option) == 1 && option %in% names(correlaid_colours)) cols <- correlaid_colours[[option]] function(n) { cols <- grDevices::colorRampPalette(cols, space = "Lab", interpolate = "spline")(n) if (direction < 0) rev(cols) else cols }}
Takes two argument: option
(which colour palette?) and direction
(revert or not?)
Returns a function that takes the desired number of colours (e.g., number of categories) and produces as many colours by interpolation
correlaid_pal()(n = 2)
#96C341
#F04451
correlaid_pal(option = "gradient")(n = 7)
#BBD259
#A0C568
#86B475
#6E9F7F
#588786
#406C8B
#204E8E
correlaid_pal(direction = -1, option = "gradient")(n = 7)
#204E8E
#406C8B
#588786
#6E9F7F
#86B475
#A0C568
#BBD259
scale_colour_correlaid_d <- function(direction = 1, option = "qualitative", ...) { ggplot2::discrete_scale( aesthetics = "colour", scale_name = "correlaid", palette = correlaid_pal(direction, option), ... )}
scale_colour_correlaid_d <- function(direction = 1, option = "qualitative", ...) { ggplot2::discrete_scale( aesthetics = "colour", scale_name = "correlaid", palette = correlaid_pal(direction, option), ... )}
scale_fill_correlaid_d
scale_colour_correlaid_c <- function(direction = 1, option = "gradient", guide = "colourbar", ...) { ggplot2::continuous_scale( aesthetics = "colour", scale_name = "correlaid", palette = scales::gradient_n_pal(correlaid_pal(direction, option)(8)), guide = guide, ... )}
p + scale_colour_correlaid_d()
As expected, applying a continuous colour scale to a discrete variable throws an error:
p + scale_colour_correlaid_c()
#> Error in `scale_colour_correlaid_c()`:#> ! Discrete values supplied to continuous scale.#> ℹ Example values: Adelie, Adelie, Adelie, Adelie, and Adelie
Check out the scale_*_correlaid_*()
functions:
https://github.com/CorrelAid/correltools/blob/main/R/ggplot-scales.R
View the slides at https://lo-ng.netlify.app/slides/2024-05-28-correlaid-ggplot2-theming