Better ggploting

Michael Jones

Why (when to) put the effort in?

  • Who is your target audience?
  • What are you trying to achieve?
  • Where will your graph be published?

Successful Graphs — BBC

Successful Graphs — (John Burn-Murdoch (FT)

The Rainbow Scale

ggplot default

viridis

{colorblindr}

  • Package from Claus Wilke
  • available on github
  • cvd_grid() to test your plots

Colour Blind Discrete Scale

Okabe-Ito Scale. (Okabe, M. and K. Ito, 2008 “Color Universal Design (CUD): How to make Figures and Presentations That Are Friendly To Colorblind People”)

Colour Blind Discrete Scale

ggplot refresher

plots are built in layers

ggplot(data, aes(x = column1)) + # sets up the plot, global aesthetic
  geom_point(aes(y = column2)) + # adds a point layer
  geom_line(aes(y = column3))    # adds a line layer

Smaller parts contribute to a larger whole.

Like code built of functions (or a lego house made of smaller pieces).

data, geom, aes..

  • All plots start with a data.frame of data to plot
  • We map columns in the data to aesthetic features, e.g. x position, y position, colour, shape, texture using mapping = aes().
  • We add geometries and stat layers using geom_*() and stat_*() functions.
  • geoms and stats use what aesthetic mappings have been provided to map the data to their respective domains.
  • Further layers are things like themes, titles, scales.

themes

themes

themes {ggthemes}

themes {bbplot}

bbplot R package

deeper into scales

gg_basic <- ggplot(iris |> mutate(sepal_2 = Sepal.Width * 1e6),
                   aes(x = sepal_2, y = Petal.Length,
                             colour = Species)) + 
  geom_point()
gg_basic

deeper into scales

gg_basic + 
  scale_x_continuous(
    labels = scales::comma
  )

deeper into scales

gg_basic + 
  scale_x_continuous(
    labels = scales::comma_format(suffix="m",scale = 1e-6)
  )

deeper into scales

labeller <- function(x) {
  if_else(x <= 3e6, "Small", "Large")
}

gg_basic + 
  scale_x_continuous(
    labels = labeller
  )

titles (sub, title, caption, etc)

gg_basic +
  labs(title = "As Sepal Width Grows, so does Petal Length",
       subtitle = "Data based on the iris dataset",
       caption = "Source: Base R")

Building layers

  • Complex graphs can be made of smaller pieces
  • Identify common plotting elements, e.g.
    • points, rectangles/areas
  • Identify aesthetic mappings
  • Think about what data you (would) need.

Example: Bullet Graphs

  • Current value
  • Target/comparison value
  • regions with qualitative value

Building layers

bullet_data <- tribble(
  ~category,     ~current,     ~target,
  "A",               95,        110,
  "B",              120,         90,
  "C",              110,        105
)

Building layers

bullet_data |>
  pivot_longer(cols = -category) |>
  ggplot(aes(x = value, colour = name, y = category)) + 
  geom_point()

Building layers

bullet_data |>
  ggplot(aes(y = category)) +
  geom_col(aes(x = current), width = 0.2, fill = "black") +
  geom_point(aes(x = target), pch = 18, size = 14,
             colour = palette_OkabeIto[2])

Building Layers

regions <- tribble(
  ~label,    ~value,
  "Good",     125,
  "Adequate", 100,
  "Poor",     75
)

Building Layers

regions_expand <- expand_grid(
  regions = regions, 
  category = bullet_data$category) |>
  unnest(regions)


g <- bullet_data |>
  ggplot(aes(y = category)) +
  geom_col(data = regions_expand,
           aes(x = value, fill = label, y = category),
           position = position_identity(),
           width = 0.6) + 
  geom_col(aes(x = current), width = 0.2, fill = "black") +
  geom_point(aes(x = target), pch = 18, size = 14, colour = palette_OkabeIto[2]) +
  scale_fill_manual(
    values = list(
      "Poor" = "grey40",
      "Adequate" = "grey60",
      "Good" = "grey90"
    )
  ) +
  theme_minimal() +
  theme(legend.position = "none")

Building layers

direct labels

library(gapminder)
gapminder |>
  group_by(continent, year) |>
  summarise(pop = sum(pop),
            .groups = "drop") |>
  ggplot(aes(x = year,
             y = pop,
             colour = continent)) +
  geom_line()

direct labels

direct labels

gapminder |>
  group_by(continent, year) |>
  summarise(pop = sum(pop)) |>
  mutate(label = if_else(year == max(year),
                         continent,
                         "")) |>
  ggplot(aes(x = year,
             y = pop,
             colour = continent,
             label = label)) +
  geom_line() +
  geom_text(hjust = 0) +
  scale_x_continuous(expand = expansion(mult = c(0.1, 0.2))) +
  theme(legend.position = "none")

direct labels

direct labels

gapminder |>
  group_by(continent, year) |>
  summarise(pop = sum(pop)) |>
  mutate(label = if_else(year == max(year),
                         continent,
                         "")) |>
  ggplot(aes(x = year,
             y = pop,
             colour = continent,
             label = label)) +
  geom_line() +
  ggrepel::geom_text_repel(hjust = 0, direction = "y") +
  scale_x_continuous(expand = expansion(mult = c(0.1, 0.2))) +
  theme(legend.position = "none")

direct labels

annotations

penguins |>
  ggplot(aes(x = bill_length_mm,
             y = bill_depth_mm,
             colour = species)) +
  geom_point() +
  annotate("segment",
           x = 55, y = 14,
           xend = 59.4, yend = 16.9,
           arrow = arrow(type = "closed",
                         length = unit(2, "mm"),
                         ends = "last")) +
  annotate("text", x = 55, y = 13.8,
           label = "Long bill Steve")

annotations

ggtext to remove legend

ggplot(penguins,
       aes(x = bill_length_mm,
           y = flipper_length_mm,
           colour = species)) +
  geom_point() +
  scale_colour_OkabeIto()

ggtext to remove legend

library(ggtext)
library(glue)

ggplot(penguins,
       aes(x = bill_length_mm,
           y = flipper_length_mm,
           colour = species)) +
  geom_point() +
  scale_colour_OkabeIto() +
  labs(title = "Bill length vs Flipper length (mm)", 
       subtitle = glue("<span style = 'color:{palette_OkabeIto[1]}'>
Adelie</span> penguins tend to be saller, 
<span style = 'color:{palette_OkabeIto[2]}'>Chinstrap</span> penguins 
have similar flippers,<br>but larger bills. 
<span style = 'color:{palette_OkabeIto[3]}'>Gentoos</span> have 
larger flippers.")) +
  theme(plot.subtitle = element_markdown()) +
  theme(legend.position = "none")

ggtext to remove legend

Themes

gg_basic

Themes

gg_basic + theme(legend.position = "bottom",
                 panel.background = element_blank(),
                 panel.grid = element_line(colour = "grey95"),
                 axis.line = element_line(colour = "black"))

Themes

my_theme <- function() {
  theme_gray() %+replace%
    theme(legend.position = "bottom",
                 panel.background = element_blank(),
                 panel.grid = element_line(colour = "grey95"),
                 axis.line = element_line(colour = "black"))
}

Themes

gg_basic +
  my_theme()

Reproducing a BBC graphic

Reproducing a BBC graphic

set.seed(123)
plot_data <- tibble(draws = rnorm(100, 0, 5) |> floor()) |>
  group_by(draws) |>
  mutate(y = 1:n())

plot_data |> head(n = 5)
# A tibble: 5 × 2
# Groups:   draws [4]
  draws     y
  <dbl> <int>
1    -3     1
2    -2     1
3     7     1
4     0     1
5     0     2

Reproducing a BBC graphic

plot_data |>
  ggplot(aes(x = draws, y = y)) +
  geom_point()

Reproducing a BBC graphic

plot_data |>
  ggplot(aes(x = draws, y = y)) +
  geom_tile(colour = "white", 
            fill = palette_OkabeIto[2])

Reproducing a BBC graphic

plot_data |>
  ggplot(aes(x = draws, y = y)) +
  geom_tile(colour = "white", 
            fill = palette_OkabeIto[2],
            size = 0.6) +
  bbc_style()

Reproducing a BBC graphic

plot_data |>
  ggplot(aes(x = draws, y = y)) +
  geom_tile(colour = "white", 
            fill = palette_OkabeIto[2],
            size = 0.8) +
  bbc_style() +
  annotate("tile", x = 2, y = 9, fill = NA, colour = "grey20", size = 2)

Practice and Resources

Tidy Tuesday

  • Weekly data sets
  • Model or just visualise
  • Good for practice
  • Share online: #tidytuesday #rstats

Claus Wilke’s book

https://clauswilke.com/dataviz/

Alberto Cairo’s books

http://albertocairo.com/

Tufte

https://www.edwardtufte.com/tufte/