Skip to contents

Standardise the width in 'ggplot2' geoms to appear visually consistent across plots with different numbers of categories, panel dimensions, and orientations.

This can be used in geoms such as ggplot2::geom_bar()/ggplot2::geom_col(), ggplot2::geom_boxplot(), ggplot2::geom_errorbar().

Usage

get_width(
  ...,
  n = NULL,
  n_dodge = NULL,
  orientation = c("x", "y"),
  equiwidth = NULL,
  panel_widths = NULL,
  panel_heights = NULL
)

Arguments

...

Must be empty. Forces all other arguments to be named and allows trailing commas.

n

Number of categories in the orientation aesthetic (i.e. "x" or "y"). For faceted plots, use the maximum n within a facet.

n_dodge

Number of dodge categories. Must match the number of groups in the fill or colour aesthetic when using position_dodge().

orientation

Orientation: "x" for vertical (width appearance equiwidth to panel width), "y" for horizontal (width appearance equiwidth to panel height).

equiwidth

Numeric. Scaling factor that controls the width appearance. A value of 1 is the default. Increase to make a wider appearance, and decrease to make a thinner appearance. If NULL, uses the value set by set_equiwidth(), falling back to 1.

panel_widths

A grid::unit object specifying the panel width. If NULL (default), uses the value set in the current theme.

panel_heights

A grid::unit object specifying the panel height. If NULL (default), uses the value set in the current theme.

Value

A numeric width value passed to the width argument of geom_bar(), geom_col(), or similar geoms.

See also

Examples

library(ggplot2)
library(dplyr)
#> 
#> Attaching package: ‘dplyr’
#> The following objects are masked from ‘package:stats’:
#> 
#>     filter, lag
#> The following objects are masked from ‘package:base’:
#> 
#>     intersect, setdiff, setequal, union
library(patchwork)

set_theme(
  theme_grey() +
    theme(panel.widths  = rep(unit(75, "mm"), 2)) +
    theme(panel.heights = rep(unit(50, "mm"), 2))
)
set_equiwidth(1)

p1 <- mpg |>
  ggplot(aes(x = drv)) +
  geom_bar(
    width = get_width(n = 3),
    colour = "black",
    fill = "grey",
  )

p2 <- diamonds |>
  ggplot(aes(x = color)) +
  geom_bar(
    width = get_width(n = 7),
    colour = "black",
    fill = "grey",
  )

p3 <- diamonds |>
  ggplot(aes(y = color)) +
  geom_bar(
    width = get_width(n = 7, orientation = "y"),
    colour = "black",
    fill = "grey",
  )

p4 <- mpg |>
  ggplot(aes(x = drv, group = factor(cyl))) +
  geom_bar(
    position = position_dodge(preserve = "single"),
    width = get_width(n = 3, n_dodge = 4),
    colour = "black",
    fill = "grey",
  )

p1 + p2 + p3 + p4


d <- tibble::tibble(
  continent = c("Europe", "Europe", "Europe", "Europe", "Europe",
                "South America", "South America"),
  country   = c("AT", "DE", "DK", "ES", "PK", "TW", "BR"),
  value     = c(10L, 15L, 20L, 25L, 17L, 13L, 5L)
)

max_n <- d |>
  count(continent) |>
  pull(n) |>
  max()

d |>
  mutate(country = forcats::fct_rev(country)) |>
  ggplot(aes(y = country, x = value)) +
  geom_col(
    width = get_width(n = max_n, orientation = "y"),
    colour = "black",
    fill = "grey",
  ) +
  facet_wrap(~continent, scales = "free_y") +
  scale_y_discrete(continuous.limits = c(1, max_n)) +
  coord_cartesian(reverse = "y", clip = "off")


mpg |>
  ggplot(aes(x = drv)) +
  geom_bar(
    width = get_width(n = 3, panel_widths = unit(160, "mm")),
    colour = "black",
    fill = "grey",
  ) +
  theme(panel.widths = unit(160, "mm"))