Overview
This article will demonstrate a random assortment of content, including some of which is quite advanced.
- Change the
stat
of the layer - Change the
position
of the layer - Use
+ *_mode_*
where axis-lines and gridlines are not as wanted - Reorder and/or reverse categorical variables
- Drop unused categorical variable values
- Transform scales to
"log"
etc - Change the
*_position
of positional axes - Add contrasting dark or light text on polygons
- Use opacity with to emphasise/demphasise.
- Use
replace_seq
to keep every nth label - Understand
oob
&clip
- Use delayed evaluation
library(ggplot2)
library(dplyr)
library(tidyr)
library(forcats)
library(stringr)
library(ggblanket)
library(palmerpenguins)
library(patchwork)
set_blanket()
1. Change the stat
of the layer
The default stat
of each gg_*
function can
be changed.
penguins |>
gg_pointrange(
stat = "summary",
x = species,
y = flipper_length_mm,
)
library(ggforce)
ggplot2::economics |>
slice_head(n = 35) |>
gg_path(
stat = "bspline", n = 100,
x = date,
y = unemploy,
linewidth = 1,
)
2. Change the position
of the layer
The default position
of each gg_*
function
can be changed.
penguins |>
gg_point(
position = ggbeeswarm::position_quasirandom(),
x = sex,
y = flipper_length_mm,
col = sex,
mode = light_mode_n(),
)
3. Use + *_mode_*
where axis-lines and gridlines are
not as wanted
Sometimes the plot might guess the removal of gridlines and
axis-line/ticks incorrectly. In these situations, you can
+ *_mode_*
on to the plot, and then remove whatever you
want.
msleep |>
gg_point(
x = bodywt,
y = brainwt,
col = vore,
col_labels = str_to_sentence,
x_transform = "log10",
y_transform = "log10",
) +
light_mode_r() +
guides(
x = guide_axis_logticks(),
y = guide_axis_logticks(),
)
4. Reorder and/or reverse categorical variables
ggblanket requires unquoted variables only for x
,
y
, col
, facet
,
facet2
and alpha
. You can often manipulate the
data prior to plotting to achieve what you want (e.g. using
tidyr::drop_na
, forcats::fct_rev
and/or
forcats::fct_reorder
).
p1 <- diamonds |>
count(color) |>
gg_col(
x = n,
y = color,
width = 0.75,
x_labels = \(x) x / 1000,
x_title = "Count (thousands)",
subtitle = "\nDefault order"
)
p2 <- diamonds |>
count(color) |>
mutate(across(color, \(x) x |>
forcats::fct_reorder(n) |>
forcats::fct_rev())) |>
gg_col(
x = n,
y = color,
width = 0.75,
x_labels = \(x) x / 1000,
x_title = "Count (thousands)",
subtitle = "\nRe-orderered"
)
p1 + p2
5. Drop unused categorical variable values
ggblanket keeps unused factor levels in the plot. If users wish to
drop unused levels they should likewise do it in the data prior to
plotting using forcats::fct_drop
.
p1 <- diamonds |>
count(color) |>
filter(color %in% c("E", "G", "I")) |>
gg_col(
x = n,
y = color,
width = 0.75,
x_labels = \(x) x / 1000,
x_title = "Count (thousands)",
subtitle = "\nUnused levels kept",
)
p2 <- diamonds |>
count(color) |>
filter(color %in% c("E", "G", "I")) |>
mutate(color = forcats::fct_drop(color)) |>
gg_col(
x = n,
y = color,
width = 0.75,
x_labels = \(x) x / 1000,
x_title = "Count (thousands)",
subtitle = "\nUnused levels dropped",
)
p1 + p2
6. Transform scales to "log"
etc
Transform objects (e.g. scales::transform_log()
or
character strings of these can be used to transform scales - including
combining these.
p1 <- pressure |>
gg_point(
x = temperature,
y = pressure,
x_labels = replace_seq,
y_labels = replace_seq,
subtitle = "\nDefault",
)
p2 <- pressure |>
gg_point(
x = temperature,
y = pressure,
x_labels = replace_seq,
y_transform = "reverse",
y_labels = replace_seq,
subtitle = "\nReverse",
)
p3 <- pressure |>
gg_point(
x = temperature,
y = pressure,
x_labels = replace_seq,
y_transform = "log10",
subtitle = "\nLog10",
)
p4 <- pressure |>
gg_point(
x = temperature,
y = pressure,
x_labels = replace_seq,
y_transform = c("log10", "reverse"),
subtitle = "\nLog10 & Reverse",
)
(p1 + p2) / (p3 + p4)
7. Change the *_position
of positional axes
Positional axes can be changed using *_position
.
Note that for x_position = "top"
, a caption must be
added or modified to make this work nicely with a *_mode_*
theme.
economics |>
gg_line(
x = date,
y = unemploy,
col = date,
y_position = "right",
x_position = "top",
caption = "",
title = "Unemployment",
subtitle = "1967\u20132015",
)
8. Add contrasting dark or light text on polygons
Text on polygons can be coloured with a dark or light colour that is
determined based on the underlying polygon colour using
!!!aes_contrast_mode()
. This method was developed by Teun
van den Brand (@teunbrand).
penguins |>
count(species, sex) |>
gg_col(
x = sex,
y = n,
col = species,
label = n,
position = position_dodge2(preserve = "single"),
width = 0.75,
x_labels = \(x) str_to_sentence(x),
) +
geom_text(
mapping = aes_contrast(),
# mapping = aes(!!!aes_contrast()),
position = position_dodge2(width = 0.75, preserve = "single"),
vjust = 1.33,
show.legend = FALSE,
)
penguins |>
count(species, sex) |>
gg_col(
position = position_dodge2(preserve = "single"),
x = n,
y = sex,
col = species,
label = n,
width = 0.75,
y_labels = \(x) str_to_sentence(x),
mode = dark_mode_r(),
) +
geom_text(
mapping = aes_contrast("dark"),
# mapping = aes(!!!aes_contrast("dark")),
position = position_dodge2(width = 0.75, preserve = "single"),
hjust = 1.25,
show.legend = FALSE,
)
9. Use opacity to emphasise/demphasise
Use opacity with mapping = aes(alpha = ...)
,
col = ...
, and col_palette
to
emphasise/demphasise parts of the visualisation.
p1 <- penguins |>
drop_na(sex) |>
mutate(across(sex, str_to_sentence)) |>
gg_density(
x = flipper_length_mm,
x_breaks = scales::breaks_pretty(n = 3),
y_labels = replace_seq,
colour = scales::alpha(orange, 0.33),
fill = orange,
alpha = 0.1,
subtitle = "\nOpacity fill 0.1 & outline 0.33"
)
p2 <- penguins |>
drop_na(sex) |>
mutate(across(sex, str_to_sentence)) |>
gg_density(
x = flipper_length_mm,
col = sex,
x_breaks = scales::breaks_pretty(n = 3),
y_labels = replace_seq,
col_palette = c(orange, "#78909C"),
subtitle = "\ncol variable"
)
p3 <- penguins |>
drop_na(sex) |>
mutate(across(sex, str_to_sentence)) |>
gg_density(
x = flipper_length_mm,
col = sex,
mapping = aes(alpha = sex),
x_breaks = scales::breaks_pretty(n = 3),
y_labels = replace_seq,
col_palette = c(orange, "#78909C"),
subtitle = "\ncol and alpha variable",
) +
guides(colour = "none", fill = "none", alpha = "none") +
scale_alpha_manual(values = c(0.5, 0.1))
p4 <- penguins |>
drop_na(sex) |>
mutate(across(sex, str_to_sentence)) |>
gg_density(
x = flipper_length_mm,
col = sex,
mapping = aes(alpha = sex),
x_breaks = scales::breaks_pretty(n = 3),
y_labels = replace_seq,
col_palette = c(orange, scales::alpha("#78909C", 0.25)),
subtitle = "\ncol and alpha variable & outline opacity",
) +
scale_alpha_manual(values = c(0.5, 0.1))
(p1 + p2) / (p3 + p4)
10. Use replace_seq
to keep every nth label
A replace_seq
helper function is provided to replace a
sequence of labels with ""
.
penguins |>
gg_point(
x = flipper_length_mm,
y = body_mass_g,
col = bill_length_mm,
x_labels = replace_seq,
y_labels = replace_seq,
col_steps = TRUE,
col_breaks = scales::breaks_pretty(5),
col_labels = replace_seq,
)
11. Understand oob
& clip
By default, ggblanket keeps values outside of the limits
(*_oob = scales::oob_keep
) in calculating the geoms and
scales to plot. It also does not clip anything outside the
cartesian coordinate space by default
(coord = ggplot2::coord_cartesian(clip = "off"
)).
ggplot2 by default drops values outside of the limits in calculating
the geoms and scales to plot (scales::oob_censor
), and
clips anything outside the cartesian coordinate space
(coord = ggplot2::coord_cartesian(clip = "on"
)).
This needs to be considered particularly when you are using
x_limits
or y_limits
, and your
stat
is not "identity"
.
p1 <- economics |>
gg_smooth(
x = date,
y = unemploy,
x_labels = \(x) stringr::str_sub(x, 3, 4),
subtitle = "\nNo x_limits set",
se = TRUE) +
geom_vline(xintercept = c(lubridate::ymd("1985-01-01", "1995-01-01"))) +
geom_point(alpha = 0.3)
p2 <- economics |>
filter(between(date, lubridate::ymd("1985-01-01"), lubridate::ymd("1995-01-01"))) |>
gg_smooth(
x = date,
y = unemploy,
se = TRUE,
x_labels = \(x) stringr::str_sub(x, 3, 4),
subtitle = "\nx data filtered") +
geom_point(alpha = 0.3)
p1 + p2
p3 <- economics |>
gg_smooth(
x = date,
y = unemploy,
se = TRUE,
x_limits = c(lubridate::ymd("1985-01-01", "1995-01-01")),
x_labels = \(x) stringr::str_sub(x, 3, 4),
subtitle = "\nx_limits set (with default oob_keep)",
) +
geom_point(alpha = 0.3)
p3 + plot_spacer()
p4 <- economics |>
gg_smooth(
coord = coord_cartesian(clip = "on"),
x = date,
y = unemploy,
se = TRUE,
x_limits = c(lubridate::ymd("1985-01-01", "1995-01-01")),
x_labels = \(x) stringr::str_sub(x, 3, 4),
subtitle = "\nx_limits set (with default oob_keep)\n& cartesian space clipped") +
geom_point(alpha = 0.3)
p5 <- economics |>
gg_smooth(
x = date,
y = unemploy,
se = TRUE,
x_limits = c(lubridate::ymd("1985-01-01", "1995-01-01")),
x_labels = \(x) stringr::str_sub(x, 3, 4),
x_oob = scales::oob_censor,
subtitle = "\nx_limits set & oob_censor") +
geom_point(alpha = 0.3)
p4 + p5
12. Use delayed evaluation
As the x
, y
, and col
aesthetic
arguments require a unquoted variable, you cannot apply a function to
these. However, you can for aesthetics within the mapping
argument. This can be used for delayed evaluation with the
ggplot2::after_stat
function.
penguins |>
gg_histogram(
x = flipper_length_mm,
mapping = aes(y = after_stat(density)),
facet = species,
)
faithfuld |>
gg_contour(
x = waiting,
y = eruptions,
z = density,
mapping = aes(colour = after_stat(level)),
bins = 8,
)