erplots draws exposure-response plots from fitted models that implement this small interface, rather than assuming a particular model class:
Implement
er_predict()for basic plotting support.Implement
er_simulate()for simulation-based visualisations.Implement
er_summary()for summary annotations.Implement
er_predict_survival()for a parametric survival-curve overlay in theer_tte()grammar (er_tte_add_model()).
Usage
er_predict(model, newdata, conf_level = 0.95, ...)
er_simulate(model, newdata, nsim = 100, seed = NULL, ...)
er_summary(model, ...)
er_predict_survival(model, newdata, time_grid, conf_level = 0.95, ...)Arguments
- model
A fitted exposure-response model object.
- newdata
A data frame of covariate values at which to predict. For
er_predict_survival(), one row per covariate profile (e.g. one per stratum level) – it does not include a time column; times come fromtime_gridinstead (see "Details").- conf_level
Confidence level for the prediction interval.
- ...
Passed to methods.
- nsim
Number of simulation replicates.
- seed
Optional RNG seed.
- time_grid
Numeric vector of times at which to predict
S(t).
Value
er_predict()returnsnewdatawith three additional columns:fit_resp(point prediction),ci_lower, andci_upper.er_simulate()returns a data frame containingnsimreplicates ofnewdata, with asim_idcolumn identifying each replicate, and afit_respcolumn giving the simulated prediction for that replicate (reflecting parameter uncertainty). Models that cannot support simulation-based visualisation should not implement a method; the default method returnsNULL; callers should treat aNULLresult as "not available" rather than an error.A method may additionally return a
sim_respcolumn: a full response-scale draw for that replicate/observation, reflecting both parameter uncertainty (asfit_respalready does) and observation-level sampling/residual noise (e.g. a 0/1 draw for a binary response, an integer draw for a count response, a draw including residual variance for a continuous response) – not just the fitted mean/probability. This is whater_vpc_add_simulated()'smodelargument requires: a visual predictive check needs simulated observations comparable to the actually observed data, not points on the mean curve, which is a genuinely different question from the onefit_resp(used byer_style_model_spaghetti()) answers.sim_respis independently optional – a method can supplyfit_respalone (as every implementation did beforesim_respexisted, and as remains sufficient for spaghetti plots), or both columns from the same call.er_vpc_add_simulated()treats asim_resp-less result the same way it treats an outrightNULL: "predictive simulation not available for this model."er_summary()returnsNULL(nothing available – the default method's behaviour), or a named list with any of the following independently optional keys. Unrecognised keys are permitted and ignored by built-in builders, giving a model package room to stash extra fields for its own custom builders.p_value: a single headline p-value (orNULL) for "the" exposure effect, when the model has one unambiguous candidate (e.g. a GLM's exposure coefficient). A model with no single privileged parameter (e.g. a multi-parameter nonlinear Emax model, with separateE0/Emax/EC50/Hillterms and no obviously "the" effect) should returnNULLhere rather than picking an arbitrary term –er_style_summary_pvalue()already treatsNULLas "nothing to show".coefficients: a tibble/data frame with one row per model parameter, for builders (e.g.er_style_summary_coefficients()) that display more than a single p-value. Columns follow this package's snake_case convention rather thanbroom::tidy()'s dotted names:term(required),label(optional display name, falls back toterm),estimate(required), and optionalstd_error,statistic,p_value,conf_low,conf_high(eachNAif not computed/meaningful).NULLif not available.glance: a single-row tibble/data frame of model-level goodness-of-fit,broom::glance()-style: optionaln,df_residual,logLik,aic,bic,deviance,r_squared(NAwhere not meaningful, e.g. non-Gaussian models),converged. Reserved for future builders; no built-in builder currently consumes it.NULLif not available.
This is purely additive: a method that only ever returns
list(p_value = ...)(as above) continues to work unchanged.er_predict_survival()returnsnewdata, cross-joined withtime_grid(one row pernewdatarow xtime_gridvalue), with three additional columns:time,fit_survival(the point estimate ofS(time | newdata row)),ci_lower, andci_upper. Unlikeer_predict(),newdatahere never includes a time/exposure column itself –time_gridis a separate argument, so a method can build the full time grid in one call per covariate profile rather than being handed a pre-crossed data frame. There is no default method that returnsNULL; a model with no survival-curve support should simply not implement this generic, ander_tte_add_model()errors informatively (via the default method above) if called with one.
Details
er_plot_add_model() does not verify that model was fit on the same exposure/response variables as the plot; that compatibility is the caller's responsibility. When er_plot_add_model() builds newdata, it always includes the exposure and, if stratified, strata variables, plus reference values for any other covariates in the model's original fitting data.
Strata membership for er_predict_survival() is carried on newdata the same way: as an ordinary column (named after the er_tte() object's own stratify_by variable), never implicit in model itself. er_tte_add_model() builds one newdata row per stratum level (or a single row, unstratified), filling any other covariate the model references with a reference value exactly as er_plot_add_model() already does (see its "Details").
A method may rely on caller-supplied extra arguments being forwarded through ...: er_plot_add_model()'s predict_args, er_plot_add_summary()'s summary_args, and er_vpc_add_simulated()'s simulate_args are each spliced into the corresponding generic call (er_predict()/er_summary()/er_simulate() respectively), so a model-specific argument beyond the fixed contract below (e.g. a landmark time for a time-to-event model) has a documented path to reach the method. These are deliberately kept separate from each er_plot_add_*()/er_vpc_add_*() function's own ..., which is reserved for the style builder instead (see er_style()'s "Passing extra arguments to a builder" section) – a method should not assume it receives anything passed via that ....
Examples
# a bare-bones er_predict() method for a plain `lm` fit
toy_fit <- lm(biomarker_change ~ auc_ss, data = erplots_data)
class(toy_fit) <- c("toy_lm", class(toy_fit))
er_predict.toy_lm <- function(model, newdata, conf_level = 0.95, ...) {
z <- -qnorm((1 - conf_level) / 2)
pred <- predict(model, newdata = newdata, se.fit = TRUE)
newdata$fit_resp <- pred$fit
newdata$ci_lower <- pred$fit - z * pred$se.fit
newdata$ci_upper <- pred$fit + z * pred$se.fit
newdata
}
er_predict(toy_fit, newdata = data.frame(auc_ss = c(100, 500, 900)))
#> auc_ss fit_resp ci_lower ci_upper
#> 1 100 -19.44029 -19.87311 -19.00747
#> 2 500 -87.09426 -89.55216 -84.63637
#> 3 900 -154.74824 -159.25187 -150.24461