Skip to contents

Overview

This article will demonstrate a random assortment of content, including some of which is more advanced.

  1. Change the stat of the layer
  2. Change the position of the layer
  3. Use + *_mode_* where axis-lines and gridlines are not as wanted
  4. Reorder and/or reverse categorical variables
  5. Drop unused categorical variable values
  6. Transform scales to "log" etc
  7. Correct the default orientation
  8. Avoid the ‘symmetric’ scale
  9. Avoid the mode side-effects
  10. Change the *_position of positional axes
  11. Use opacity with to emphasise/de-emphasise
  12. Zoom in or out on scales
  13. Use delayed evaluation
  14. Rescale a diverging col scale
  15. Add a legend within the panel
library(dplyr)
library(tidyr)
library(forcats)
library(stringr)
library(ggplot2)
library(scales)
library(ggblanket)
library(patchwork)
library(palmerpenguins)

set_blanket()

penguins2 <- penguins |> 
  labelled::set_variable_labels(
    bill_length_mm = "Bill length (mm)",
    bill_depth_mm = "Bill depth (mm)",
    flipper_length_mm = "Flipper length (mm)",
    body_mass_g = "Body mass (g)",
  ) |> 
  mutate(sex = factor(sex, labels = c("Female", "Male")))

1. Change the stat of the layer

The default stat of each gg_* function can be changed.

penguins2 |>
  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,
    y_label = "Unemployment",
    linewidth = 1,
  ) 

2. Change the position of the layer

The default position of each gg_* function can be changed.

penguins2 |> 
  gg_point(
    position = ggbeeswarm::position_quasirandom(),
    x = sex, 
    y = flipper_length_mm,
    col = sex,
  ) +
  theme(legend.position = "none")

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_label = "Count (thousands)", 
    subtitle = "\nDefault order"
  )

p2 <- diamonds |>
  count(color) |>
  mutate(color = fct_rev(fct_reorder(color, n))) |>
  gg_col(
    x = n,
    y = color,
    width = 0.75,
    x_labels = \(x) x / 1000,
    x_label = "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_label = "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_label = "Count (thousands)", 
    subtitle = "\nUnused levels dropped",
  )

p1 + p2

6. Transform scales to "log" etc

Transform objects (e.g. 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_breaks_n = 4,
    y_breaks_n = 4,
    subtitle = "\nDefault",
  )

p2 <- pressure |>
  gg_point(
    x = temperature, 
    y = pressure, 
    x_breaks_n = 4,
    y_breaks_n = 4,
    y_transform = "reverse", 
    subtitle = "\nReverse",
  )

p3 <- pressure |>
  gg_point(
    x = temperature, 
    y = pressure,
    x_breaks_n = 4,
    y_breaks_n = 4,
    y_transform = "sqrt",
    subtitle = "\nSqrt", 
  )

p4 <- pressure |>
  gg_point(
    x = temperature, 
    y = pressure, 
    x_breaks_n = 4,
    y_breaks_n = 4,
    y_transform = c("sqrt", "reverse"),
    subtitle = "\nSqrt & Reverse",
  )

(p1 + p2) / (p3 + p4)

7. Correct the default orientation

The gg_* function guesses the *_orientation of the plot to determine how to make continuous axes and what side-effects to have on the provided mode. If it guesses incorrectly, use either the x_orientation or y_orientation argument.

p1 <- penguins2 |>
  gg_point(
    x = bill_depth_mm,
    y = bill_length_mm,
    subtitle = "\nDefault orientation",
  )

p2 <- penguins2 |>
  gg_point(
    x = bill_depth_mm,
    y = bill_length_mm,
    y_orientation = TRUE,
    subtitle = "\nCorrected orientation",
  ) 

p1 + p2

8. Avoid the ‘symmetric’ scale

Symmetric scales can be turned off or on using *_symmetric arguments.

p1 <- penguins2 |>
  gg_pointrange(
    x = sex,
    y = bill_length_mm,
    stat = "summary",
    position = position_dodge(),
    x_labels = \(x) str_sub(x, 1, 1),
    subtitle = "\ny_symmetric = NULL",
  ) +
  labs(y = NULL)

p2 <- penguins2 |>
  gg_pointrange(
    x = sex,
    y = bill_length_mm,
    stat = "summary",
    position = position_dodge(),
    x_labels = \(x) str_sub(x, 1, 1),
    y_symmetric = FALSE,
    subtitle = "\ny_symmetric = FALSE,",
  ) +
  labs(y = NULL)

