Skip to contents

Checks a figure as it will be submitted, rather than the palette it was built from. palette_safety() can promise that the eight colours depictr ships stay apart under colour-vision deficiency, but it knows nothing about the figure in front of you: how many of those colours it uses, what you replaced them with, how small the text will be once the figure is squeezed into a journal column, or whether the only thing separating two groups is their colour. check_figure() reads the built plot and answers those questions with numbers.

Usage

check_figure(
  plot,
  width_cm = 17.78,
  render_width_cm = 17.78,
  min_delta_e = 5,
  min_text_pt = 6
)

Arguments

plot

A plot, as returned by any depictr plotting function, including one extended afterwards with +. A multi-panel composite is refused: its panels have their own scales, themes and text, and one table of numbers cannot describe them all. Check each panel on its own.

width_cm

The width, in centimetres, that the figure will occupy in the finished document. Defaults to 17.78 cm, the seven inches save_plot() draws at, which means no scaling.

render_width_cm

The width, in centimetres, that the figure is drawn at. Defaults to the same 17.78 cm. The ratio of the two widths is the factor every point size is multiplied by.

min_delta_e

The smallest acceptable CIE76 colour difference, used for the colour and greyscale separability checks. Defaults to 5, matching palette_safety().

min_text_pt

The smallest acceptable printed text size, in points. Defaults to 6, a common publisher floor for figure text.

Value

A data frame with one row per check and columns check, measured, threshold, verdict ("pass", "fail" or "not applicable") and detail, a short note naming what produced the measurement.

Details

Every row carries the value it measured next to the threshold it was measured against, so a verdict can be argued with rather than merely accepted. A check passes when the measured value is at least the threshold. A check that has nothing to measure, such as colour separability on a figure that encodes nothing by colour, reports NA and a verdict of "not applicable" instead of a free pass.

What each check measures

colour_separability is the smallest CIE76 colour difference (Delta-E) between any two of the figure's encoding colours, and the three colour_separability_* rows repeat that measurement after simulating each dichromacy at full severity with simulate_cvd(). Encoding colours are the distinct colour and fill values a layer uses to tell groups apart; a continuous colour or fill scale is a smooth ramp rather than a set of codes, so it is excluded.

greyscale_separability is the smallest difference in CIE lightness between those same colours, which is what survives printing in black and white.

text_size is the smallest point size of any text the figure draws, after scaling by width_cm / render_width_cm: a figure drawn seven inches wide and printed in an 8.9 cm column has every point size halved. Text drawn inside the panel, by a layer such as ggplot2::geom_text() or by an annotation, is deliberately left out. It sits on the marks rather than on the background, so there is no one background to measure its contrast against, and the two engines size a layer's text in different units, which would leave the check disagreeing with its Python twin on the same figure.

text_contrast and geometry_contrast are the smallest WCAG 2.x contrast ratios of, respectively, any drawn text against the plot background and any encoding colour against the panel background.

redundant_encoding counts how many of shape and line type also vary in a layer whose colour varies. Zero means the distinction between groups is carried by colour alone, which is the single most common way an otherwise careful figure becomes unreadable.

A limitation of the default palette

The eight-colour qualitative palette clears the colour-separability checks comfortably and fails greyscale_separability: its orange (#e69f00) and sky blue (#56b4e9) differ by only 0.79 in lightness, so they print as the same grey. The colourblind-safety guarantee depictr makes is about hue confusion, and it was never a claim about greyscale. A figure that may be printed in black and white should use fewer groups, or a sequential palette, or add a redundant shape or line type; the four leading colours of the palette are also not safe in greyscale, since the bluish green and the vermillion differ by 3.55. The threshold has been left where it is rather than moved to let the package's own defaults through.

References

Machado GM, Oliveira MM, Fernandes LAF (2009). “A physiologically-based model for simulation of color vision deficiency.” IEEE Transactions on Visualization and Computer Graphics, 15(6), 1291–1298. doi:10.1109/TVCG.2009.113 .

World Wide Web Consortium (2023). “Web Content Accessibility Guidelines (WCAG) 2.2.” W3C Recommendation, https://www.w3.org/TR/WCAG22/. Accessed 2026-08-18.

See also

palette_safety() for the palette in the abstract, and palette_preview() to look at it.

Examples

library(ggplot2)

# A figure that clears every check: two well-separated colours, a redundant
# shape, and text left at the size it was drawn.
good <- ggplot(crop_yield, aes(rainfall, yield, colour = treatment,
                               shape = treatment)) +
  geom_point() +
  scale_colour_manual(values = c("#005b96", "#d55e00")) +
  theme_depictr()
check_figure(good)
#>                        check measured threshold verdict
#> 1        colour_separability   111.87       5.0    pass
#> 2 colour_separability_protan    89.87       5.0    pass
#> 3 colour_separability_deutan   107.07       5.0    pass
#> 4 colour_separability_tritan    98.50       5.0    pass
#> 5     greyscale_separability    16.92       5.0    pass
#> 6                  text_size     8.80       6.0    pass
#> 7              text_contrast     8.45       4.5    pass
#> 8          geometry_contrast     3.87       3.0    pass
#> 9         redundant_encoding     1.00       1.0    pass
#>                                                              detail
#> 1           Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 2           Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 3           Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 4           Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 5                Closest pair #005b96 and #d55e00 in CIE lightness.
#> 6 Smallest text 8.80 pt, drawn at 17.78 cm and printed at 17.78 cm.
#> 7                          Lowest-contrast text #4d4d4d on #ffffff.
#> 8                        Lowest-contrast colour #d55e00 on #ffffff.
#> 9                                        Colour is joined by shape.

# The same figure destined for an 8.9 cm journal column, where the text is
# half the size it looks on screen.
check_figure(good, width_cm = 8.9)
#>                        check measured threshold verdict
#> 1        colour_separability   111.87       5.0    pass
#> 2 colour_separability_protan    89.87       5.0    pass
#> 3 colour_separability_deutan   107.07       5.0    pass
#> 4 colour_separability_tritan    98.50       5.0    pass
#> 5     greyscale_separability    16.92       5.0    pass
#> 6                  text_size     4.40       6.0    fail
#> 7              text_contrast     8.45       4.5    pass
#> 8          geometry_contrast     3.87       3.0    pass
#> 9         redundant_encoding     1.00       1.0    pass
#>                                                             detail
#> 1          Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 2          Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 3          Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 4          Closest pair #005b96 and #d55e00 of 2 encoding colours.
#> 5               Closest pair #005b96 and #d55e00 in CIE lightness.
#> 6 Smallest text 8.80 pt, drawn at 17.78 cm and printed at 8.90 cm.
#> 7                         Lowest-contrast text #4d4d4d on #ffffff.
#> 8                       Lowest-contrast colour #d55e00 on #ffffff.
#> 9                                       Colour is joined by shape.