diff --git a/content/blog/ggplot2-styling/figs/aspect_ratio-1.png b/content/blog/ggplot2-styling/figs/aspect_ratio-1.png new file mode 100644 index 000000000..4798ab518 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/aspect_ratio-1.png differ diff --git a/content/blog/ggplot2-styling/figs/axis_local_theme-1.png b/content/blog/ggplot2-styling/figs/axis_local_theme-1.png new file mode 100644 index 000000000..560e280c8 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/axis_local_theme-1.png differ diff --git a/content/blog/ggplot2-styling/figs/base_plot-1.png b/content/blog/ggplot2-styling/figs/base_plot-1.png new file mode 100644 index 000000000..b379aa9a1 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/base_plot-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_base_size-1.png b/content/blog/ggplot2-styling/figs/complete_base_size-1.png new file mode 100644 index 000000000..4be24f606 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_base_size-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_bw-1.png b/content/blog/ggplot2-styling/figs/complete_bw-1.png new file mode 100644 index 000000000..99068d0b0 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_bw-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_classic-1.png b/content/blog/ggplot2-styling/figs/complete_classic-1.png new file mode 100644 index 000000000..4ff8f0027 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_classic-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_cowplot-1.png b/content/blog/ggplot2-styling/figs/complete_cowplot-1.png new file mode 100644 index 000000000..95819bd91 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_cowplot-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_dark-1.png b/content/blog/ggplot2-styling/figs/complete_dark-1.png new file mode 100644 index 000000000..ba82ace9b Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_dark-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_font_family-1.png b/content/blog/ggplot2-styling/figs/complete_font_family-1.png new file mode 100644 index 000000000..5dc0b93a5 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_font_family-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_ggthemes-1.png b/content/blog/ggplot2-styling/figs/complete_ggthemes-1.png new file mode 100644 index 000000000..27de77e74 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_ggthemes-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_grey-1.png b/content/blog/ggplot2-styling/figs/complete_grey-1.png new file mode 100644 index 000000000..b379aa9a1 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_grey-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_ink_paper-1.png b/content/blog/ggplot2-styling/figs/complete_ink_paper-1.png new file mode 100644 index 000000000..df8ef5d5f Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_ink_paper-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_light-1.png b/content/blog/ggplot2-styling/figs/complete_light-1.png new file mode 100644 index 000000000..8b431b93c Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_light-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_linedraw-1.png b/content/blog/ggplot2-styling/figs/complete_linedraw-1.png new file mode 100644 index 000000000..03fa0c288 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_linedraw-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_minimal-1.png b/content/blog/ggplot2-styling/figs/complete_minimal-1.png new file mode 100644 index 000000000..b3f638eeb Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_minimal-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_test-1.png b/content/blog/ggplot2-styling/figs/complete_test-1.png new file mode 100644 index 000000000..3d815f6e1 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_test-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_tvthemes-1.png b/content/blog/ggplot2-styling/figs/complete_tvthemes-1.png new file mode 100644 index 000000000..a6040dcad Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_tvthemes-1.png differ diff --git a/content/blog/ggplot2-styling/figs/complete_void-1.png b/content/blog/ggplot2-styling/figs/complete_void-1.png new file mode 100644 index 000000000..38a03fa9d Binary files /dev/null and b/content/blog/ggplot2-styling/figs/complete_void-1.png differ diff --git a/content/blog/ggplot2-styling/figs/element_markdown-1.png b/content/blog/ggplot2-styling/figs/element_markdown-1.png new file mode 100644 index 000000000..ceaa1a9cd Binary files /dev/null and b/content/blog/ggplot2-styling/figs/element_markdown-1.png differ diff --git a/content/blog/ggplot2-styling/figs/example_complete-1.png b/content/blog/ggplot2-styling/figs/example_complete-1.png new file mode 100644 index 000000000..b3f638eeb Binary files /dev/null and b/content/blog/ggplot2-styling/figs/example_complete-1.png differ diff --git a/content/blog/ggplot2-styling/figs/extension_elements-1.png b/content/blog/ggplot2-styling/figs/extension_elements-1.png new file mode 100644 index 000000000..45afaafaf Binary files /dev/null and b/content/blog/ggplot2-styling/figs/extension_elements-1.png differ diff --git a/content/blog/ggplot2-styling/figs/fonts-1.png b/content/blog/ggplot2-styling/figs/fonts-1.png new file mode 100644 index 000000000..ca7688807 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/fonts-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_aesthetic-1.png b/content/blog/ggplot2-styling/figs/layer_aesthetic-1.png new file mode 100644 index 000000000..8feba8e8a Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_aesthetic-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_borderline-1.png b/content/blog/ggplot2-styling/figs/layer_borderline-1.png new file mode 100644 index 000000000..f7e279469 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_borderline-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_colour_fill-1.png b/content/blog/ggplot2-styling/figs/layer_colour_fill-1.png new file mode 100644 index 000000000..e2ca84f21 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_colour_fill-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_granular-1.png b/content/blog/ggplot2-styling/figs/layer_granular-1.png new file mode 100644 index 000000000..dcb738796 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_granular-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_ink_paper-1.png b/content/blog/ggplot2-styling/figs/layer_ink_paper-1.png new file mode 100644 index 000000000..eb362f1c9 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_ink_paper-1.png differ diff --git a/content/blog/ggplot2-styling/figs/layer_pointtext-1.png b/content/blog/ggplot2-styling/figs/layer_pointtext-1.png new file mode 100644 index 000000000..146e4def8 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/layer_pointtext-1.png differ diff --git a/content/blog/ggplot2-styling/figs/palettes-1.png b/content/blog/ggplot2-styling/figs/palettes-1.png new file mode 100644 index 000000000..9ce7668da Binary files /dev/null and b/content/blog/ggplot2-styling/figs/palettes-1.png differ diff --git a/content/blog/ggplot2-styling/figs/part_theme_barchart-1.png b/content/blog/ggplot2-styling/figs/part_theme_barchart-1.png new file mode 100644 index 000000000..1eec38caf Binary files /dev/null and b/content/blog/ggplot2-styling/figs/part_theme_barchart-1.png differ diff --git a/content/blog/ggplot2-styling/figs/part_theme_bottom_colourbar-1.png b/content/blog/ggplot2-styling/figs/part_theme_bottom_colourbar-1.png new file mode 100644 index 000000000..7c69f11c2 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/part_theme_bottom_colourbar-1.png differ diff --git a/content/blog/ggplot2-styling/figs/part_theme_upper_legend-1.png b/content/blog/ggplot2-styling/figs/part_theme_upper_legend-1.png new file mode 100644 index 000000000..a2014f108 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/part_theme_upper_legend-1.png differ diff --git a/content/blog/ggplot2-styling/figs/pattern_fill-1.png b/content/blog/ggplot2-styling/figs/pattern_fill-1.png new file mode 100644 index 000000000..869294633 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/pattern_fill-1.png differ diff --git a/content/blog/ggplot2-styling/figs/red_axis-1.png b/content/blog/ggplot2-styling/figs/red_axis-1.png new file mode 100644 index 000000000..1e42e755e Binary files /dev/null and b/content/blog/ggplot2-styling/figs/red_axis-1.png differ diff --git a/content/blog/ggplot2-styling/figs/root_leaves-1.png b/content/blog/ggplot2-styling/figs/root_leaves-1.png new file mode 100644 index 000000000..992755735 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/root_leaves-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_axis-1.png b/content/blog/ggplot2-styling/figs/sub_axis-1.png new file mode 100644 index 000000000..c1a5176f8 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_axis-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_axis_positions-1.png b/content/blog/ggplot2-styling/figs/sub_axis_positions-1.png new file mode 100644 index 000000000..a5b9331e7 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_axis_positions-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_axis_xy-1.png b/content/blog/ggplot2-styling/figs/sub_axis_xy-1.png new file mode 100644 index 000000000..b6a3ed1ef Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_axis_xy-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_binned-1.png b/content/blog/ggplot2-styling/figs/sub_legend_binned-1.png new file mode 100644 index 000000000..3a9f2b964 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_binned-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_colourbar-1.png b/content/blog/ggplot2-styling/figs/sub_legend_colourbar-1.png new file mode 100644 index 000000000..87231a811 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_colourbar-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_general-1.png b/content/blog/ggplot2-styling/figs/sub_legend_general-1.png new file mode 100644 index 000000000..9e4e2874c Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_general-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_guidebox-1.png b/content/blog/ggplot2-styling/figs/sub_legend_guidebox-1.png new file mode 100644 index 000000000..feee557ba Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_guidebox-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_guidebox_position-1.png b/content/blog/ggplot2-styling/figs/sub_legend_guidebox_position-1.png new file mode 100644 index 000000000..2fe381aac Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_guidebox_position-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_legend_legend-1.png b/content/blog/ggplot2-styling/figs/sub_legend_legend-1.png new file mode 100644 index 000000000..f9a648d2c Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_legend_legend-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_panel-1.png b/content/blog/ggplot2-styling/figs/sub_panel-1.png new file mode 100644 index 000000000..433fd7b78 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_panel-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_panel_border_background-1.png b/content/blog/ggplot2-styling/figs/sub_panel_border_background-1.png new file mode 100644 index 000000000..aaaa2ba56 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_panel_border_background-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_panel_size-1.png b/content/blog/ggplot2-styling/figs/sub_panel_size-1.png new file mode 100644 index 000000000..e7810b347 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_panel_size-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_plot-1.png b/content/blog/ggplot2-styling/figs/sub_plot-1.png new file mode 100644 index 000000000..0f64f44e1 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_plot-1.png differ diff --git a/content/blog/ggplot2-styling/figs/sub_strip-1.png b/content/blog/ggplot2-styling/figs/sub_strip-1.png new file mode 100644 index 000000000..260e637f1 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/sub_strip-1.png differ diff --git a/content/blog/ggplot2-styling/figs/theme_adding_parts-1.png b/content/blog/ggplot2-styling/figs/theme_adding_parts-1.png new file mode 100644 index 000000000..8d74c9ec3 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/theme_adding_parts-1.png differ diff --git a/content/blog/ggplot2-styling/figs/theme_caching-1.png b/content/blog/ggplot2-styling/figs/theme_caching-1.png new file mode 100644 index 000000000..4656029ac Binary files /dev/null and b/content/blog/ggplot2-styling/figs/theme_caching-1.png differ diff --git a/content/blog/ggplot2-styling/figs/theme_set-1.png b/content/blog/ggplot2-styling/figs/theme_set-1.png new file mode 100644 index 000000000..86025a786 Binary files /dev/null and b/content/blog/ggplot2-styling/figs/theme_set-1.png differ diff --git a/content/blog/ggplot2-styling/index.Rmd b/content/blog/ggplot2-styling/index.Rmd new file mode 100644 index 000000000..bfd80d886 --- /dev/null +++ b/content/blog/ggplot2-styling/index.Rmd @@ -0,0 +1,1141 @@ +--- +output: hugodown::md_document + +slug: ggplot2-styling +title: ggplot2 styling +date: 2025-01-10 +author: Teun van den Brand +description: > + A 2-3 sentence description of the post that appears on the articles page. + This can be omitted if it would just recapitulate the title. + +photo: + url: https://unsplash.com/photos/n6vS3xlnsCc + author: Kelley Bozarth + +# one of: "deep-dive", "learn", "package", "programming", "roundup", or "other" +categories: [package] +tags: [] +--- + + + +## So you want to style your plot? + +Diligently, you have read, cleaned and modelled your data. +You have carefully crafted a plot that lets your data speak its story. +Now it is time to polish. +Now it is time to let your visualisation shine. + +We will set out to illuminate how to set the stylistic finishing touches on your visualisations made with the ggplot2 package. +In ggplot2, the theme system is responsible for many non-data aspects of how your plot looks. +It covers anything from panels, to axes, titles and legends. +Here, we'll get started with digesting important parts of the theme system. +We'll start with complete themes, get into theme elements followed by how these elements are used in various parts of the plot and finish off with some tips, including how to write your own theme functions. +Before we begin discussing themes, let's make an example plot that can showcase many aspects. + +```{r, echo=FALSE} +knitr::opts_chunk$set(dev = "ragg_png") +``` + + +```{r base_plot} +library(ggplot2) + +p <- ggplot(mpg, aes(displ, hwy, colour = cty, shape = drv)) + + geom_point() + + facet_grid(~ year) + + labs( + title = "Fuel efficiency", + subtitle = paste0("Described for ", nrow(mpg), " cars from 1999 and 2008"), + caption = "Source: U.S. Environmental Protection Agency", + x = "Engine Displacement", + y = "Highway miles per gallon", + colour = "City miles\nper gallon", + shape = "Drive train" + ) + +p +``` + +## What is a theme? + +In ggplot, a theme is a list of descriptions for various parts of the plot. +It is where you can set the size of your titles, the colours of your panels, the thickness of your grid lines and placement of your legends. + +Themes are declared using the `theme()` function, which populates these descriptions called 'theme elements'. +Some of these elements have a predefined set of properties and can be set using the element functions, like `element_text()`. +Other theme elements can take simpler values like strings, numbers or units. + +Some pre-arranged collections of elements can be found in complete themes, like the iconic `theme_gray()`. +These are convenient ways to quickly swap out the complete look of a plot. + +## Complete themes + +Let's start big and work our way through the more nitty-gritty aspects of theming plots. +The most thorough way to change the styling of a single plot is to swap out the complete theme. +You can do this simply by adding one of the `theme_*()` functions, like `theme_minimal()`. + +```{r example_complete} +p + theme_minimal() +``` + +### Built-in themes + +The base ggplot2 package already comes with a series of 9 built-in complete themes. +For the sake of completeness about complete themes, they are displayed in the fold-out sections below. +You can peruse them at your leisure to help you pick one you might like. + +
+
+```{r complete_grey}
+p + theme_grey()
+```
+
+theme_grey()
(default)
+
+```{r complete_bw}
+p + theme_bw()
+```
+
+theme_bw()
+
+```{r complete_linedraw}
+p + theme_linedraw()
+```
+
+theme_linedraw()
+
+```{r complete_light}
+p + theme_light()
+```
+
+theme_light()
+
+```{r complete_dark}
+p + theme_dark()
+```
+
+theme_dark()
+
+```{r complete_minimal}
+p + theme_minimal()
+```
+
+theme_minimal()
+
+```{r complete_classic}
+p + theme_classic()
+```
+
+theme_classic()
+
+```{r complete_void}
+p + theme_void()
+```
+
+theme_void()
+
+```{r complete_test}
+p + theme_test()
+```
+
+theme_test()
+
+```{r complete_cowplot}
+p + cowplot::theme_cowplot()
+```
+
+cowplot::theme_cowplot()
+
+```{r complete_ggthemes}
+p + ggthemes::theme_fivethirtyeight()
+```
+
+ggthemes::theme_fivethirtyeight()
+
+```{r complete_tvthemes}
+p + tvthemes::theme_simpsons()
+```
+
+tvthemes::theme_simpsons()
library(ggplot2)
+
+p <- ggplot(mpg, aes(displ, hwy, colour = cty, shape = drv)) +
+ geom_point() +
+ facet_grid(~ year) +
+ labs(
+ title = "Fuel efficiency",
+ subtitle = paste0("Described for ", nrow(mpg), " cars from 1999 and 2008"),
+ caption = "Source: U.S. Environmental Protection Agency",
+ x = "Engine Displacement",
+ y = "Highway miles per gallon",
+ colour = "City miles\nper gallon",
+ shape = "Drive train"
+ )
+
+p
+
+p + theme_minimal()
+
+
+
+
+
+theme_grey()
(default)
+
+p + theme_grey()
+
+
+
+
+
+
+theme_bw()
+
+p + theme_bw()
+
+
+
+
+
+
+theme_linedraw()
+
+p + theme_linedraw()
+
+
+
+
+
+
+theme_light()
+
+p + theme_light()
+
+
+
+
+
+
+theme_dark()
+
+p + theme_dark()
+
+
+
+
+
+
+theme_minimal()
+
+p + theme_minimal()
+
+
+
+
+
+
+theme_classic()
+
+p + theme_classic()
+
+
+
+
+
+
+theme_void()
+
+p + theme_void()
+
+
+
+
+
+
+theme_test()
+
+p + theme_test()
+
+
+
+
+
+
+cowplot::theme_cowplot()
+
+p + cowplot::theme_cowplot()
+
+
+
+
+
+
+ggthemes::theme_fivethirtyeight()
+
+p + ggthemes::theme_fivethirtyeight()
+
+
+
+
+
+
+tvthemes::theme_simpsons()
+
+p + tvthemes::theme_simpsons()
+
+
+
p + theme_bw(base_size = 8)
+
+p + theme_bw(base_family = "Roboto", header_family = "Roboto Slab")
+
+p +
+ # Turning off these aesthetics to prevent grouping
+ aes(shape = NULL, colour = NULL) +
+ geom_smooth(method = "lm", formula = y ~ x) +
+ theme_bw(
+ ink = "#BBBBBB",
+ paper = "#333333",
+ accent = "red"
+ )
+
+red_line <- element_line(colour = "red", linewidth = 2)
+red_line
+#> <ggplot2::element_line>
+#> @ colour : chr "red"
+#> @ linewidth : num 2
+#> @ linetype : NULL
+#> @ lineend : NULL
+#> @ linejoin : NULL
+#> @ arrow : logi FALSE
+#> @ arrow.fill : chr "red"
+#> @ inherit.blank: logi FALSE
+
+
+p + theme(axis.line = red_line)
+
+p +
+ labs(title = "<b>Fuel</b> <i>efficiency</i>") +
+ theme(
+ plot.title = ggtext::element_markdown(),
+ strip.background = ggh4x::element_part_rect(colour = "black", side = "b")
+ )
+
+p + theme(
+ # A root element
+ text = element_text(colour = "red"),
+ # A leaf element
+ legend.text = element_text(family = "impact")
+)
+
+# Will inherit entirely from parent
+theme_gray()$axis.ticks.x.bottom
+#> NULL
+
+# The element is incomplete
+theme_gray()$axis.ticks
+#> <ggplot2::element_line>
+#> @ colour : chr "#333333FF"
+#> @ linewidth : NULL
+#> @ linetype : NULL
+#> @ lineend : NULL
+#> @ linejoin : NULL
+#> @ arrow : logi FALSE
+#> @ arrow.fill : chr "#333333FF"
+#> @ inherit.blank: logi TRUE
+
+# Proper way to access the properties of an element
+calc_element("axis.ticks.x.bottom", theme_gray())
+#> <ggplot2::element_line>
+#> @ colour : chr "#333333FF"
+#> @ linewidth : num 0.5
+#> @ linetype : num 1
+#> @ lineend : chr "butt"
+#> @ linejoin : chr "round"
+#> @ arrow : logi FALSE
+#> @ arrow.fill : chr "#333333FF"
+#> @ inherit.blank: logi TRUE
+
+
+tree <- get_element_tree()
+tree$axis.line.x.bottom$inherit
+#> [1] "axis.line.x"
+
+
+theme_sub_axis(title = element_blank())
+#> <theme> List of 1
+#> $ axis.title: <ggplot2::element_blank>
+#> @ complete: logi FALSE
+#> @ validate: logi TRUE
+
+
+p +
+ labs(tag = "A") +
+ theme_sub_plot(
+ # Adjust the background colour
+ background = element_rect(fill = "cornsilk"),
+
+ # Align title and subtitle to plot instead of panels
+ title = element_text(hjust = 0), # default,
+ subtitle = element_text(colour = "dodgerblue"),
+ title.position = "plot",
+
+ # Align caption to plot instead of panels
+ caption = element_text(hjust = 1), # default
+ caption.position = "plot",
+
+ # Place the tag in the top right of the panels instead of top left of plot
+ tag.position = "topright",
+ tag.location = "panel"
+ )
+
+p +
+ theme_sub_panel(
+ # Extra space between panels
+ spacing.x = unit(1, "cm"),
+
+ # Tweaking all the grid elements
+ grid = element_line(colour = "grey80"),
+
+ # Turning off the minor grid elements
+ grid.minor = element_blank(),
+
+ # Tweak the major x/y lines separately
+ grid.major.x = element_line(linetype = "dotted"),
+ grid.major.y = element_line(colour = "white")
+ )
+
+p +
+ theme_sub_panel(
+ background = element_rect(fill = "cornsilk", colour = "blue", linewidth = 6),
+ border = element_rect(colour = "red", linewidth = 3, fill = "black"),
+ )
+
+p +
+ theme_sub_panel(
+ widths = unit(c(3, 5), "cm"),
+ heights = unit(4, "cm")
+ )
+
+# We're including a labeller to showcase formatting
+my_labeller <- as_labeller(c(`1999` = "The Nineties", `2008` = "The Noughties",
+ V = "Vertical Strip"))
+p +
+ # Using a dummy strip for the vertical direction
+ facet_grid("V" ~ year, labeller = my_labeller, switch = "x") +
+ theme_sub_strip(
+ # All strip backgrounds
+ background = element_rect(fill = "cornsilk"),
+ # Specifically the horizontal strips
+ background.x = element_rect(colour = "black", linewidth = 1),
+ # Tweak text, specifically for the bottom strip
+ text.x.bottom = element_text(size = 16),
+
+ placement = "outside",
+ # Spacing in between axes and strips. Note that it doesn't affect the
+ # vertical strip that doesn't have an axis.
+ switch.pad.grid = unit(1, "cm"),
+ clip = "off"
+ )
+
+# Turn on all lines
+p + theme_sub_axis(line = element_line())
+
+p +
+ # Turn on horizontal line
+ theme_sub_axis_x(line = element_line()) +
+ # Turn off ticks for vertical
+ theme_sub_axis_y(ticks = element_blank())
+
+p +
+ # Extra axes
+ guides(x.sec = "axis", y.sec = "axis") +
+ # Turning off ticks
+ theme_sub_axis_bottom(ticks = element_blank()) +
+ # Extra long, coloured ticks
+ theme_sub_axis_top(
+ ticks.length = unit(5, "mm"),
+ ticks = element_line(colour = "red")
+ ) +
+ # Extra spacing
+ theme_sub_axis_left(text = element_text(margin = margin_auto(10))) +
+ # Turning on the axis line
+ theme_sub_axis_right(line = element_line())
+
+red_axis <- guide_axis(theme = theme_classic(ink = "red"))
+p + guides(x = red_axis)
+
+p +
+ theme_sub_legend(
+ # Showing the box
+ box.background = element_rect(fill = "cornsilk"),
+
+ # Put legends on the left
+ position = "left",
+
+ # Arrange legends horizontally
+ box = "horizontal",
+
+ # Align to legend box to top
+ justification = "top",
+ # location = "plot",
+ # But align legends within the box at the bottom
+ box.just = "bottom",
+
+ # Spacings and margins
+ box.margin = margin_auto(5),
+ box.spacing = unit(1, "cm")
+ )
+
+p +
+ guides(shape = guide_legend(position = "left")) +
+ theme_sub_legend(
+ # Showing the boxes
+ box.background = element_rect(fill = "cornsilk"),
+ box.margin = margin_auto(5),
+
+ # Tweaking the justification per position
+ justification.left = "top",
+ justification.right = "bottom"
+ )
+
+p +
+ theme_sub_legend(
+ # Give guides a wider background
+ background = element_rect(fill = "cornsilk"),
+ margin = margin_auto(5, unit = "mm"),
+
+ # Display legend titles to the right of the guide
+ title = element_text(angle = 270),
+ title.position = "right",
+
+ # Display red labels to the left of the keys
+ text = element_text(colour = "red"),
+ text.position = "left",
+
+ # Set smaller keys
+ key.width = unit(5, "mm"),
+ key.height = unit(5, "mm")
+ )
+
+p +
+ # Set two columns and long label text
+ scale_shape_discrete(
+ labels = c("4\nwheel\ndrive", "front\nwheel\ndrive", "rear\nwheel\ndrive"),
+ guide = guide_legend(ncol = 2)
+ ) +
+ theme_sub_legend(
+ # Fill items in grid in a row-wise fashion
+ byrow = TRUE,
+ # Increase spacing between keys
+ key.spacing.y = unit(5, "mm"),
+ key.spacing.x = unit(5, "mm"),
+ # Top-align keys with text
+ key.justification = "top"
+ )
+
+p +
+ # Using a local guide theme to directly set the size
+ guides(colour = guide_colourbar(theme = theme(legend.key.height = unit(5, "cm")))) +
+ theme_sub_legend(
+ frame = element_rect(colour = "red"),
+ # Long blue ticks
+ ticks = element_line(colour = "blue"),
+ ticks.length = unit(-5, "mm"),
+ # Adapt margins to accommodate longer ticks
+ text = element_text(margin = margin(l = 6, unit = "mm")),
+ margin = margin(l = 6, unit = "mm")
+ )
+
+p +
+ guides(colour = "bins") +
+ theme_sub_legend(
+ axis.line = element_line("red"),
+ ticks = element_line("blue")
+ )
+
+p +
+ # Turn off grouping
+ aes(colour = NULL, shape = NULL) +
+ geom_smooth(formula = y ~ x, method = "lm") +
+ theme(
+ geom = element_geom(
+ ink = "tomato",
+ paper = "dodgerblue",
+ accent = "forestgreen"
+ )
+ )
+
+element_geom()
+#> <ggplot2::element_geom>
+#> @ ink : NULL
+#> @ paper : NULL
+#> @ accent : NULL
+#> @ linewidth : NULL
+#> @ borderwidth: NULL
+#> @ linetype : NULL
+#> @ bordertype : NULL
+#> @ family : NULL
+#> @ fontsize : NULL
+#> @ pointsize : NULL
+#> @ pointshape : NULL
+#> @ colour : NULL
+#> @ fill : NULL
+
+
+last_plot() +
+ theme(geom = element_geom(
+ fill = "purple",
+ colour = "orange",
+ paper = "green" # Ignored
+ ))
+
+ggplot(faithful, aes(eruptions)) +
+ geom_histogram(aes(y = after_stat(density)), bins = 30, colour = "black") +
+ geom_line(stat = "density") +
+ theme(
+ geom = element_geom(
+ # Applies to the bars
+ borderwidth = 0.5,
+ bordertype = "dashed",
+ # Applies to the line
+ linewidth = 4,
+ linetype = "solid"
+ )
+ )
+
+ggplot(mtcars, aes(mpg, disp, label = rownames(mtcars))) +
+ geom_point() +
+ geom_label(nudge_x = 0.25, hjust = 0) +
+ theme(
+ geom = element_geom(
+ # Point settings
+ pointsize = 8,
+ pointshape = "←",
+
+ # Text settings
+ fontsize = 8,
+ family = "Ink Free"
+ )
+ )
+
+ggplot(mpg, aes(class, displ)) +
+ geom_boxplot(outliers = FALSE) +
+ geom_jitter() +
+ theme(
+ geom.point = element_geom(colour = "dodgerblue"),
+ geom.boxplot = element_geom(fill = "orchid", colour = "turquoise")
+ )
+
+p + aes(colour = from_theme(scales::col_darker(accent, 20)))
+
+p + theme(
+ palette.shape.discrete = c("plus", "triangle", "diamond"),
+ palette.colour.continuous = c("maroon", "hotpink", "white")
+)
+
+p + ggforce::facet_zoom(ylim = c(20, 30), xlim = c(3, 4)) +
+ theme(zoom = element_rect(colour = "red", linewidth = 0.2, fill = NA))
+
+# A custom element comes up empty
+calc_element("my_element", complete_theme())
+#> NULL
+
+# Register element
+register_theme_elements(
+ my_element = element_rect(),
+ element_tree = list(
+ my_element = el_def(
+ class = "element_rect", # Must be a rect element
+ inherit = "rect" # Get settings from theme(rect)
+ )
+ )
+)
+
+# Now custom element can be computed
+calc_element("my_element", complete_theme())
+#> <ggplot2::element_rect>
+#> @ fill : chr "white"
+#> @ colour : chr "black"
+#> @ linewidth : num 0.5
+#> @ linetype : num 1
+#> @ linejoin : chr "round"
+#> @ inherit.blank: logi TRUE
+
+
+my_theme <- function(...) {}
+
+my_theme <- function(...) {
+ theme_gray(...)
+}
+
+# Do *not* do the following!
+my_fragile_theme <- function(...) {
+ t <- theme_gray(...)
+ t$legend.text <- element_text() # BAD
+ t
+}
+
+my_theme <- function(...) {
+ theme_gray(...) %+replace%
+ theme(
+ # Because we're replacing, we should fully define root elements
+ text = element_text(
+ family = "", face = "plain", colour = "red", size = 11,
+ hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 1, margin = margin()
+ ),
+ # Non-root elements can be partially defined
+ legend.text = element_text(colour = "blue")
+ ) +
+ # Here we're updating the root line element with `+`, instead of replacing it
+ theme(line = element_line(linetype = "dotted"))
+}
+
+p + my_theme()
+
+# Create a variable for your future theme
+cached_theme <- NULL
+
+# In your .onLoad function, construct the theme
+.onLoad <- function(libname, pkgname) {
+ cached_theme <<- my_theme()
+}
+
+# In your package's functions, you can now use the cached theme
+my_plotting_function <- function() {
+ ggplot(mpg, aes(displ, hwy)) +
+ geom_point() +
+ cached_theme
+}
+
+# Simulate loading
+.onLoad()
+
+# Works!
+my_plotting_function()
+
+my_theme <- function(...) {
+ theme_gray() +
+ theme(
+ panel.background = element_blank(),
+ panel.grid = element_line(colour = "grey95"),
+ palette.colour.continuous = "viridis"
+ )
+}
+
+set_theme(my_theme())
+
+# Global goodness galore!
+p
+
+my_theme <- function(header_family = "Impact", ...) {
+ systemfonts::require_font(header_family)
+ theme_gray(header_family = header_family, ...)
+}
+
+p + my_theme()
+
+upper_legend <- function() {
+ theme(
+ plot.title.position = "plot",
+ legend.location = "plot",
+ legend.position = "top",
+ legend.justification.top = "left",
+ legend.title.position = "top",
+ legend.margin = margin_part(l = 0)
+ )
+}
+
+p +
+ aes(colour = NULL) +
+ upper_legend()
+
+bottom_colourbar <- function() {
+ theme_sub_legend(
+ position = "bottom",
+ title.position = "top",
+ justification.bottom = "left",
+ # Stretch bar across width of panels
+ key.width = unit(1, "null"),
+ margin = margin_part(l = 0, r = 0)
+ )
+}
+
+p +
+ aes(shape = NULL) +
+ bottom_colourbar()
+
+barchart_settings <- function() {
+ list(
+ theme(panel.grid.major.x = element_blank()),
+ coord_cartesian(expand = c(bottom = FALSE))
+ )
+}
+
+ggplot(mpg, aes(class)) +
+ geom_bar() +
+ barchart_settings()
+
+pattern <- "https://raw.githubusercontent.com/tidyverse/ggplot2/refs/heads/main/man/figures/logo.png" |>
+ magick::image_read() |>
+ grid::rasterGrob(
+ x = 0.8, y = 0.8,
+ width = unit(0.2, "snpc"),
+ height = unit(0.23, "snpc"),
+ ) |>
+ grid::pattern(extend = "none")
+
+p +
+ theme(
+ panel.background = element_rect(fill = pattern),
+ # legend.key inherits from panel background, so we tweak it
+ legend.key = element_blank(),
+ # make grid semitransparent to lay over pattern
+ panel.grid = element_line(colour = alpha("black", 0.05))
+ )
+
+