Model-Agnostic Exposure-Response Plots
Overview
Provides a fluent mini-language for building exposure-response plots (model curves/ribbons, quantile-binned summaries, data strips, and grouped distribution panels) from observed data and a fitted exposure-response model. Designed to be model-agnostic: any model object that implements the er_predict() generic (and, optionally, er_simulate() and er_summary()) can be visualised.
New features
- Added
er_tte(), a third mini-grammar (alongsideer_plot()/er_vpc()) for Kaplan-Meier/survival-over-time figures, built around a time axis, a survival-probability axis, and an optional discretestratify_by. Five singleton layers:er_tte_add_curve()(the KM step curve + confidence band),er_tte_add_censor()(censoring tick marks),er_tte_add_risktable()(a number-at-risk panel stacked below the curve),er_tte_add_summary()(a corner-placed text/label annotation -- a log-rank test by default, or subject/event counts or a fitted model's coefficients/goodness-of-fit viastyle), ander_tte_add_model()(a fitted parametricS(t)curve/ribbon overlay).er_tte_theme()styles labels, titles, axis limits, formatters, the legend key, and panel heights, mirroringer_plot_theme()/er_vpc_theme(). See the newplot-ttevignette.
Show all changes in 0.2.0Hide the rest of the changes in 0.2.0
- Added
er_predict_survival(), a fourth model-interface generic (see?er_model_interface) poweringer_tte_add_model()'sS(t)overlay. The new companion packageertte(Suggests/Remotes-only, GitHub- only likeerglm/emaxnls) implements it, alongside the existinger_predict()/er_simulate()/er_summary()methods. cut_quantile()/cut_exposure_quantile()gain atiesargument controlling how a value that sits exactly on an interior quantile break is assigned ("upward", the default and prior behaviour;"downward"; or"split-even", which randomly balances tied values between the two candidate bins), plus an opt-inseedargument for reproducing"split-even"'s random tie-break. The resolved rule is recorded as a"ties"attribute on the returned factor.cut_quantile()/cut_exposure_quantile()gain aquantile_typeargument, passed straight through to [stats::quantile()]'s owntypeargument for computing the quantile break points. Defaults to7(unchanged prior behaviour) and is recorded as a"quantile_type"attribute on the returned factor.cut_quantile()/cut_exposure_quantile()gain alabellerargument for customising quantile-bin labels: a function called aslabeller(n, breaks), or a character vector used directly. Defaults toNULL(unchanged"Q1"/"Q2"/... labelling);cut_exposure_quantile()'s separate"Placebo"level is untouched bylabeller.er_plot_add_quantiles()/er_plot_add_groups()gainties/quantile_type/labellerarguments, forwarded tocut_exposure_quantile()/cut_quantile(). These are local to each call -- they aren't required to agree across differenter_plot_add_groups()calls, or wither_plot_add_quantiles()-- except in one case:er_plot_build()now warns ifer_plot_add_groups()bins *the exposure variable itself* differently thaner_plot_add_quantiles()does, since the two panels would then show inconsistent quantile bins for the same variable.er_vpc()gainsties/quantile_type/labellerforplot_by, plus aseedargument for reproducing a"split-even"tie-break. Unlike theer_plot_add_quantiles()/er_plot_add_groups()arguments above, these live oner_vpc()itself rather than oner_vpc_add_observed()/er_vpc_add_simulated(), since the observed and simulated layers must always binplot_byidentically --er_vpc_add_simulated()'s ownseedargument now also seeds its independent"split-even"tie-break.er_vpc()gains an optionalstratify_byfor faceting a VPC into one panel per discrete stratum, mirroringer_plot()'s own stratification (facet-only here, since a VPC has no colour/fill precedence rule to reconcile). Errors ifstratify_byresolves to the same variable asplot_by.er_style_tag()gains alabelargument for registering a builder under a short string (e.g.label = "logrank"), so the corresponding_add_*()function'sstyleargument can be given that string instead of the function itself (e.g.er_plot_add_model(mod, style = "spaghetti")in place ofstyle = er_style_model_spaghetti). Every built-in builder across all three grammars is tagged with one; seeer_style_labels()to list what's registered (optionally filtered to onelayer), and?er_style_tagfor the full naming/lookup contract.labelrequireslayerto also be set in the same call, since the registry is keyed by(layer, label), notlabelalone. A newoverwriteargument (defaultFALSE) controls what happens when re-registering a(layer, label)pair already assigned to a *different* function: errors by default;overwrite = TRUEreplaces it unconditionally. Re-registering the identical function is always a silent no-op regardless ofoverwrite.
Improvements
er_style_vpc_observed_mean_errorbar()/er_style_vpc_simulated_mean_errorbar()gain an opt-inshow_label/label_sizepair that draws each bin's formatted rate/mean above its error bar, makinger_vpc_theme()'sformat_percent/format_numberarguments actually visible (#22).er_style_tte_risktable_text()gains an opt-inshow_percentargument that appends each break's number at risk as a percentage of its stratum's baseline size, usinger_tte_theme()'sformat_percent(#22).emaxnlsis back inSuggests/Remotes(pinned toemaxnls (>= 0.1.1.9000), the GitHub development version), and its gated examples in?erplots_dataare reinstated, now thatemaxnlsregisters theer_predict()/er_simulate()/er_summary()methods. It had been stripped for the 0.1.0 CRAN submission, ahead of that registration landing.
Breaking changes
er_style_tag()'szorderargument is renamed todraw_order(same"foreground"/"background"values); a builder tagged with the old name needs updating (e.g.er_style_tag(fn, draw_order = "background")in place ofzorder = "background")).layoutis split into two independent arguments:layoutkeeps its existing"overlay"/"panel"meaning for a data-layer builder, while a VPC observed/ simulated builder's"categorical"/"continuous"distinction moves to a newvpc_layoutargument -- the two had shared one argument and attribute despite meaning unrelated things. See?er_style_tag.er_style_tag()'slayervalues are renamed to be grammar-prefixed:"model"/"summary"/"quantile"/"data"/"group"(er_plot()) become"plot_model"/"plot_summary"/"plot_quantile"/"plot_data"/"plot_group";"observed"/"simulated"(er_vpc()) become"vpc_observed"/"vpc_simulated";"curve"/"censor"/"risktable"(er_tte()) become"tte_curve"/"tte_censor"/"tte_risktable"."tte_model"/"tte_summary"are unchanged (already grammar-prefixed). A custom builder tagged with one of the old values needs updating; see?er_style_tag.stratify_bymust now name a discrete/categorical variable iner_vpc(); a numeric column errors instead of being automatically split into quantile bins, and then_strataargument is removed. Bin a continuous covariate yourself first withcut_quantile()/cut_exposure_quantile(), which also gives full control over bin count, tie-breaking, and labels -- see?er_vpc. (er_tte()'s ownstratify_byhas the same discrete-only requirement from the outset, being new in this release.)style/keep_strata's argument position is standardised across everyer_plot_add_*()/er_vpc_add_*()/er_tte_add_*()layer function:stylenow always comes immediately afterobjectand any required model/grouping argument, andkeep_strata(where the layer has one) always comes immediately afterstyle.conf_level(where the layer has one) always comes immediately afterkeep_strata, ahead of any layer-specific argument such aser_plot_add_quantiles()'sbinsorer_tte_add_model()'stime_grid. Calls that name these arguments (the documented usage) are unaffected; positional calls that relied on the previous ordering will need updating.er_vpc()'sstratify_byargument moves to immediately afterresponse, matching whereer_plot()/er_tte()already place their ownstratify_by; it previously sat afterplot_by's binning arguments (plot_by/n_bins/ties/quantile_type/labeller). Calls that namestratify_by(the documented usage) are unaffected.- The position of
...relative to a builder's own named arguments is standardised to always come last, across every built-iner_style_*()builder:er_style_model_ribbonline()/_line()/_spaghetti(),er_style_data_overlay()/_boxjitter()/_hex(),er_style_tte_curve_km(),er_style_tte_censor_ticks(),er_style_tte_risktable_text(),er_style_tte_model_line(), ander_style_tte_summary_logrank()previously placed...immediately aftertheme, ahead of their own style-specific arguments, unlike every other built-in builder. Calls that name these arguments (the documented usage) are unaffected. - The "number of quantile bins" argument is renamed to
n_binseverywhere, matchinger_vpc()'s existing name:binsiner_plot_add_quantiles()/er_plot_add_groups(), andnincut_quantile()/cut_exposure_quantile(), all becomen_bins. A customlabellerfunction is now called aslabeller(n_bins, breaks)rather thanlabeller(n, breaks)-- since this call is positional, only the documentation changed; existing customlabellerfunctions keep working regardless of their own parameter names.er_style_data_hex()'s ander_style_group_histogram()'s ownbinsarguments (2D-hexbin/histogram bin counts, forwarded straight to the matchingggplot2geom) are unrelated and unchanged. er_style_data_overlay()'s ander_style_tte_censor_ticks()'ssizeargument (a plotted point's size) is renamed topoint_size, matching the quantile/VPC builder family's existing name for the same concept (er_style_quantile_errorbar(),er_style_vpc_observed/ simulated_mean_errorbar(), etc.) and the package's own<thing>_sizeconvention (label_size,text_size,jitter_size).er_style_group_linerange()'ssizeargument is renamed toscale_factor, since it isn't a point size at all -- it's a single multiplier applied to three different elements (a dot and two line ranges) at three different ratios, so neithersizenorpoint_sizedescribed it accurately.er_style_group_linerange()'salpha_dot/alpha_inner/alpha_outerare renamed todot_alpha/inner_alpha/outer_alpha, matching the<thing>_alphasuffix order used by every other alpha argument in the package (ribbon_alpha,box_alpha,jitter_alpha).
Bug fixes
er_plot_add_model()'s curve/ribbon no longer goes stale afterer_plot_theme(xlim = ...)narrows or widens the exposure axis once the model layer has already been added -- the prediction grid is now recomputed at build time rather than cached from add-layer time (#14).- The data, quantile, and group layers now drop (and warn about) any observations falling outside
er_plot_theme(xlim = )/ylim = ), instead of silently handing them to a geom that renders past the visible panel with no visual cue (#16). er_vpc_add_observed()/er_vpc_add_simulated()summary markers falling outsideer_vpc_theme(xlim = )/ylim = )are now dropped, with a warning, instead of silently drawn past the panel (#17).er_plot()now errors clearly whenstratify_bynames a numeric column, instead of silently mapping it to a continuous colour scale (which broke every stratified builder's discrete-groups assumption -- ribbons, per-stratum lines, dodging -- with no warning).stratify_byhas always been documented as requiring a discrete variable; this was simply never validated.er_plot_add_groups()'sbinsargument now actually controls the number of quantile bins used for a continuous grouping variable. Previously documented but silently ignored -- every continuous grouping variable was always split intocut_quantile()/cut_exposure_quantile()'s own default of 4 bins, regardless of whatbinswas set to.er_style_quantile_errorbar_vlines()/er_style_quantile_pointrange_vlines()'s bin-boundary lines/labels are now dropped (and warn), like every other layer's out-of-range markers, when they fall outsideer_plot_theme(xlim = ), instead of silently landing off the visible panel with no cue (#16).
Documentation
?er_style_tagis rewritten to describe the mechanism as a whole -- the shared self-declaration system every built-in builder acrosser_plot()/er_vpc()/er_tte()carries -- rather than describing each argument in isolation.- Added
?er_style_vpc/?er_style_tte, documenting the shared builder interface forer_vpc()/er_tte()builders, alongside the existing?er_styleforer_plot(). Previously this material was scattered across each builder family's own help page. - Fixed several cross-reference links in the pkgdown articles that previously rendered as literal bracketed text instead of a hyperlink.
- Every layer-adding function (
er_plot_add_model(),er_plot_add_summary(),er_plot_add_quantiles(),er_plot_add_data(),er_plot_add_groups(),er_vpc_add_observed(),er_vpc_add_simulated(), and all fiveer_tte_add_*()functions) now documents a "Styles" table listing every registeredstylelabel for that layer, linking straight to each builder's own help page.
From NEWS.md in the release
Install
Health
WARNINGfor unstated dependencies in ‘tests’r-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc, r-devel-windows-x86_64, r-oldrel-windows-x86_64, r-release-linux-x86_64, r-release-windows-x86_64
r-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc
'::' or ':::' import not declared from: ‘ertte’
r-oldrel-windows-x86_64, r-release-windows-x86_64
'::' or ':::' import not declared from: 'ertte'
r-devel-windows-x86_64
'::' or ':::' import not declared from: 'ertte'
r-release-linux-x86_64
'::' or ':::' import not declared from: ‘ertte’
- WARNING5 OK, 8 WARNINGNow
- WARNING11 OK, 2 WARNING2026-10-17
- OK13 OK2026-10-11
- ERROR11 OK, 2 ERROR2026-09-30
- OK5 OK2026-09-10
Documentation
The repository also keeps web-only articles.
- Help pages
- 45
- Examples that run
- 100%35 run in a plain check (16 of them under a condition)
- Exported functions with examples
- 83%
- Documented parameters
- 91%
- Return-value docs
- 100%
- Help pages citing references
- 2%
Downloads
Repository
- PRs merged (all time)
- 88%
- Median days to close, 50 most recently updated closed issues
- 0
- Median days to close, 50 most recently updated closed PRs
- 0
Releases over time
Issues over time
PRs over time
Commits over time
12 development-tooling and community-health practices detected across 6 families in the upstream repository
Checks run against github.com/djnavarro/erplots on 2026-10-18.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-10-04 · The repository has a site deploy workflow
pkgdown site last built 2026-10-04
Show all practicesHide 2 practices
Dependencies
Installing erplots adds 27 packages (13 with compiled code, 20 MB of source tarballs). Heaviest: ggplot2 6.0 MB, patchwork 3.2 MB, isoband 1.5 MB.
Code & Tests
Datasets
People & History
Pick two releases to compare their code metrics.
- 0.2.0Latest2026-10-04 · current release · diff ↗ ··
added 18 exports
er_predict_survival, er_style_labels, er_style_tte_censor_ticks, er_style_tte_curve_km, er_style_tte_model_line, er_style_tte_risktable_text, er_style_tte_summary_coefficients, er_style_tte_summary_gof, er_style_tte_summary_logrank, er_style_tte_summary_n, er_tte, er_tte_add_censor, er_tte_add_curve, er_tte_add_model, er_tte_add_risktable, er_tte_add_summary, er_tte_build, er_tte_themelisted once in CRAN's queue
Seen in one reading of CRAN's incoming queue, at 2026-10-04 12:59 UTC, so it stayed less than the time between readings. - 0.1.22026-09-09
- RR 4.6.0 released · 2026-04-24
Package metadata
- First published
- 2026-09-09
- Total releases
- 2 / 1 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 4.1.0
- Bundled data
- 51 KB / 1 file
- Download size
- 1.0 MB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("erplots")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-21, which the citation names so these numbers can be found later. More on citing and the projects behind them.