Skip to contents

Documents the shared function(data, config, stratify, exposure, response, strata, theme, ...) signature every er_style_*() builder implements, including how to write a custom one.

Value

A geom, or a list of geoms. More precisely, a list of objects that can be added to a ggplot2 plot. The expectation is that these objects will be added to a partially constructed plot which, at a minimum, already has the base theme applied. For "model", "summary", "quantile", and "overlay", the pieces will be added to a plot that already has a coord that sets the axis limits (the base plot). For the "data" (panel-based, e.g. er_style_data_boxjitter()) and "group" plots, the plot object does not yet have a coord. The expectation, however, is that the builder will supply an x-axis limit that is consistent with the base plot. That is, since all layer plots use the exposure variable for the x-axis, they should use the values stored in exposure$limits to set the x-axis limits.

Details

This page documents the shared interface all er_style_*() builders implement. The builders themselves are documented on their own family-specific pages, one per layer:

Arguments are standardised to allow users to write their own as needed

Arguments

Every er_style_*() builder receives:

  • data – The original data frame

  • config – Configuration for the specific plot

  • stratify – Logical indicating whether to stratify

  • exposure – Exposure variable

  • response – Response variable

  • strata – Stratification variable

  • theme – Theme components

  • ... – Additional named arguments forwarded from the corresponding er_plot_add_*() call's own ...; see "Passing extra arguments to a builder" below.

Writing your own builder

Every er_style_*() function above shares the signature documented in the "Arguments" section above, and that signature is a public part of the API, not an implementation detail: any function function(data, config, stratify, exposure, response, strata, theme, ...) that returns a geom or list of geoms can stand in for a built-in builder. This is the officially supported way to draw a layer differently from any of the built-in style options – e.g. a 2D density instead of a scatter for the data overlay, per-panel histograms instead of jittered points for the panel-based data layer, or a geom_crossbar() instead of a geom_errorbar()/geom_pointrange() for the quantile summary. (er_style_quantile_pointrange() started life as exactly this kind of custom builder – it was promoted to a built-in option once it proved to be a natural, low-risk alternative to er_style_quantile_errorbar(), with no new config requirements.)

Each er_plot_add_*() function takes a style argument that defaults to one built-in er_style_*() function and can be set to any other – built-in or custom – matching the standard signature: a custom builder can be plugged in without forking the package or reaching into the plot object's internal state. For the data layer specifically, style also has to declare which structural family it belongs to – a single call merged into the main panel, or one or more panels stacked below the base plot – via er_style_tag(), since er_plot_add_data() reads that tag off style to decide how to assemble the layer; the other four layers have only one structural call site, so no such tagging is needed there. See the @examples on er_plot_add_model(), er_plot_add_quantiles(), and er_plot_add_data() for worked custom builders (a dashed model curve, a quantile crossbar, and a data-overlay density, respectively). An overlay-layout data builder can additionally declare, via the same er_style_tag() call's zorder argument, whether its geoms are drawn before or after the model/summary/quantile layers when they share the main panel – relevant for a builder whose geoms cover the whole panel (e.g. er_style_data_hex()), which would otherwise bury those layers by drawing on top of them; see er_style_data() for the full explanation.

A custom builder receives the same pre-computed config a built-in builder would have received for that layer (e.g. config$predictions for model, config$summary for quantile) – it does not need to recompute anything erplots already derived from data/exposure/ response/strata; it only needs to turn that config into ggplot2 layers.

A custom builder can optionally self-declare which layer it's meant for via er_style_tag(builder, layer = ...) (one of "model", "summary", "quantile", "data", "group"). Every er_plot_add_*() function checks a builder's layer tag, if it has one, against the layer it was actually passed to, erroring immediately if they disagree – e.g. passing a builder tagged layer = "quantile" to er_plot_add_data() errors rather than calling the builder with a config shape it wasn't written for. This tag is entirely optional (unlike layout, which is mandatory for a data-layer builder specifically) – an untagged custom builder is simply never checked, so existing custom builders keep working unchanged. All built-in builders carry this tag.

All of the builders above feed a singleton layer: model, summary, quantile, data, and overlay each occupy a single slot in the plot's internal state, so calling the corresponding er_plot_add_*() function again overwrites that slot rather than combining builders. group (er_style_group_boxplot()/ er_style_group_violin()) is the one additive exception – each call to er_plot_add_groups() adds another named entry rather than replacing the previous one. See er_plot()'s "Layers are either singleton or additive" section for the full discussion.

The data slot's default, er_style_data_overlay(), needs no color_role tag: its colour aesthetic (when stratified) is always strata, since the response is already shown via y-position, so it shares the base plot's own strata legend directly. config$color_role matters for the "panel"-layout family instead, where it's "strata" for a binary response (as used by the built-in er_style_data_boxjitter(), whose colour aesthetic still means strata) or "response" for a continuous/count response, where the colour channel is already spoken for by the response value itself – there's no built-in "panel"-layout builder for that case today, but a custom builder tagged er_style_tag(builder, layout = "panel") can still opt into it; see er_plot_add_data() for the user-facing version of this rule.

Passing extra arguments to a builder

Every er_plot_add_*() function (er_plot_add_model(), er_plot_add_summary(), er_plot_add_quantiles(), er_plot_add_data(), er_plot_add_groups()) takes its own ..., which is forwarded unchanged to style when it's actually called at build time. Extra arguments must be named, since they're appended positionally after the seven standard arguments; an unnamed one errors immediately rather than silently binding to the wrong parameter. This is how a builder that needs a piece of information beyond what config already carries – something genuinely per-call rather than a fixed part of the layer's configuration – can accept it without a bespoke argument on every er_plot_add_*() function. The motivating built-in example is er_style_model_spaghetti(), which calls er_simulate() and, for models (like erglm's) that auto-select and report a seed when none is supplied, would otherwise always trigger that message:

erglm_data |>
  er_plot(aucss, ae1) |>
  er_plot_add_model(mod, style = er_style_model_spaghetti, seed = 9626) |>
  plot()

A builder that doesn't need any extra arguments simply declares ... and ignores it – every built-in builder does exactly this except er_style_model_spaghetti(). A custom builder can read whichever named arguments it recognizes out of its own ... (e.g. via rlang::list2(...)) and ignore the rest; unrecognised extra arguments are never an error at the builder itself, only at the er_plot_add_*() call site if they weren't named.