p3 <- penguins2 |>
  gg_col(
    x = sex,
    y = bill_length_mm,
    stat = "summary",
    position = position_dodge(),
    width = 0.5,
    x_labels = \(x) str_sub(x, 1, 1),
    y_symmetric = FALSE,
    subtitle = "\ny_symmetric = FALSE,",
  ) +
  labs(y = NULL)

p1 + p2 + p3

9. Avoid the mode side-effects

Where *_orientation = TRUE, it will remove the relevant axis line/ticks and the gridlines from the mode theme.

But you can avoid this by +-ing your theme on to the plot, instead of adding it to the mode argument.

p1 <- penguins2 |>
  gg_jitter(
    x = sex,
    y = bill_depth_mm,
    subtitle = "\nmode = light_more_r()",
  )

p2 <- penguins2 |>
  gg_jitter(
    x = sex,
    y = bill_depth_mm,
    subtitle = "\n+ light_more_r()",
  ) +
  light_mode_r()

p1 + p2

10. 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",
  ) 

11. Use opacity to emphasise/de-emphasise

Use opacity with mapping = aes(alpha = ...), col = ..., and col_palette to emphasise/de-emphasise parts of the visualisation.

p1 <- penguins2 |> 
  drop_na(sex) |> 
  gg_density(
    x = flipper_length_mm,
    x_breaks_n = 4,
    y_breaks_n = 4,
    colour = alpha(orange, 0.33),
    fill = orange,
    alpha = 0.1,
    subtitle = "\nOpacity fill 0.1 & outline 0.33"
  )

p2 <- penguins2 |> 
  drop_na(sex) |> 
  gg_density(
    x = flipper_length_mm,
    col = sex,
    x_breaks_n = 4,
    y_breaks_n = 4,
    col_palette = c(orange, "#78909C"),
    subtitle = "\ncol variable"
  )

p3 <- penguins2 |> 
  drop_na(sex) |> 
  gg_density(
    x = flipper_length_mm,
    col = sex, 
    mapping = aes(alpha = sex),
    x_breaks_n = 4,
    y_breaks_n = 4,
    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 <- penguins2 |> 
  drop_na(sex) |> 
  gg_density(
    x = flipper_length_mm,
    col = sex, 
    mapping = aes(alpha = sex),
    x_breaks_n = 4,
    y_breaks_n = 4,
    col_palette = c(orange, alpha("#78909C", 0.25)),
    subtitle = "\ncol and alpha variable & outline opacity",
  ) +
  scale_alpha_manual(values = c(0.5, 0.1))

(p1 + p2) / (p3 + p4)

12. Zoom in or out on scales

There are no *_limits arguments in ggblanket.

Instead, users should use a combination of filtering the data, adding *_expand_limits and coord = coord_cartesian(xlim = ..., ylim = ...) arguments etc.

#To Zoom out, se *_expand_limits:
penguins |>
  gg_smooth(
    x =  body_mass_g, 
    y = bill_depth_mm,
    x_expand_limits = c(0),
    y_expand_limits = c(10, 25),
  ) 

#To zoom-in when the stat equals "identity", use dplyr::filter
penguins |>
  filter(bill_depth_mm < 15) |>
  gg_point(
    x =  bill_depth_mm, 
    y = body_mass_g,
  ) 

#To zoom-in when the stat does _not_ equal "identity", use coord_cartesian 
#Then either recreate the breaks, or turn off the symmetric axis 
penguins |>
  gg_smooth(
    x =  body_mass_g, 
    y = bill_depth_mm,
    coord = coord_cartesian(ylim = c(14.8, 15)), 
    y_breaks = scales::breaks_width(0.05),
    # y_symmetric = FALSE,
  ) 

13. Use delayed evaluation

The mapping argument can be used for delayed evaluation with the ggplot2::after_stat function.

penguins2 |>
  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,
  )

14. Rescale a diverging col scale

Use col_rescale to rescale a diverging scale around a central point.

rescale_vctr <- sort(c(range(mpg$cty), 15))

mpg  |>  
  gg_point(
    x = displ, 
    y = hwy, 
    col = cty,
    col_palette = c(navy, teal, "white", orange, red),
    col_rescale = scales::rescale(rescale_vctr),
    col_breaks = scales::breaks_width(5),
    mode = dark_mode_r(),
  )

15. Add a legend within the panel

set_blanket()

penguins2 |> 
  gg_histogram(
    x = flipper_length_mm,
    col = species,
    mode = light_mode_r(),
  ) +
  theme(legend.position = "inside") +
  theme(legend.position.inside = c(1, 0.975)) +
  theme(legend.justification = c(1, 1))