Package {cifmodeling}


Title: Visualization and Polytomous Modeling of Survival and Competing Risks
Version: 1.2.3
Description: A publication-ready toolkit for modern survival and competing risks analysis with a minimal, formula-based interface. Both nonparametric estimation and direct polytomous regression of cumulative incidence functions (CIFs) are supported. The main functions 'cifcurve()', 'cifplot()', and 'cifpanel()' estimate survival and CIF curves and produce high-quality graphics with risk tables, censoring and competing-risk marks, and multi-panel or inset layouts built on 'ggplot2' and 'ggsurvfit'. The modeling function 'polyreg()' performs direct polytomous regression for coherent joint modeling of all cause-specific CIFs to estimate risk ratios, odds ratios, or subdistribution hazard ratios at user-specified time points. The function 'ciftest()' provides log-rank, Gray, robust score, augmented score, and multiple-direction tests for survival and competing-risk outcomes. All core functions adopt a formula-and-data syntax and return tidy and extensible outputs that integrate smoothly with 'modelsummary', 'broom', and the broader 'tidyverse' ecosystem. Key numerical routines are implemented in C++ via 'Rcpp'.
License: MIT + file LICENSE
Encoding: UTF-8
RoxygenNote: 7.3.3
RdMacros: lifecycle
Config/Needs/website: lifecycle
Depends: R (≥ 4.1.0)
Suggests: survival, mets, numDeriv, modelsummary, gtsummary (≥ 2.6.1), broom, broom.helpers (≥ 1.20.0), cardx (≥ 0.3.4), glue, gt, flextable, DiagrammeR, knitr, rmarkdown, testthat (≥ 3.0.0), pkgdown
Config/testthat/edition: 3
LinkingTo: Rcpp
Imports: Rcpp, nleqslv, boot, ggsurvfit, ggplot2, patchwork, scales, generics, lifecycle
VignetteBuilder: knitr
BuildManual: true
URL: https://gestimation.github.io/cifmodeling/, https://github.com/gestimation/cifmodeling
BugReports: https://github.com/gestimation/cifmodeling/issues
NeedsCompilation: yes
Packaged: 2026-11-10 09:25:36 UTC; Shiro
Author: Shiro Tanaka ORCID iD [aut, cre, cph], Shigetaka Kobari [ctb], Chisato Honda [ctb]
Maintainer: Shiro Tanaka <gestimation@gmail.com>
Repository: CRAN
Date/Publication: 2026-11-11 08:30:08 UTC

cifmodeling: Visualization and Polytomous Modeling of Survival and Competing Risks

Description

A publication-ready toolkit for modern survival and competing risks analysis with a minimal, formula-based interface. Both nonparametric estimation and direct polytomous regression of cumulative incidence functions (CIFs) are supported. The main functions 'cifcurve()', 'cifplot()', and 'cifpanel()' estimate survival and CIF curves and produce high-quality graphics with risk tables, censoring and competing-risk marks, and multi-panel or inset layouts built on 'ggplot2' and 'ggsurvfit'. The modeling function 'polyreg()' performs direct polytomous regression for coherent joint modeling of all cause-specific CIFs to estimate risk ratios, odds ratios, or subdistribution hazard ratios at user-specified time points. The function 'ciftest()' provides log-rank, Gray, robust score, augmented score, and multiple-direction tests for survival and competing-risk outcomes. All core functions adopt a formula-and-data syntax and return tidy and extensible outputs that integrate smoothly with 'modelsummary', 'broom', and the broader 'tidyverse' ecosystem. Key numerical routines are implemented in C++ via 'Rcpp'.

Author(s)

Maintainer: Shiro Tanaka gestimation@gmail.com (ORCID) [copyright holder]

Other contributors:

See Also

Useful links:


Create a survival or competing-risks response

Description

A lightweight response constructor used in cifcurve() and polyreg() to pass survival and competing-risks data via a model formula.

Usage

Event(time, event, allowed = getOption("cifmodeling.allowed", c(0, 1, 2)))

Arguments

time

Numeric vector of follow-up times (non-negative).

event

Integer (0=censor, 1,2,...) or a character/factor vector whose levels are numeric codes "0","1","2",... for competing events.

allowed

Numeric vector of acceptable event codes.

Value

An object of class "Event" (a 2-column matrix) with columns time, event.

Lifecycle

[Stable]

See Also

polyreg() for log-odds product modeling of CIFs; cifcurve() for KM/AJ estimators; cifplot() for display of a CIF; cifpanel() for display of multiple CIFs; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

## event: 0=censor, 1=primary, 2=competing
data(diabetes.complications)
output <- polyreg(
  nuisance.model = Event(t, epsilon) ~ +1,
  exposure = "fruitq1",
  data = diabetes.complications,
  effect.measure1 = "RR",
  effect.measure2 = "RR",
  time.point = 8,
  outcome.type = "competing-risk"
)


Extract a ggplot for customization or export

Description

Extract a ggplot for customization or export

Usage

as_ggplot(x, ...)

Arguments

x

A ggplot or a single-plot cifplot object.

...

No additional arguments are supported.

Value

A ggplot. This function does not estimate or predict anything.


Convert regression results to modelsummary input

Description

Convert regression results to modelsummary input

Usage

as_modelsummary(x, ...)

## S3 method for class 'polyreg'
as_modelsummary(
  x,
  event = c("both", "event1", "event2"),
  conf.int = x$conf.int,
  variance = NULL,
  ...
)

Arguments

x

A supported fitted model.

...

Model-specific inference and coefficient-selection arguments.

event

For polyreg, event1, event2, or both (the default).

conf.int

Interval level. For polyreg, defaults to its fitted level.

variance

Covariance estimator: if or bootstrap for polyreg. Omitting it preserves the stored inference.

Value

A modelsummary_list, or a named list of these for multiple outcomes. Each contains tidy and glance data frames. Extraction does not require modelsummary. Inference settings are recorded in glance and metadata.


Extract prediction data in the common long format

Description

Extract prediction data in the common long format

Usage

as_prediction_data(x, ...)

## S3 method for class 'polyreg'
as_prediction_data(
  x,
  exposure.level = x$estimand$code.exposure.ref,
  event = c("both", "event1", "event2"),
  ...
)

Arguments

x

Prediction data or a supported fitted model.

...

Model-specific arguments. GAM/CIF methods take newdata and inference settings. polyreg extracts stored training-cohort potential CIFs.

exposure.level

For polyreg, one fitted exposure label; defaults to the reference. Values are counterfactual predictions for this level.

event

For polyreg, event1, event2, or both (the default).

Value

A data frame with .row, estimate, optional category, and optional conf.low/conf.high columns. No newdata prediction is added to polyreg.


Build the closed-form competing-risk augmentation

Description

This computes the working-model process

H_a(t,X)=\int_t^\tau a(u)(X-e_X(u))G_C(u)d\Lambda_1(u|X)

in each exposure-by-competing-risk-by-censoring nuisance cell, then evaluates the centered censoring-martingale projection. The returned matrix is on the score scale; its column sums are the closed-form augmentation score.

Usage

build_closed_form_augmentation(
  base,
  working,
  t,
  epsilon,
  x,
  exposure,
  strata.censor = rep.int("pooled", length(t)),
  strata.competing.risk = rep.int("pooled", length(t)),
  weights = rep.int(1, length(t)),
  code.event1 = 1L,
  code.event2 = 2L,
  code.censoring = 0L,
  prob.bound = 1e-07,
  strata.event = rep.int("pooled", length(t))
)

Build individual Fine-Gray score-scale contributions

Description

The base component is the known-censoring-distribution martingale score. The censoring component is the delta-method contribution from estimating the stratified censoring hazards. Their column sums equal the plug-in score and zero, respectively. The matrices are diagnostic infrastructure for the augmented branch; they do not replace Gray's classical covariance.

Usage

build_fg_score_iid(
  t,
  epsilon,
  x,
  code.event1 = 1L,
  code.event2 = 2L,
  code.censoring = 0L,
  strata = rep.int("pooled", length(t)),
  weights = rep.int(1, length(t)),
  rho = 0,
  gamma = 0,
  fh.weight = NULL,
  censoring = NULL,
  prob.bound = 1e-07,
  prob.truncation = NULL,
  strata.event = rep.int("pooled", length(t))
)

Build a finite-iteration time-directed Fine-Gray score

Description

iterations = 0 is intentionally handled by the closed-form caller. This function computes one or more empirical Appendix-E refinements and maps the resulting full-data direction to observed-data score contributions.

Usage

build_iterated_score_iid(
  base,
  working,
  t,
  epsilon,
  x,
  exposure,
  weights = rep.int(1, length(t)),
  iterations = 1L,
  code.event1 = 1L,
  code.event2 = 2L,
  code.censoring = 0L,
  prob.bound = 1e-07,
  tolerance = NULL
)

Internal Kaplan-Meier interface

Description

The numerical engine always retains fractional weighted counts. The public package interface defaults to integer reporting for plotting compatibility; internal estimation code can request the unrounded weighted totals.

Usage

calculateKM(
  t,
  d,
  w = numeric(),
  strata = integer(),
  error = "greenwood",
  count.type = c("integer", "numeric")
)

Arguments

t

Follow-up times.

d

Event indicator.

w

Optional non-negative case weights.

strata

Optional integer stratum codes.

error

Variance calculation method.

count.type

Return weighted n.risk, n.event, and n.censor as upward-rounded integers ("integer") or exact numeric totals ("numeric").


A12 for log-rank-type score using directional finite differences with dw/dB from WeightIt

Description

Returns A12 on the "mean score" scale: (1/n) * dU_total/dB^T

Usage

calculate_A12_logrank_weightit(
  t,
  epsilon,
  strata,
  data,
  exposure,
  weightit,
  code.exposure.ref = NULL,
  prefix = "a",
  rho = 0,
  gamma = 0,
  prob.bound = 1e-07,
  fd_rel_step = 1e-06
)

Compute Gray's K-sample test

Description

Implements the predictable-weight estimating equations and covariance from Gray (1988). The pooled weight is ⁠(1 - F_1(t-))^rho * F_1(t-)^gamma⁠; gamma = 0 recovers the family used by cmprsk::cuminc().

Usage

calculate_gray(
  t,
  epsilon,
  exposure,
  code.exposure.ref = NULL,
  prefix = "a",
  weights = rep.int(1, length(t)),
  strata = rep.int(1L, length(t)),
  data,
  rho = 0,
  gamma = 0,
  prob.bound = 1e-10
)

Details

weights are frequency weights. strata defines independent analysis strata; stratum-specific scores and covariance matrices are summed.


Censoring-estimation correction to left-limit IPCW regression scores

Description

Returns q_i such that IF_beta_i = n H^-1 (s_i - mean(s) + q_i). Uses the same source cohort as KM, with unit sampling weights. The supplied scores already contain IPCW, including zero scores for unknown outcomes. This product-limit derivative includes the (1-h) factor at tied jumps. No n-by-n influence matrix is constructed: time-grouped score sums and cumulative risk contributions give O(n log n + np) work and O(np) storage.

Usage

censoring_km_score_correction(
  object,
  t,
  epsilon,
  strata,
  evaluation.time,
  score
)

These arguments are shared by cifplot(), cifpanel(), and cifcurve().

Description

These arguments are shared by cifplot(), cifpanel(), and cifcurve().

Arguments

data

A data frame containing variables in the formula.

weights

Optional name of the weight variable in data. Weights must be nonnegative.

n.risk.type

Character string; one of "weighted", "unweighted", or "ess". Controls which risk set size is returned in ⁠$n.risk⁠ without affecting estimates or SEs (default "weighted").

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

outcome.type

Character string specifying the type of time-to-event outcome. One of "survival" (Kaplan-Meier) or "competing-risk" (Aalen-Johansen). If NULL (default), the function automatically infers the outcome type from the data: if the event variable has more than two unique levels, "competing-risk" is assumed; otherwise, "survival" is used. You can also use abbreviations such as "S" or "C". An explicit "competing-risk" remains in effect when a cause is absent in the analysis data. Mixed or ambiguous inputs (e.g., c("S", "C")) trigger automatic detection based on the event coding.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

error

Character string specifying the method for SEs and CIs used internally. For "survival" without weights, choose one of "greenwood" (default), "tsiatis", "if", or "fay". For "competing-risk" without weights, choose one of "delta" (default), "aalen", "if", or "fay". Weighted analysis defaults to influence-function SEs ("if"). The C++ curve engine also supports "fay", a Fay–Graubard-type correction. Supplied weights are held fixed; uncertainty from estimating a propensity score is not included.

conf.type

Character specifying the method of transformation for CIs used internally (default ⁠arcsine-square root⁠).

conf.int

Numeric two-sided level of CIs (default 0.95).


These arguments are shared by cifplot() and cifpanel().

Description

These arguments are shared by cifplot() and cifpanel().

Arguments

add.risktable

Logical; if TRUE, adds a numbers-at-risk table under the plot. Default TRUE. Note: when a panel mode is active, tables are suppressed.

add.estimate.table

Logical; if TRUE, adds a table of estimates and CIs. Default FALSE. Note: when a panel mode is active, tables are suppressed.

symbol.risk.table

Character specifying the symbol used in the risk table to denote strata: "square", "circle", or "triangle" (default "square").

font.size.risk.table

Numeric font size for texts in risk / estimate tables (default 3).

label.strata

Character vector or named character vector specifying labels for strata. Names (if present) must match the (re-ordered) underlying strata levels. Note: when any of the panel modes is active (panel.per.variable = TRUE, panel.per.event = TRUE, panel.censoring = TRUE, or panel.mode = "auto" and it actually dispatches to a panel), strata labels are suppressed to avoid duplicated legends across sub-plots.

level.strata

Optional character vector giving the full set of expected strata levels. When provided, both order.strata and label.strata are validated against it before application.

order.strata

Optional character vector specifying the display order of strata in the legend/number-at-risk table. Specify the levels of strata. Levels not listed are dropped.

legend.position

Character specifying the legend position: "top", "right", "bottom", "left", or "none" (default "top").

type.y

Character string specifying the y-scale. For survival/CIF curves, "surv" implies survival probabilities and "risk" implies CIF (1-survival in simple survival settings). Specify "cumhaz" to plot cumulative hazard or "cloglog" to generate a complementary log-log plot. If NULL, a default is chosen from outcome.type or the survfit object.

label.x

Character x-axis label (default "Time").

label.y

Character y-axis label (default is chosen automatically from outcome.type and type.y, e.g. "Survival", "Cumulative incidence" or "Cumulative hazard").

limits.x

Numeric length-2 vector specifying x-axis limits. If NULL, it is set from the fitted object (typically c(0, max(time))).

limits.y

Numeric length-2 vector specifying y-axis limits. If NULL, it is set to c(0, 1) for probability-type outcomes.

breaks.x

Numeric vector of x-axis breaks (default NULL).

breaks.y

Numeric vector of y-axis breaks (default NULL).

use.coord.cartesian

Logical; if TRUE, uses ggplot2::coord_cartesian() for zooming instead of changing the scale limits (default FALSE).

add.conf

Logical; if TRUE, adds a CI ribbon (via ggsurvfit::add_confidence_interval()). Default TRUE.

add.censor.mark

Logical; if TRUE, draws censoring marks on each curve (via ggsurvfit::add_censor_mark()). Default TRUE.

shape.censor.mark

Integer point shape used for censoring marks (default 3).

size.censor.mark

Numeric point size used for censoring marks (default 2).

add.competing.risk.mark

Logical; if TRUE, draws time marks for the competing event (event 2). If no times are supplied via competing.risk.time, the function tries to extract them automatically from the data. Default FALSE.

competing.risk.time

A named list of numeric vectors. Each name must correspond to a strata label, and its numeric vector gives the times at which the competing event occurred in that stratum. Typically left as list() and filled internally.

shape.competing.risk.mark

Integer point shape for competing-risk marks (default 16).

size.competing.risk.mark

Numeric point size for competing-risk marks (default 2).

add.intercurrent.event.mark

Logical; if TRUE, overlays user-specified intercurrent-event times per stratum. Default FALSE.

intercurrent.event.time

A named list of numeric vectors for intercurrent events (names must match strata labels).

shape.intercurrent.event.mark

Integer point shape for intercurrent-event marks (default 1).

size.intercurrent.event.mark

Numeric point size for intercurrent-event marks (default 2).

add.quantile

Logical; if TRUE, adds a quantile reference line (via ggsurvfit::add_quantile()). Default FALSE.

level.quantile

Numeric quantile level to be shown (default 0.5 for the median).

rows.columns.panel

Optional integer vector c(nrow, ncol) controlling the layout of the panel returned by the panel modes. If NULL, an automatic layout is determined from the number of subplots.

style

Character choosing the base plot style: "classic", "bold", "framed", "grid", "gray" or "ggsurvfit" (default "classic"). Abbreviations such as "C", "B", "F", or "G" are also accepted.

palette

Optional character vector specifying the color palette to use across strata.

linewidth

Optional numeric specifying the line width of curve (default 0.8).

linetype

Optional logical using different line types of curve (default FALSE).

font.family

Character specifying the font family: "sans", "serif", or "mono" (default "sans").

font.size

Integer specifying the base font size (default 12).

print.panel

Logical. When TRUE, panel displays created internally are printed automatically in interactive sessions; otherwise they are returned invisibly for further modification (default FALSE).

filename.ggsave

Character; if non-NULL, save the plot to this file.

width.ggsave

Numeric width passed to ggplot2::ggsave() (default 6).

height.ggsave

Numeric height passed to ggplot2::ggsave() (default 6).

dpi.ggsave

Numeric DPI passed to ggplot2::ggsave() (default 300).


Calculate the Kaplan-Meier estimator and the Aalen-Johansen estimator

Description

Core estimation routine that computes a survfit-compatible object from a formula + data interface (Event() or survival::Surv() on the LHS, and a stratification variable on the RHS if necessary). The back-end C++ routine supports both weighted and stratified data. Use this when you want numbers only (e.g. estimates, SEs, CIs and influence functions) and will plot it yourself.

Usage

## S3 method for class 'cifcurve'
summary(object, ...)

cifcurve(
  formula,
  data,
  weights = NULL,
  n.risk.type = "weighted",
  subset.condition = NULL,
  na.action = na.omit,
  outcome.type = NULL,
  time.point = NULL,
  null.hypothesis = NULL,
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  error = NULL,
  conf.type = "arcsine-square root",
  conf.int = 0.95,
  report.influence.function = FALSE,
  report.survfit.std.err = FALSE,
  engine = "calculateAJ_Rcpp",
  prob.bound = 1e-07,
  conf.dist = c("normal", "t"),
  df.method = c("deletion", "equal")
)

Arguments

object

A fitted cifcurve object to summarize.

...

Arguments passed to summary.survfit(), including times.

formula

A model formula specifying the time-to-event outcome on the LHS (typically Event(time, status) or survival::Surv(time, status)) and, optionally, a stratification variable on the RHS. Surv() responses must be right-censored. Unlike cifplot(), this function does not accept a fitted survfit object.

data

A data frame containing variables in the formula.

weights

Optional name of the weight variable in data. Weights must be nonnegative.

n.risk.type

Character string; one of "weighted", "unweighted", or "ess". Controls which risk set size is returned in ⁠$n.risk⁠ without affecting estimates or SEs (default "weighted").

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

outcome.type

Character string specifying the type of time-to-event outcome. One of "survival" (Kaplan-Meier) or "competing-risk" (Aalen-Johansen). If NULL (default), the function automatically infers the outcome type from the data: if the event variable has more than two unique levels, "competing-risk" is assumed; otherwise, "survival" is used. You can also use abbreviations such as "S" or "C". An explicit "competing-risk" remains in effect when a cause is absent in the analysis data. Mixed or ambiguous inputs (e.g., c("S", "C")) trigger automatic detection based on the event coding.

time.point

Optional finite, non-negative time for a one-sided normal approximation test when null.hypothesis is specified. The test returns a missing p-value for strata with no positive-weight follow-up at this time.

null.hypothesis

Optional null value for the survival probability or cumulative incidence at time.point. For outcome.type = "survival", the one-sided alternative is that the observed survival probability is higher than the null value. For outcome.type = "competing-risk", the one-sided alternative is that the observed CIF for code.event1 is lower than the null value. A scalar value is recycled across strata. A named numeric vector can be used to specify stratum-specific null values.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

error

Character string specifying the method for SEs and CIs used internally. For "survival" without weights, choose one of "greenwood" (default), "tsiatis", "if", or "fay". For "competing-risk" without weights, choose one of "delta" (default), "aalen", "if", or "fay". Weighted analysis defaults to influence-function SEs ("if"). The C++ curve engine also supports "fay", a Fay–Graubard-type correction. Supplied weights are held fixed; uncertainty from estimating a propensity score is not included.

conf.type

Character specifying the method of transformation for CIs used internally (default ⁠arcsine-square root⁠).

conf.int

Numeric two-sided level of CIs (default 0.95).

report.influence.function

Logical. When TRUE and engine = "calculateAJ_Rcpp", the influence function is also computed and returned (default FALSE).

report.survfit.std.err

Logical. If TRUE, report SE on the log-survival scale (survfit's convention). Otherwise SE is on the probability scale.

engine

Character. One of "auto", "calculateKM", or "calculateAJ_Rcpp" (default). "calculateAJ" is also accepted as an alias for "calculateAJ_Rcpp". The legacy engine accepts no weights or positive weights constant within each stratum, and normal inference with Greenwood/Tsiatis for survival or delta/Aalen for competing risks. Its SEs use subject counts.

prob.bound

Numeric lower bound used to internally truncate probabilities away from 0 and 1 (default 1e-7).

conf.dist

Reference distribution for pointwise CIs: "normal" (default) or "t". Student intervals require error = "if" or "fay"; omitting error with conf.dist = "t" selects "if".

df.method

Allocation used for Student degrees of freedom: "deletion" (default, FG-type) or "equal" (IF-t only).

Details

Typical use cases

Risk set display

Standard error and confidence intervals

Argument Description Default
error SE for KM: "greenwood", "tsiatis", "if", "fay". For CIF: "aalen", "delta", "if", "fay". "greenwood", "delta" or "if"
conf.type Transformation for CIs: "plain", "log", "log-log", "arcsin", "logit", or "none". "arcsin"
conf.int Two-sided CI level. 0.95

With the C++ engine, error = "fay" applies the Fay–Graubard-type sandwich correction with leverage capped at 0.75. Combining error = "if" or "fay" with conf.dist = "t" gives IF-t or FG-t, respectively. "fg" and "fay-graubard" are accepted aliases for "fay"; the returned error is always "fay" for this correction. All supplied weights are held fixed, including externally estimated IPTW; uncertainty from fitting a propensity-score model is not included. Deletion degrees of freedom use unscaled hazard-score equations and no-event-baseline hazard logits (a positive cause is the baseline at complete exit). Equal allocation is invariant to fixed invertible score transformations within this system; its small-sample coverage need not equal deletion allocation. These are working quadratic-form approximations, not exact Student laws.

With the C++ engine, IF and FG intervals use exact boundary singletons; interior zero variance, unavailable degrees of freedom, and times beyond positive-weight follow-up produce missing limits with reasons in ⁠$conf.status⁠. No normal fallback is used for a failed Student interval. Degrees of freedom vary by stratum and time; calculation can be expensive for large risk sets. The optional one-sided test retains its documented normal reference distribution. Delta and Aalen variances use all event times up to the reported time. If the Aalen formula gives a negative variance with tied events, its SE and confidence limits are missing. Returned influence functions are uncorrected case-weight derivatives (IF/n) of the event probability ⁠1 - $surv⁠, even when the SE uses FG-adjusted contributions.

One-sided normal approximation test

When both time.point and null.hypothesis are specified, cifcurve() compares the estimate at time.point with null.hypothesis using a normal approximation. The test statistic is

Z = (g(\hat{p}) - g(p_0)) / \widehat{SE}(g(\hat{p})).

where g() is the transformation specified by conf.type. For survival outcomes, \hat p is the Kaplan-Meier survival estimate and the default one-sided alternative is S(t) > S_0(t). For competing-risk outcomes, the reported estimate is the Aalen-Johansen cumulative incidence estimate F_1(t) for code.event1, but the transformation for the one-sided test is applied to 1 - F_1(t) and 1 - F_{10}(t), consistently with the survfit-compatible ⁠$surv⁠ component. Thus, conf.type = "log-log" corresponds to \log[-\log(1 - F_1(t))] for competing-risk outcomes. The default one-sided alternative is F_1(t) < F_{10}(t), equivalently 1 - F_1(t) > 1 - F_{10}(t). When strata are present, the test is calculated separately within each stratum.

Value

An object inheriting from "cifcurve" and "survfit". For outcome.type="survival", ⁠$surv⁠ is the survival function. For outcome.type="competing-risk", ⁠$surv⁠ equals 1 - CIF for code.event1. SE and CIs are provided per error, conf.type and conf.int. This enables an independent use of standard methods for survfit such as:

If null.hypothesis is specified, the returned object additionally contains a one.sided.p list with the one-sided normal approximation test results. Its table marks strata beyond positive-weight follow-up with test.status = "outside_observed_followup".

Note that ⁠$n.risk⁠, ⁠$n.event⁠, and ⁠$n.censor⁠ are rounded up to the nearest integer regardless of whether the data is weighted or not. Some methods (e.g. residuals.survfit) may not be supported. IF/FG results also record conf.dist, df, df.reason, critical.value, and conf.status; Student results record df.method. These vectors follow the fitted curve's stratum/time ordering. FG results record the fixed leverage cap in fay.bound. Influence matrices have one row per original observation within each stratum, including zero-weight rows. summary(fit, times = ..., extend = TRUE) extracts the saved intervals, probability-scale SEs and time-specific inference diagnostics. Unsupported times retain missing limits. Use this summary rather than indexing added inference vectors on copies whose time grid was expanded by survfit0(). logse records the scale of the stored std.err. The internal reporting component preserves the native inference grid for this extraction.

Lifecycle

[Stable]

See Also

polyreg() for log-odds product modeling of CIFs; cifplot() for display of a CIF; cifpanel() for display of multiple CIFs; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

data(diabetes.complications)
output1 <- cifcurve(Event(t,epsilon) ~ fruitq,
                    data = diabetes.complications,
                    outcome.type="competing-risk")
cifplot(output1,
        outcome.type = "competing-risk",
        type.y = "risk",
        add.risktable = FALSE,
        label.y = "CIF of diabetic retinopathy",
        label.x = "Years from registration")

output2 <- cifcurve(Event(t,epsilon) ~ fruitq,
                    data = diabetes.complications,
                    outcome.type = "competing-risk",
                    time.point = 8,
                    null.hypothesis = 0.30)
output2$one.sided.p


Create a flowchart of exclusions, treatment groups, and outcome status

Description

cifflowchart() creates a lightweight flowchart of exclusions, treatment groups, and outcome status with DiagrammeR. It can be used as a simple CONSORT-like flowchart helper, but it is not intended to fully automate a CONSORT-compliant diagram.

Usage

cifflowchart(
  formula,
  data,
  time.point = NULL,
  withdraw.consent = NULL,
  ineligible = NULL,
  pre.exclude = NULL,
  post.exclude = NULL,
  subset.condition = NULL,
  na.action = na.pass,
  outcome.type = NULL,
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  label.strata = NULL,
  order.strata = NULL,
  label.events = NULL,
  title = NULL,
  percent = TRUE,
  digits = 1,
  ...
)

Arguments

formula

A formula. Supported forms are response ~ arm, response ~ 1, and Event(time, status) ~ arm.

data

A data frame.

time.point

Optional time point for Event(time, status) formulas.

withdraw.consent, ineligible, pre.exclude, post.exclude

Optional exclusion variables. Logical vectors use TRUE as excluded. Character and factor vectors use non-missing, non-empty values as exclusion reasons.

subset.condition

Optional expression evaluated in data before counting.

na.action

Included for consistency with other formula interfaces. The default is na.pass because missing outcomes and missing groups are displayed in the flowchart.

outcome.type

Reserved for future use.

code.event1, code.event2, code.censoring

Status codes for event-history formulas.

label.strata

Optional labels for treatment groups.

order.strata

Optional order for treatment groups.

label.events

Optional labels for outcome states. A named vector may be used to map existing labels to display labels.

title

Optional graph title.

percent

Logical; show percentages in nodes.

digits

Number of digits for percentages.

...

Reserved for future use.

Value

A DiagrammeR::grViz() htmlwidget.

Lifecycle

[Experimental]

Examples

if (requireNamespace("DiagrammeR", quietly = TRUE)) {
  data(diabetes.complications)

  cifflowchart(
    Event(t, epsilon) ~ fruitq1,
    data = diabetes.complications,
    time.point = 8,
    outcome.type = "competing-risk"
  )
}


Arrange multiple survival and CIF plots in a panel display

Description

cifpanel() is the panel-building counterpart of cifplot(). It takes one or more model formulas (or, alternatively, one formula and several event-coding specifications) and returns a multi-panel figure, typically as a patchwork-compatible object. Most display options (axis labels, marks, style, ggsave options) are shared with cifplot(), but per-panel legends and number-at-risk tables are suppressed to avoid duplicated display. Typical use cases are:

Usage

cifpanel(
  plots = NULL,
  formula = NULL,
  formulas = NULL,
  data = NULL,
  weights = NULL,
  subset.condition = NULL,
  na.action = na.omit,
  outcome.type = NULL,
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  code.events = NULL,
  error = NULL,
  conf.type = NULL,
  conf.int = NULL,
  n.risk.type = c("weighted", "unweighted", "ess"),
  type.y = NULL,
  label.x = NULL,
  label.y = NULL,
  label.strata = NULL,
  order.strata = NULL,
  level.strata = NULL,
  limits.x = NULL,
  limits.y = NULL,
  breaks.x = NULL,
  breaks.y = NULL,
  add.conf = NULL,
  add.risktable = NULL,
  add.estimate.table = NULL,
  symbol.risk.table = NULL,
  font.size.risk.table = NULL,
  add.censor.mark = NULL,
  shape.censor.mark = NULL,
  size.censor.mark = NULL,
  add.competing.risk.mark = NULL,
  competing.risk.time = NULL,
  shape.competing.risk.mark = NULL,
  size.competing.risk.mark = NULL,
  add.intercurrent.event.mark = NULL,
  intercurrent.event.time = NULL,
  shape.intercurrent.event.mark = NULL,
  size.intercurrent.event.mark = NULL,
  add.quantile = NULL,
  level.quantile = NULL,
  rows.columns.panel = c(1, 1),
  inset.panel = FALSE,
  title.panel = NULL,
  subtitle.panel = NULL,
  caption.panel = NULL,
  tag.panel = NULL,
  title.plot = NULL,
  style = "classic",
  palette = NULL,
  linewidth = 0.8,
  linetype = FALSE,
  font.family = "sans",
  font.size = 8,
  legend.position = "top",
  legend.collect = TRUE,
  inset.left = 0.6,
  inset.bottom = 0.05,
  inset.right = 0.98,
  inset.top = 0.45,
  inset.align.to = c("panel", "plot", "full"),
  inset.legend.position = NULL,
  print.panel = FALSE,
  filename.ggsave = NULL,
  width.ggsave = NULL,
  height.ggsave = NULL,
  dpi.ggsave = 300,
  survfit.info = NULL,
  axis.info = NULL,
  visual.info = NULL,
  panel.info = NULL,
  style.info = NULL,
  inset.info = NULL,
  print.info = NULL,
  ggsave.info = NULL,
  engine = "cifplot",
  ...
)

Arguments

plots

Optional list of existing ggplot objects to be arranged into a panel. When plots is supplied, no new models are fitted; the plots are used as-is.

formula

A model formula specifying the time-to-event outcome on the left-hand side (typically Event(time, status) or Surv(time, status)) and, optionally, a stratification variable on the right-hand side. Unlike cifplot(), this function does not accept a fitted survfit object.

formulas

Optional list of formulas. When given, each formula defines one panel. This is the most common way to create “one variable per plot” panels.

data

A data frame containing variables in the formula.

weights

Optional name of the weight variable in data. Weights must be nonnegative.

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

outcome.type

Character string specifying the type of time-to-event outcome. One of "survival" (Kaplan-Meier) or "competing-risk" (Aalen-Johansen). If NULL (default), the function automatically infers the outcome type from the data: if the event variable has more than two unique levels, "competing-risk" is assumed; otherwise, "survival" is used. You can also use abbreviations such as "S" or "C". An explicit "competing-risk" remains in effect when a cause is absent in the analysis data. Mixed or ambiguous inputs (e.g., c("S", "C")) trigger automatic detection based on the event coding.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

code.events

Optional specification of event/censoring codes. For single-panel calls, supply a numeric vector. For competing-risk outcomes, use c(event1, event2, censoring). For survival outcomes, a length-2 or length-3 vector is allowed: c(event, censoring) or ⁠c(event, *, censoring)⁠, where any middle element is ignored. When supplied, this argument overrides code.event1, code.event2, and code.censoring for the purpose of estimation. For panel displays (e.g. cifpanel() or when panel.per.event = TRUE or panel.censoring = TRUE), code.events may also be a list of such numeric vectors, one per panel.

error

Character string specifying the method for SEs and CIs used internally. For "survival" without weights, choose one of "greenwood" (default), "tsiatis", "if", or "fay". For "competing-risk" without weights, choose one of "delta" (default), "aalen", "if", or "fay". Weighted analysis defaults to influence-function SEs ("if"). The C++ curve engine also supports "fay", a Fay–Graubard-type correction. Supplied weights are held fixed; uncertainty from estimating a propensity score is not included.

conf.type

Character specifying the method of transformation for CIs used internally (default ⁠arcsine-square root⁠).

conf.int

Numeric two-sided level of CIs (default 0.95).

n.risk.type

Character string; one of "weighted", "unweighted", or "ess". Controls which risk set size is returned in ⁠$n.risk⁠ without affecting estimates or SEs (default "weighted").

type.y

Character string specifying the y-scale. For survival/CIF curves, "surv" implies survival probabilities and "risk" implies CIF (1-survival in simple survival settings). Specify "cumhaz" to plot cumulative hazard or "cloglog" to generate a complementary log-log plot. If NULL, a default is chosen from outcome.type or the survfit object.

label.x

Character x-axis label (default "Time").

label.y

Character y-axis label (default is chosen automatically from outcome.type and type.y, e.g. "Survival", "Cumulative incidence" or "Cumulative hazard").

label.strata

Character vector or named character vector specifying labels for strata. Names (if present) must match the (re-ordered) underlying strata levels. Note: when any of the panel modes is active (panel.per.variable = TRUE, panel.per.event = TRUE, panel.censoring = TRUE, or panel.mode = "auto" and it actually dispatches to a panel), strata labels are suppressed to avoid duplicated legends across sub-plots.

order.strata

Optional character vector specifying the display order of strata in the legend/number-at-risk table. Specify the levels of strata. Levels not listed are dropped.

level.strata

Optional character vector giving the full set of expected strata levels. When provided, both order.strata and label.strata are validated against it before application.

limits.x

Numeric length-2 vector specifying x-axis limits. If NULL, it is set from the fitted object (typically c(0, max(time))).

limits.y

Numeric length-2 vector specifying y-axis limits. If NULL, it is set to c(0, 1) for probability-type outcomes.

breaks.x

Numeric vector of x-axis breaks (default NULL).

breaks.y

Numeric vector of y-axis breaks (default NULL).

add.conf

Logical; if TRUE, adds a CI ribbon (via ggsurvfit::add_confidence_interval()). Default TRUE.

add.risktable

Logical; if TRUE, adds a numbers-at-risk table under the plot. Default TRUE. Note: when a panel mode is active, tables are suppressed.

add.estimate.table

Logical; if TRUE, adds a table of estimates and CIs. Default FALSE. Note: when a panel mode is active, tables are suppressed.

symbol.risk.table

Character specifying the symbol used in the risk table to denote strata: "square", "circle", or "triangle" (default "square").

font.size.risk.table

Numeric font size for texts in risk / estimate tables (default 3).

add.censor.mark

Logical; if TRUE, draws censoring marks on each curve (via ggsurvfit::add_censor_mark()). Default TRUE.

shape.censor.mark

Integer point shape used for censoring marks (default 3).

size.censor.mark

Numeric point size used for censoring marks (default 2).

add.competing.risk.mark

Logical; if TRUE, draws time marks for the competing event (event 2). If no times are supplied via competing.risk.time, the function tries to extract them automatically from the data. Default FALSE.

competing.risk.time

A named list of numeric vectors. Each name must correspond to a strata label, and its numeric vector gives the times at which the competing event occurred in that stratum. Typically left as list() and filled internally.

shape.competing.risk.mark

Integer point shape for competing-risk marks (default 16).

size.competing.risk.mark

Numeric point size for competing-risk marks (default 2).

add.intercurrent.event.mark

Logical; if TRUE, overlays user-specified intercurrent-event times per stratum. Default FALSE.

intercurrent.event.time

A named list of numeric vectors for intercurrent events (names must match strata labels).

shape.intercurrent.event.mark

Integer point shape for intercurrent-event marks (default 1).

size.intercurrent.event.mark

Numeric point size for intercurrent-event marks (default 2).

add.quantile

Logical; if TRUE, adds a quantile reference line (via ggsurvfit::add_quantile()). Default FALSE.

level.quantile

Numeric quantile level to be shown (default 0.5 for the median).

rows.columns.panel

Optional integer vector c(nrow, ncol) controlling the layout of the panel returned by the panel modes. If NULL, an automatic layout is determined from the number of subplots.

inset.panel

Logical. If FALSE (default), all panels are arranged in a regular grid using patchwork::wrap_plots() and plot_layout(). If TRUE, the function switches to “inset mode”: the first plot becomes the main plot and the second plot (only the second) is drawn on top of it as an inset. Additional plots beyond the second are ignored in inset mode. Use grid mode to display more than two panels (inset.panel = FALSE).

title.panel, subtitle.panel, caption.panel

Character annotations applied to the whole panel layout (not to individual plots). These are passed to patchwork::plot_annotation() and are useful for creating figure-like outputs (title + subfigures + caption).

tag.panel

Passed to patchwork::plot_annotation() to auto-label individual panels (e.g. "A", "B", "C"). Typical values are "A", "1", or "a". See ?patchwork::plot_annotation.

title.plot

Character vector of titles for each panel in the order they are drawn. Length-1 values are recycled to all panels. In inset mode, the first element refers to the main plot and the second (if present) to the inset.

style

Character choosing the base plot style: "classic", "bold", "framed", "grid", "gray" or "ggsurvfit" (default "classic"). Abbreviations such as "C", "B", "F", or "G" are also accepted.

palette

Optional character vector specifying the color palette to use across strata.

linewidth

Optional numeric specifying the line width of curve (default 0.8).

linetype

Optional logical using different line types of curve (default FALSE).

font.family

Character specifying the font family: "sans", "serif", or "mono" (default "sans").

font.size

Integer specifying the base font size (default 12).

legend.position

Character specifying the legend position: "top", "right", "bottom", "left", or "none" (default "top").

legend.collect

Logical; if TRUE, try to collect a single legend for all panels (passed to patchwork). Default TRUE.

inset.left, inset.bottom, inset.right, inset.top

Numeric values in the range ⁠[0, 1]⁠ that define the inset box as fractions of the reference area. inset.left / inset.right control the horizontal position, inset.bottom / inset.top control the vertical position. Values are interpreted as “from the left/bottom” of the reference. For example, inset.left = 0.4, inset.right = 1.0 draws the inset over the right 60% of the reference area.

inset.align.to

Character string specifying the coordinate system for the inset box. One of "panel" (default; the box is placed relative to the panel area, i.e. the plotting region excluding outer titles/margins), "plot" (relative to the entire plot area, including axes and titles of the main plot), or "full" (relative to the full patchwork canvas). This argument is passed to patchwork::inset_element().

inset.legend.position

Optional legend position for the inset plot only. If NULL (default), the inset plot keeps whatever legend position was defined for it (often this means a legend will also be inset). Set, for example, "none" to hide the legend inside the inset, while still showing the main plot's legend.

print.panel

Logical. When TRUE, panel displays created internally are printed automatically in interactive sessions; otherwise they are returned invisibly for further modification (default FALSE).

filename.ggsave

Character; if non-NULL, save the plot to this file.

width.ggsave

Numeric width passed to ggplot2::ggsave() (default 6).

height.ggsave

Numeric height passed to ggplot2::ggsave() (default 6).

dpi.ggsave

Numeric DPI passed to ggplot2::ggsave() (default 300).

survfit.info, axis.info, visual.info, panel.info, style.info, print.info, ggsave.info, inset.info

Internal lists used for programmatic control. Not intended for direct user input.

engine

Character string specifying the internal rendering engine used to build each panel. Currently intended for internal use; default is "cifplot".

...

Additional arguments forwarded to the internal cifplot_single() calls that build each panel. Use this to pass low-level options such as competing.risk.time, intercurrent.event.time, or styling overrides.

Details

Overview

cifpanel() composes multiple survival/CIF plots into a single figure. For each panel, it estimates curves via cifcurve() and renders them with cifplot(). You can supply a single formula reused across panels or a list in formulas (one per panel). When both are provided, formulas wins.

Outcome type & event coding

Panel-wise vs shared arguments

Panel layout is specified by length-2 vector rows.columns.panel. This function can also automatically determine the panel count in the following order: (1) if plots is supplied, its length defines the number of plots, (2) else if formulas is supplied, its length defines the number of plots, (3) else if code.events is supplied, its length defines the number of plots together with formula, and (4) otherwise rows.columns.panel=c(1,1).

Many arguments accept a scalar (recycled to all panels) or a list/vector (one entry per panel). Precedence: panel-wise explicit values > shared scalar > internal defaults. Length-1 inputs are recycled.

Grid vs inset composition

Advanced panel controls (forwarded to cifplot())

The following arguments allow per-panel control by supplying vectors/lists, or shared control by supplying scalars. They are forwarded to cifplot().

Scale & labels
Argument Meaning Default
type.y "risk" (CIF y-axis) or NULL (survival). inferred
label.x, label.y Axis labels per panel. auto
label.strata Legend labels per panel. from data
limits.x, limits.y Axis limits c(min, max). auto
breaks.x, breaks.y Axis breaks (forwarded to breaks.x/breaks.y). auto
Plot layers (toggles)
Argument Effect Default
add.conf CI ribbon. TRUE
add.censor.mark Censor marks. TRUE
add.competing.risk.mark Marks for event2 at supplied times. FALSE
add.intercurrent.event.mark User-specified intercurrent marks. FALSE
add.quantile Quantile reference line(s). FALSE

(Time marks inputs such as competing.risk.time / intercurrent.event.time can be given via ... if needed; names must match strata labels.)

Legend & annotations

Export (optional)

If filename.ggsave is non-NULL, the composed panel is saved with ggsave() using width.ggsave, height.ggsave, and dpi.ggsave. Otherwise, the function returns objects without saving.

Notes

Value

A "cifpanel" object (returned invisibly), which is a list with at least the following elements:

When print.panel = TRUE, the patchwork object is printed in interactive sessions in addition to being returned.

Lifecycle

[Experimental]

See Also

polyreg() for log-odds product modeling of CIFs; cifcurve() for KM/AJ estimators; cifplot() for display of a CIF; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

data(diabetes.complications)
output1 <- cifpanel(
  title.panel = "A comparison of cumulative incidence of competing events",
  rows.columns.panel = c(1,2),
  formula = Event(t, epsilon) ~ fruitq,
  data = diabetes.complications,
  outcome.type = "competing-risk",
  code.events = list(c(1,2,0), c(2,1,0)),
  label.y = c("Diabetic retinopathy", "Macrovascular complications"),
  label.x = "Years from registration",
  subtitle.panel = "Stratified by fruit intake",
  caption.panel  = "Data: diabetes.complications",
  title.plot = c("Diabetic retinopathy", "Macrovascular complications"),
  legend.position = "bottom",
  legend.collect=TRUE
)
print(output1)

output2 <- cifplot(Event(t,epsilon) ~ fruitq,
                   data = diabetes.complications,
                   outcome.type="competing-risk",
                   code.event1=2,
                   code.event2=1,
                   add.conf = FALSE,
                   add.risktable = FALSE,
                   label.y="CIF of macrovascular complications",
                   label.x="Years from registration")
output3 <- cifplot(Event(t,epsilon) ~ fruitq,
                   data = diabetes.complications,
                   outcome.type="competing-risk",
                   code.event1=2,
                   code.event2=1,
                   add.conf = FALSE,
                   add.risktable = FALSE,
                   label.y="",
                   label.x="",
                   limits.y=c(0,0.15))
output4 <- list(a = output2$plot, b = output3$plot)
output5 <- cifpanel(plots = output4,
         inset.panel = TRUE,
         inset.left = 0.40, inset.bottom = 0.45,
         inset.right = 1.00, inset.top = 0.95,
         inset.align.to = "plot",
         inset.legend.position = "none",
         legend.position = "bottom")
print(output5)


Generate a survival/CIF curve with marks that represent censoring, competing risks and intercurrent events

Description

This function generates a survival or CIF curve from a unified formula–data interface or from an existing survfit object. When a formula is supplied, the LHS is typically Event() or survival::Surv(), and the RHS specifies an optional stratification variable. In addition to the curves themselves, cifplot() can add numbers-at-risk tables, tables of point estimates and CIs, censoring marks, competing-risk marks, and intercurrent-event marks.

For usual single-panel mode, the function returns an object whose plot component is a regular ggplot object that can be further modified. Use as_ggplot(result) + ggplot2::labs(...) or result$plot + ...; the wrapper itself is not a ggplot. For more complex multi-panel displays, cifplot() can internally call cifpanel() via several “panel modes” (per event, per variable, or censoring-focused).

Usage

cifplot(
  formula_or_fit,
  data = NULL,
  weights = NULL,
  subset.condition = NULL,
  na.action = na.omit,
  outcome.type = "competing-risk",
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  code.events = NULL,
  error = NULL,
  conf.type = "arcsine-square root",
  conf.int = 0.95,
  n.risk.type = c("weighted", "unweighted", "ess"),
  type.y = NULL,
  label.x = "Time",
  label.y = NULL,
  label.strata = NULL,
  level.strata = NULL,
  order.strata = NULL,
  limits.x = NULL,
  limits.y = NULL,
  breaks.x = NULL,
  breaks.y = NULL,
  use.coord.cartesian = FALSE,
  add.conf = TRUE,
  add.risktable = TRUE,
  add.estimate.table = FALSE,
  symbol.risk.table = "square",
  font.size.risk.table = 3,
  add.censor.mark = TRUE,
  shape.censor.mark = 3,
  size.censor.mark = 2,
  add.competing.risk.mark = FALSE,
  competing.risk.time = list(),
  shape.competing.risk.mark = 16,
  size.competing.risk.mark = 2,
  add.intercurrent.event.mark = FALSE,
  intercurrent.event.time = list(),
  shape.intercurrent.event.mark = 1,
  size.intercurrent.event.mark = 2,
  add.quantile = FALSE,
  level.quantile = 0.5,
  panel.per.event = FALSE,
  panel.censoring = FALSE,
  panel.per.variable = FALSE,
  panel.mode = "auto",
  rows.columns.panel = NULL,
  style = "classic",
  palette = NULL,
  linewidth = 0.8,
  linetype = FALSE,
  font.family = "sans",
  font.size = 12,
  legend.position = "top",
  print.panel = FALSE,
  filename.ggsave = NULL,
  width.ggsave = 6,
  height.ggsave = 6,
  dpi.ggsave = 300,
  survfit.info = NULL,
  axis.info = NULL,
  visual.info = NULL,
  panel.info = NULL,
  style.info = NULL,
  inset.info = NULL,
  print.info = NULL,
  ggsave.info = NULL,
  ...
)

Arguments

formula_or_fit

Either a model formula or a survfit object. When a formula is supplied, the LHS must be Event(time, status) or Surv(time, status). The RHS specifies an optional stratification variable.

data

A data frame containing variables in the formula.

weights

Optional name of the weight variable in data. Weights must be nonnegative.

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

outcome.type

Character string specifying the type of time-to-event outcome. One of "survival" (Kaplan-Meier) or "competing-risk" (Aalen-Johansen). If NULL (default), the function automatically infers the outcome type from the data: if the event variable has more than two unique levels, "competing-risk" is assumed; otherwise, "survival" is used. You can also use abbreviations such as "S" or "C". An explicit "competing-risk" remains in effect when a cause is absent in the analysis data. Mixed or ambiguous inputs (e.g., c("S", "C")) trigger automatic detection based on the event coding.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

code.events

Optional specification of event/censoring codes. For single-panel calls, supply a numeric vector. For competing-risk outcomes, use c(event1, event2, censoring). For survival outcomes, a length-2 or length-3 vector is allowed: c(event, censoring) or ⁠c(event, *, censoring)⁠, where any middle element is ignored. When supplied, this argument overrides code.event1, code.event2, and code.censoring for the purpose of estimation. For panel displays (e.g. cifpanel() or when panel.per.event = TRUE or panel.censoring = TRUE), code.events may also be a list of such numeric vectors, one per panel.

error

Character string specifying the method for SEs and CIs used internally. For "survival" without weights, choose one of "greenwood" (default), "tsiatis", "if", or "fay". For "competing-risk" without weights, choose one of "delta" (default), "aalen", "if", or "fay". Weighted analysis defaults to influence-function SEs ("if"). The C++ curve engine also supports "fay", a Fay–Graubard-type correction. Supplied weights are held fixed; uncertainty from estimating a propensity score is not included.

conf.type

Character specifying the method of transformation for CIs used internally (default ⁠arcsine-square root⁠).

conf.int

Numeric two-sided level of CIs (default 0.95).

n.risk.type

Character string; one of "weighted", "unweighted", or "ess". Controls which risk set size is returned in ⁠$n.risk⁠ without affecting estimates or SEs (default "weighted").

type.y

Character string specifying the y-scale. For survival/CIF curves, "surv" implies survival probabilities and "risk" implies CIF (1-survival in simple survival settings). Specify "cumhaz" to plot cumulative hazard or "cloglog" to generate a complementary log-log plot. If NULL, a default is chosen from outcome.type or the survfit object.

label.x

Character x-axis label (default "Time").

label.y

Character y-axis label (default is chosen automatically from outcome.type and type.y, e.g. "Survival", "Cumulative incidence" or "Cumulative hazard").

label.strata

Character vector or named character vector specifying labels for strata. Names (if present) must match the (re-ordered) underlying strata levels. Note: when any of the panel modes is active (panel.per.variable = TRUE, panel.per.event = TRUE, panel.censoring = TRUE, or panel.mode = "auto" and it actually dispatches to a panel), strata labels are suppressed to avoid duplicated legends across sub-plots.

level.strata

Optional character vector giving the full set of expected strata levels. When provided, both order.strata and label.strata are validated against it before application.

order.strata

Optional character vector specifying the display order of strata in the legend/number-at-risk table. Specify the levels of strata. Levels not listed are dropped.

limits.x

Numeric length-2 vector specifying x-axis limits. If NULL, it is set from the fitted object (typically c(0, max(time))).

limits.y

Numeric length-2 vector specifying y-axis limits. If NULL, it is set to c(0, 1) for probability-type outcomes.

breaks.x

Numeric vector of x-axis breaks (default NULL).

breaks.y

Numeric vector of y-axis breaks (default NULL).

use.coord.cartesian

Logical; if TRUE, uses ggplot2::coord_cartesian() for zooming instead of changing the scale limits (default FALSE).

add.conf

Logical; if TRUE, adds a CI ribbon (via ggsurvfit::add_confidence_interval()). Default TRUE.

add.risktable

Logical; if TRUE, adds a numbers-at-risk table under the plot. Default TRUE. Note: when a panel mode is active, tables are suppressed.

add.estimate.table

Logical; if TRUE, adds a table of estimates and CIs. Default FALSE. Note: when a panel mode is active, tables are suppressed.

symbol.risk.table

Character specifying the symbol used in the risk table to denote strata: "square", "circle", or "triangle" (default "square").

font.size.risk.table

Numeric font size for texts in risk / estimate tables (default 3).

add.censor.mark

Logical; if TRUE, draws censoring marks on each curve (via ggsurvfit::add_censor_mark()). Default TRUE.

shape.censor.mark

Integer point shape used for censoring marks (default 3).

size.censor.mark

Numeric point size used for censoring marks (default 2).

add.competing.risk.mark

Logical; if TRUE, draws time marks for the competing event (event 2). If no times are supplied via competing.risk.time, the function tries to extract them automatically from the data. Default FALSE.

competing.risk.time

A named list of numeric vectors. Each name must correspond to a strata label, and its numeric vector gives the times at which the competing event occurred in that stratum. Typically left as list() and filled internally.

shape.competing.risk.mark

Integer point shape for competing-risk marks (default 16).

size.competing.risk.mark

Numeric point size for competing-risk marks (default 2).

add.intercurrent.event.mark

Logical; if TRUE, overlays user-specified intercurrent-event times per stratum. Default FALSE.

intercurrent.event.time

A named list of numeric vectors for intercurrent events (names must match strata labels).

shape.intercurrent.event.mark

Integer point shape for intercurrent-event marks (default 1).

size.intercurrent.event.mark

Numeric point size for intercurrent-event marks (default 2).

add.quantile

Logical; if TRUE, adds a quantile reference line (via ggsurvfit::add_quantile()). Default FALSE.

level.quantile

Numeric quantile level to be shown (default 0.5 for the median).

panel.per.event

Logical. Explicit panel mode. If TRUE and outcome.type == "competing-risk", cifplot() internally calls cifpanel() to display two event-specific CIFs side-by-side (event 1 and event 2) using reversed code.events. Ignored for non-competing-risk outcomes.

panel.censoring

Logical. Explicit panel mode. If TRUE and outcome.type == "survival", cifplot() internally calls cifpanel() to display KM curves for ⁠(event, censor)⁠ and ⁠(censor, event)⁠ so that censoring patterns can be inspected.

panel.per.variable

Logical. Explicit panel mode. If TRUE and the RHS of the formula has multiple covariates (e.g. ~ a + b + c), the function produces a panel where each variable in the RHS is used once as the stratification factor.

panel.mode

Character specifying Automatic panel mode. If "auto" and none of panel.per.variable, panel.per.event, panel.censoring has been set to TRUE, the function chooses a suitable panel mode automatically: (i) if the formula RHS has 2+ variables, it behaves like panel.per.variable = TRUE; (ii) otherwise, if outcome.type == "competing-risk", it behaves like panel.per.event = TRUE; (iii) otherwise, if outcome.type == "survival", it behaves like panel.censoring = TRUE. If a panel mode is explicitly specified, panel.mode is ignored.

rows.columns.panel

Optional integer vector c(nrow, ncol) controlling the layout of the panel returned by the panel modes. If NULL, an automatic layout is determined from the number of subplots.

style

Character choosing the base plot style: "classic", "bold", "framed", "grid", "gray" or "ggsurvfit" (default "classic"). Abbreviations such as "C", "B", "F", or "G" are also accepted.

palette

Optional character vector specifying the color palette to use across strata.

linewidth

Optional numeric specifying the line width of curve (default 0.8).

linetype

Optional logical using different line types of curve (default FALSE).

font.family

Character specifying the font family: "sans", "serif", or "mono" (default "sans").

font.size

Integer specifying the base font size (default 12).

legend.position

Character specifying the legend position: "top", "right", "bottom", "left", or "none" (default "top").

print.panel

Logical. When TRUE, panel displays created internally are printed automatically in interactive sessions; otherwise they are returned invisibly for further modification (default FALSE).

filename.ggsave

Character; if non-NULL, save the plot to this file.

width.ggsave

Numeric width passed to ggplot2::ggsave() (default 6).

height.ggsave

Numeric height passed to ggplot2::ggsave() (default 6).

dpi.ggsave

Numeric DPI passed to ggplot2::ggsave() (default 300).

survfit.info, axis.info, visual.info, panel.info, style.info, inset.info, print.info, ggsave.info

Internal lists used for programmatic control. Not intended for direct user input.

...

Additional arguments passed to internal helper functions.

Details

Typical use cases

Key arguments shared with cifcurve()

Key arguments for cifplot()

When panel.per.event = TRUE, two panels are created with code.events = list(c(e1, e2, c), c(e2, e1, c)), where code.events = c(e1, e2, c) is the input coding for event1, event2, and censoring. Common legend is collected by default (legend.collect = TRUE).

Numeric stratification variables are normalized automatically. Columns with fewer than nine distinct numeric values are coerced to factors; columns with nine or more distinct numeric values are split at the median into “Below median” and “Above median” strata.

Advanced control not required for typical use

The arguments below fine-tune internal estimation and figure appearance. Most users do not need to change these defaults.

Graphical layers
Argument Description Default
add.conf Add confidence interval ribbon. TRUE
add.risktable Add numbers-at-risk table below the plot. TRUE
add.estimate.table Add estimates and confidence intervals table. FALSE
symbol.risk.table Symbol for strata in risk / estimate tables "square"
font.size.risk.table Font size for texts in risk / estimate tables 3
add.censor.mark Add censoring marks. TRUE
add.competing.risk.mark Add marks for event2 of "competing-risk" outcome. FALSE
add.intercurrent.event.mark Add intercurrent event marks at user-specified times. FALSE
add.quantile Add quantile reference lines. FALSE
level.quantile Quantile level for add.quantile. 0.5
Time for marks
Argument Description
competing.risk.time Named list of numeric vectors that contains times of competing risks. Names must match strata labels. Typically created internally
intercurrent.event.time Named list of numeric vectors that contains times of intercurrent events. Names must match strata labels. Typically created by extract_time_to_event().
Appearance of marks
Argument Applies to Default
shape.censor.mark Censoring marks 3 (cross)
size.censor.mark Censoring marks 2
shape.competing.risk.mark Competing-risk marks 16 (filled circle)
size.competing.risk.mark Competing-risk marks 2
shape.intercurrent.event.mark Intercurrent marks 1 (circle)
size.intercurrent.event.mark Intercurrent marks 2
Panel display
Argument Description
panel.per.variable One panel per stratification variable
panel.per.event For "competing-risk", show CIFs of event 1 and event 2
panel.censoring For survival, show (event, censor) vs (censor, event)
panel.mode with 2+ stratification variables Behave like panel.per.variable
panel.mode with outcome.type = "competing-risk" Behave like panel.per.event
panel.mode with outcome.type = "survival" Behave like panel.censoring
Axes and legend
Argument Description Default
limits.x, limits.y Axis limits (c(min, max)) Auto
breaks.x, breaks.y Tick breaks for x and y axes Auto
use.coord.cartesian For zooming use coord_cartesian() FALSE
legend.position "top", "right", "bottom", "left", "none" "top"
Export
Argument Description Default
filename.ggsave If non-NULL, save the plot using ggsave() NULL
width.ggsave Size passed to ggsave() 6
height.ggsave Size passed to ggsave() 6
dpi.ggsave DPI passed to ggsave() 300

Notes

Value

A "cifplot" object (a list) with at least the following elements:

When a panel mode is active and print.panel = TRUE, the panel is also printed in interactive sessions.

Lifecycle

[Stable]

See Also

polyreg() for log-odds product modeling of CIFs; cifcurve() for KM/AJ estimators; cifpanel() for display of multiple CIFs; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

data(diabetes.complications)
cifplot(Event(t,epsilon) ~ fruitq,
        data = diabetes.complications,
        outcome.type="competing-risk",
        add.risktable = FALSE,
        label.y='CIF of diabetic retinopathy',
        label.x='Years from registration')


Tests for survival and cumulative incidence curves

Description

Provides a formula-based interface for log-rank, Fleming-Harrington, Gray, and augmented score tests. test = "auto" selects log-rank for survival outcomes and the augmented score test for competing-risk outcomes. The "early" and "late" presets select that same outcome-specific test with Fleming–Harrington parameters ⁠(rho, gamma) = (1, 0)⁠ and ⁠(0, 1)⁠, respectively. Analysis strata can be specified independently with strata. For augmented tests, working Aalen-Johansen distributions are estimated within exposure-by-strata.competing.risk cells, censoring distributions are estimated within strata.censor, and the closed-form augmentation is used. Setting iteration to a positive integer applies that many Scheike fixed-point refinements. Finite iterates are anchored as the closed-form score plus the change in the AIPWCC image from the seed to the refined direction, preserving the zeroth-step identity in the observed sample.

Usage

ciftest(
  formula,
  data,
  weights = NULL,
  subset.condition = NULL,
  na.action = na.omit,
  outcome.type = "auto",
  test = "auto",
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  rho = NULL,
  gamma = NULL,
  iteration = 0L,
  tolerance = NULL,
  strata = NULL,
  strata.censor = NULL,
  strata.competing.risk = NULL,
  tau = NULL,
  prob.bound = 1e-07,
  prob.truncation = NULL,
  ...
)

Arguments

formula

A two-sided formula with an Event() or Surv() response and one grouping variable on the right-hand side. Surv() responses must be right-censored.

data

A data frame containing variables in the formula.

weights

Optional numeric case weights or the name of a weight column. The standard Gray branch currently accepts integer frequency weights.

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

outcome.type

One of "auto", "competing-risk", or "survival". The aliases "C" and "S" are accepted.

test

One of "auto", "early", "late", "logrank", "gray", "score", "augmented", or "multiple". The aliases "L", "LR", and "log-rank" select log-rank; "G" selects Gray; and "A", "aug", and "augmentation" select the augmented score test. The early and late choices are outcome-specific single-direction presets. "multiple" (aliases "multi" and "m") returns ciftest_mdir() using the default directions ⁠(rho, gamma) = (2, 0), (0, 2), (0, 0)⁠. "score" uses the null score-IID variance; for competing-risk outcomes it may use censoring Kaplan–Meier strata.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

rho, gamma

Optional non-negative Fleming-Harrington weight parameters. Omitted values default to zero. They cannot be combined with the fixed "early" and "late" presets.

iteration

Non-negative integer giving the number of Scheike fixed-point refinements. 0 returns the closed-form augmented score; positive values use the closed-form-anchored AIPWCC difference.

tolerance

Optional positive convergence tolerance. NULL performs exactly the requested number of finite iterations.

strata

Optional character vector of one or more column names defining analysis strata. Multiple columns define their observed interaction. The grouping variable cannot be included. Event risk sets, null event distributions, and Fleming–Harrington weight processes are constructed separately within these strata, and their score vectors are summed. This is distinct from the two nuisance-model strata.

strata.censor

Optional character vector of one or more column names defining censoring Kaplan-Meier strata. The grouping variable may be included explicitly when group-specific censoring distributions are required.

strata.competing.risk

Optional character vector of one or more column names defining the exposure-by-stratum working Aalen-Johansen models used for the competing-risk nuisance distribution. The grouping variable must not be included because it is crossed with these strata automatically.

tau

Optional finite non-negative analysis horizon.

prob.bound

Strictly positive numerical/positivity bound. Required nuisance probabilities at or below this value produce an error rather than being silently replaced.

prob.truncation

Optional probability lower truncation strictly above prob.bound. It is applied only to positive censoring and working-survival denominators used by score and augmented tests.

...

Reserved for future extensions.

Value

An object inheriting from "ciftest" and "htest", with a test-specific subclass. An ordinary unweighted log-rank result also inherits from "survdiff" and contains a fully compatible object in survdiff. Every score-based branch returns an analysis-row by contrast matrix of individual null-score contributions in score.iid. Augmented results include score.iid.base, score.iid.censor, and score.iid.augment matrices and use their summed empirical cross-product as vcov.score. Standard Gray results retain the classical Gray covariance. If the optional standard-Gray score-IID diagnostic cannot be constructed, the Gray test is still returned; its score-IID matrices contain NA and the reason is recorded in diagnostics$score.iid.error. Positive iteration values return the requested finite-iteration score, its subject-level score matrix, anchoring diagnostics, and fixed-point diagnostics. The event-time FH process actually used by the fit is returned in diagnostics$fh.weight.process, including whether it came from the pooled or event-stratified AJ left limit or the native Gray subdistribution construction.


Build a finite-iteration time-directed Fine-Gray score

Description

iterations = 0 is intentionally handled by the closed-form caller. This function computes one or more empirical Appendix-E refinements and maps the resulting full-data direction to observed-data score contributions.

Usage

ciftest_iteration_setup(
  base,
  working,
  t,
  epsilon,
  x,
  exposure,
  weights = rep.int(1, length(t)),
  code.event1 = 1L,
  code.event2 = 2L,
  code.censoring = 0L,
  prob.bound = 1e-07,
  prob.truncation = NULL
)

Multiple-direction quadratic score test

Description

Combines several Fleming–Harrington score directions in the quadratic form proposed by Ditzhaus and Friedrich. Each component is fitted with the same outcome-specific ciftest() branch. Classical log-rank components use the joint, finite-population-corrected hypergeometric covariance, with cross-direction blocks weighted by w_r(t) * w_s(t). Classical Gray components analogously use the joint Gray (1988) covariance, including the target-event, competing-event, and censoring contributions. Score and augmented components use the cross-product of the stacked individual score contributions. The default chi-square reference uses the numerical rank of the joint covariance. This function does not perform the permutation calibration from the original two-sample survival proposal.

Usage

ciftest_mdir(
  formula,
  data,
  directions = c("early", "late", "unweighted"),
  weights = NULL,
  subset.condition = NULL,
  outcome.type = "auto",
  test = "auto",
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  iteration = 0L,
  tolerance = NULL,
  strata = NULL,
  strata.censor = NULL,
  strata.competing.risk = NULL,
  tau = NULL,
  prob.bound = 1e-07,
  prob.truncation = NULL,
  na.action = stats::na.omit
)

Arguments

formula

A two-sided formula with an Event() or Surv() response and one grouping variable on the right-hand side. Surv() responses must be right-censored.

data

A data frame containing variables in the formula.

directions

Fleming–Harrington directions. A character vector may contain "unweighted", "early", and "late". Alternatively supply a two-column numeric matrix/data frame with rho and gamma, or a named list of numeric length-two vectors. In this multiple-direction interface, the default character presets correspond to ⁠(2, 0)⁠, ⁠(0, 2)⁠, and ⁠(0, 0)⁠. The stronger early/late directions keep the default set linearly independent.

weights

Optional numeric case weights or the name of a weight column. The standard Gray branch currently accepts integer frequency weights.

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

outcome.type

One of "auto", "competing-risk", or "survival". The aliases "C" and "S" are accepted.

test

Underlying component test: "auto", "logrank", "gray", "score", or "augmented". The corresponding aliases documented for ciftest() are accepted. Put early and late choices in directions.

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing risk (default 2).

code.censoring

Integer code of censoring (default 0).

iteration

Non-negative integer giving the number of Scheike fixed-point refinements. 0 returns the closed-form augmented score; positive values use the closed-form-anchored AIPWCC difference.

tolerance

Optional positive convergence tolerance. NULL performs exactly the requested number of finite iterations.

strata

Optional character vector of one or more column names defining analysis strata. Multiple columns define their observed interaction. The grouping variable cannot be included. Event risk sets, null event distributions, and Fleming–Harrington weight processes are constructed separately within these strata, and their score vectors are summed. This is distinct from the two nuisance-model strata.

strata.censor

Optional character vector of one or more column names defining censoring Kaplan-Meier strata. The grouping variable may be included explicitly when group-specific censoring distributions are required.

strata.competing.risk

Optional character vector of one or more column names defining the exposure-by-stratum working Aalen-Johansen models used for the competing-risk nuisance distribution. The grouping variable must not be included because it is crossed with these strata automatically.

tau

Optional finite non-negative analysis horizon.

prob.bound

Strictly positive numerical/positivity bound. Required nuisance probabilities at or below this value produce an error rather than being silently replaced.

prob.truncation

Optional probability lower truncation strictly above prob.bound. It is applied only to positive censoring and working-survival denominators used by score and augmented tests.

na.action

A function specifying the action to take on missing values (default na.omit).

Value

An object inheriting from "ciftest_mdir", "ciftest", and "htest". Component fits are available in components; the unmodified individual contributions are in score.iid, and the covariance actually used by the quadratic statistic is in vcov.score.

References

Ditzhaus M, Friedrich S. More powerful logrank permutation tests for two-sample survival data. arXiv preprint (2018).


Data from a cohort study of patients with type 2 diabetes

Description

Anonymized data from a cohort study of patients with type 2 diabetes followed for ocular and macro-vascular complications.

Usage

data(diabetes.complications)

Format

A data frame with 978 observations and 19 variables:

t

Follow-up time in years.

epsilon

Event type indicator (0 = censored, 1 = diabetic retinopathy, 2 = macro-vascular complication).

fruit

Fruit intake (g/day).

fruitq

Quartile of fruit intake.

fruitq1

Binary indicator for low fruit intake.

strata

Stratum used for inverse probability of censoring weights.

age

Age at baseline (years).

sex

Sex coded as 0 = woman, 1 = man.

bmi

Body mass index at baseline.

hba1c

Hemoglobin A1c (%).

diabetes_duration

Duration of diabetes (years).

drug_oha

Indicator for oral hypoglycemic agent use.

drug_insulin

Indicator for insulin use.

sbp

Systolic blood pressure (mmHg).

ldl

Low-density lipoprotein cholesterol (mg/dL).

hdl

High-density lipoprotein cholesterol (mg/dL).

tg

Triglycerides (mg/dL).

current_smoker

Indicator for current smoking status.

alcohol_drinker

Indicator for current alcohol drinking.

ltpa

Leisure-time physical activity (METs).

Details

The variables include follow-up time, cause-specific event indicators, exposure indicators for fruit intake, censoring strata, and a set of covariates used in the package vignettes.

Source

Anonymized example data from the Japan Diabetes Complications Study. The original cohort analysis of fruit intake and incident diabetic retinopathy was reported by Tanaka S, Yoshimura Y, Kawasaki R, Kamada C, Tanaka S, Horikawa C, Ohashi Y, Araki A, Ito H, Akanuma Y, Yamada N, Yamashita H, Sone H, for the Japan Diabetes Complications Study Group. Fruit intake and incident diabetic retinopathy with type 2 diabetes. Epidemiology. 2013, 24(2), 204–211. doi:10.1097/EDE.0b013e318281725e

Examples

data(diabetes.complications)
str(diabetes.complications)

Estimate a stratified censoring Kaplan-Meier distribution

Description

Uses the package Kaplan-Meier counts, retaining both left and right limits. The default keeps the existing censoring-first convention for ciftest. With tie.order="event_first", actual failures leave before the censoring jump, consistently with observation of failures when T <= C.

Usage

estimate_censoring_km(
  t,
  epsilon,
  code.censoring = 0L,
  strata = rep.int("pooled", length(t)),
  weights = rep.int(1, length(t)),
  prob.bound = 1e-07,
  prob.truncation = NULL,
  censoring.event = epsilon == code.censoring,
  tie.order = c("censoring_first", "event_first")
)

Estimate working Aalen-Johansen distributions by exposure and stratum

Description

The package Aalen-Johansen engine is evaluated separately within every observed exposure-by-stratum cell. A second call with the two event codes exchanged supplies the competing-event cumulative incidence.

Usage

estimate_working_aj(
  t,
  epsilon,
  exposure,
  strata = rep.int("pooled", length(t)),
  weights = rep.int(1, length(t)),
  code.event1 = 1L,
  code.event2 = 2L,
  code.censoring = 0L,
  prob.bound = 1e-07,
  prob.truncation = NULL
)

Extract per-stratum event times from a formula and data

Description

Creates a list of event times that can be passed to downstream visualization or analysis functions such as competing.risk.time or intercurrent.event.time in cifplot() and cifpanel(). Event types are specified by event 1, event 2, censoring, or user-specified codes.

Usage

extract_time_to_event(
  formula,
  data,
  weights = NULL,
  subset.condition = NULL,
  na.action = na.omit,
  which.event = c("event2", "event1", "censor", "censoring", "user_specified"),
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  code.user.specified = NULL,
  read.unique.time = TRUE,
  drop.empty = TRUE
)

Arguments

formula

A model formula specifying the outcome and (optionally) strata().

data

A data frame containing variables in formula.

weights

Optional numeric case weights or the name of a weight column. Rows with missing weights are excluded consistently with curve estimation.

subset.condition

Optional expression (as a character string) defining a subset of data to analyse. Defaults to NULL.

na.action

Function to handle missing values (default: na.omit in stats).

which.event

One of "event1", "event2", "censor", "censoring", or "user_specified", indicating which event type to extract times for.

code.event1, code.event2, code.censoring

Integer codes representing the event and censoring categories. Defaults are 1, 2, and 0, respectively.

code.user.specified

When which.event = "user_specified", the integer event code to extract (e.g., 3 for an intercurrent event).

read.unique.time

Logical if TRUE, only unique and sorted time points are returned for each stratum.

drop.empty

Logical if TRUE (default), strata with no events are dropped from the returned list. Set to FALSE to retain empty strata as numeric(0) vectors (useful for diagnostics or consistent list length).

Details

This function is typically used internally by plotting and model functions, but can also be called directly to inspect the per-stratum event-time structure of a data frame.

Value

A named list of numeric vectors, where each element corresponds to a stratum and contains the event times of the selected type.

Lifecycle

[Stable]

See Also

polyreg() for log-odds product modeling of CIFs; cifcurve() for KM/AJ estimators; cifplot() for display of a CIF; cifpanel() for display of multiple CIFs; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

data(diabetes.complications)
output <- extract_time_to_event(Event(t,epsilon) ~ fruitq,
                                data = diabetes.complications,
                                which.event = "event2")
cifplot(Event(t,epsilon) ~ fruitq,
        data = diabetes.complications,
        outcome.type="competing-risk",
        add.conf=FALSE,
        add.risktable=FALSE,
        add.censor.mark=FALSE,
        add.competing.risk.mark=TRUE,
        competing.risk.time=output,
        label.y="CIF of diabetic retinopathy",
        label.x="Years from registration")

Choose a safe finite-difference step so w +/- h*delta stays >= 0

Description

Choose a safe finite-difference step so w +/- h*delta stays >= 0

Usage

fd_step_safe(w, delta, rel = 1e-06, max_tries = 20L)

Extract Mparts from a weightit object (robustly)

Description

Extract Mparts from a weightit object (robustly)

Usage

get_weightit_mparts(weightit)

Fit coherent regression models of CIFs using polytomous log odds products

Description

polyreg() fits regression models of CIFs, targeting familiar effect measures (risk ratios, odds ratios and subdistribution hazard ratios). Modeling the nuisance structure using polytomous log odds products ensures that the sum of cause-specific CIFs does not exceed one, and enables coherent modelling of the multiplicative effects.

This function follows a familiar formula–data workflow: the outcome and covariates other than the exposure are specified through a formula in nuisance.model (with Event() or survival::Surv() on the LHS), and the exposure of interest is given by a separate variable name in exposure. The fitted object contains tidy summaries of exposure effects (point estimates, SEs, CIs, and p-values) and can be summarised with summary.polyreg() or formatted with external tools such as modelsummary::modelsummary().

Usage

polyreg(
  nuisance.model,
  exposure,
  strata = NULL,
  data,
  subset.condition = NULL,
  na.action = na.omit,
  code.event1 = 1,
  code.event2 = 2,
  code.censoring = 0,
  code.exposure.ref = 0,
  effect.measure1 = "RR",
  effect.measure2 = "RR",
  time.point = NULL,
  outcome.type = "competing-risk",
  conf.int = 0.95,
  report.nuisance.parameter = FALSE,
  report.optim.convergence = FALSE,
  report.sandwich.conf = TRUE,
  report.boot.conf = NULL,
  boot.bca = FALSE,
  boot.multiplier = "rademacher",
  boot.replications = 200,
  boot.seed = 46,
  nleqslv.method = "Newton",
  optim.parameter1 = 1e-06,
  optim.parameter2 = 1e-06,
  optim.parameter3 = 100,
  optim.parameter4 = 50,
  optim.parameter5 = 50,
  optim.parameter6 = 50,
  optim.parameter7 = 1e-10,
  optim.parameter8 = 1e-06,
  optim.parameter9 = 0.001,
  optim.parameter10 = 40,
  optim.parameter11 = 1e-06,
  optim.parameter12 = 2,
  optim.parameter13 = 0.5,
  data.initial.values = NULL,
  normalize.covariate = TRUE,
  terminate.time.point = TRUE,
  prob.bound = 1e-07
)

Arguments

nuisance.model

A formula describing the outcome and nuisance covariates, excluding the exposure of interest. The LHS must be Event(time, status) or survival::Surv(time, status). Surv() responses must be right-censored.

exposure

A character string giving the name of the categorical exposure variable in data.

strata

Optional character string with the name of the stratification variable used to adjust for dependent censoring (default NULL).

data

A data frame containing the outcome, exposure and nuisance covariates referenced by nuisance.model.

subset.condition

Optional character string giving a logical condition to subset data (default NULL).

na.action

A function specifying the action to take on missing values (default na.omit).

code.event1

Integer code of the event of interest (default 1).

code.event2

Integer code of the competing event (default 2). Used for competing-risk models and when inferring the outcome type.

code.censoring

Integer code of censoring (default 0). The event codes used by the model must be distinct non-negative integers.

code.exposure.ref

Integer code identifying the reference exposure category (default 0).

effect.measure1

Character string specifying the effect measure for the primary event. Supported values are "RR", "OR" and "SHR".

effect.measure2

Character string specifying the effect measure for the competing event. Supported values are "RR", "OR" and "SHR".

time.point

Numeric time point at which the exposure effect is evaluated for time-point models. Required for "competing-risk" and "survival" outcomes.

outcome.type

Character string selecting the outcome type. Valid values are "competing-risk", "survival", "binomial", "proportional-survival", and "proportional-competing-risk". The default is "competing-risk". Fitting either competing-risk model requires observations of both event types. For "competing-risk", both types must be observed by time.point. If explicitly set to NULL, polyreg() attempts to infer the outcome type from the data: if the event variable has more than two distinct levels, "competing-risk" is assumed; otherwise, "survival" is assumed. Abbreviations such as "S" or "C" are accepted; mixed or ambiguous inputs trigger automatic detection from the event coding in data.

conf.int

Numeric two-sided level of CIs (default 0.95).

report.nuisance.parameter

Logical; if TRUE, the returned object includes estimates of the nuisance model parameters (default FALSE).

report.optim.convergence

Logical; if TRUE, optimization convergence summaries are returned (default FALSE).

report.sandwich.conf

Logical or NULL. When TRUE, CIs based on sandwich variance are computed. When FALSE, they are omitted (default TRUE). This CI is default for time-point models ("outcome.type=competing-risk", "survival" or "binomial") and is not available otherwise. For time-point survival and competing-risk models, the variance accounts for estimation of the censoring distribution within each supplied stratum.

report.boot.conf

Logical or NULL. When TRUE, bootstrap CIs are computed. When FALSE, they are omitted. If NULL, the function chooses based on outcome.type (default NULL). This CI is default for proportional models (outcome.type="proportional-competing-risk" or "proportional-survival").

boot.bca

Logical indicating the bootstrap CI method. Use TRUE for bias-corrected and accelerated intervals or FALSE for the normal approximation (default FALSE). For proportional models, normal intervals are centered on the mean bootstrap coefficient and use the requested conf.int. BCa limits are computed separately for each reported coefficient.

boot.multiplier

Character string specifying the wild bootstrap weight distribution. One of "rademacher", "mammen" or "gaussian" (default "rademacher").

boot.replications

Integer giving the number of bootstrap replications (default 200).

boot.seed

Numeric seed used for resampling of bootstrap.

nleqslv.method

Character string specifying the solver used in nleqslv(). Available choices are "Broyden" and "Newton".

optim.parameter1

Numeric tolerance for convergence of the outer loop (default 1e-6).

optim.parameter2

Numeric tolerance for convergence of the inner loop (default 1e-6).

optim.parameter3

Numeric constraint on the absolute value of parameters (default 100).

optim.parameter4

Integer maximum number of outer loop iterations (default 50).

optim.parameter5

Integer maximum number of nleqslv iterations per outer iteration (default 50).

optim.parameter6

Integer maximum number of iterations for the Levenberg-Marquardt routine (default 50).

optim.parameter7

Numeric convergence tolerance for the Levenberg-Marquardt routine (default 1e-10).

optim.parameter8

Numeric tolerance for updating the Hessian in the Levenberg-Marquardt routine (default 1e-6).

optim.parameter9

Numeric starting value for the Levenberg-Marquardt damping parameter lambda (default 1e-3).

optim.parameter10

Numeric upper bound for lambda in the Levenberg-Marquardt routine (default 40).

optim.parameter11

Numeric lower bound for lambda in the Levenberg-Marquardt routine (default 1e-6).

optim.parameter12

Numeric multiplicative decrement applied to lambda when the Levenberg-Marquardt step is unsuccessful (default 2).

optim.parameter13

Numeric multiplicative increment applied to lambda when the Levenberg-Marquardt step is successful (default 0.5).

data.initial.values

Optional data frame providing starting values for the optimization (default NULL).

normalize.covariate

Logical indicating whether covariates should be centered and scaled prior to optimization (default TRUE).

terminate.time.point

Logical indicating whether time points that contribute estimation are terminated by min of max follow-up times of each exposure level (default TRUE).

prob.bound

Numeric lower bound used to internally truncate probabilities away from 0 and 1 (default 1e-7).

Details

Overview

polyreg() implements log odds product modeling for CIFs at user-specified time points, focusing on multiplicative effects of a categorical exposure, or constant effects over time like Cox regression and Fine-Gray models. It estimates multiplicative effects such as risk ratios, odds ratios, or subdistribution hazard ratios, while ensuring that the probabilities across competing events sum to one. This is achieved through reparameterization using polytomous log odds products, which fits so-called effect-measure models and nuisance models on multiple competing events simultaneously (Tanaka and Scheike 2026). Additionally, polyreg() supports direct binomial regression for survival outcomes and the Richardson model for binomial outcomes, both of which use log odds products. With more than two exposure levels, the single-outcome model uses the generalized log odds product, the sum of log odds across exposure levels.

Key arguments

Outcome type and event status coding

The outcome.type argument must be set to:

Setting Codes Meaning
competing-risk code.event1, code.event2, code.censoring event of interest / competing event / censoring
competing-risk (default) code.event1 = 1, code.event2 = 2, code.censoring = 0 event of interest / competing event / censoring
survival code.event1, code.censoring event / censoring
survival (default) code.event1 = 1, code.censoring = 0 event / censoring
survival (ADaM-ADTTE) code.event1 = 0, code.censoring = 1 set to match ADaM convention
proportional-survival code.event1, code.censoring event / censoring
proportional-survival (default) code.event1 = 1, code.censoring = 0 event / censoring
proportional-survival (ADaM) code.event1 = 0, code.censoring = 1 set to match ADaM convention
proportional-competing-risk code.event1, code.event2, code.censoring event of interest / competing event / censoring
proportional-competing-risk (default) code.event1 = 1, code.event2 = 2, code.censoring = 0 event of interest / competing event / censoring

Effect measures for categorical exposure

Choose the effect scale for event 1 and (optionally) event 2:

Argument Applies to Choices Default
effect.measure1 event of interest "RR", "OR", "SHR" "RR"
effect.measure2 competing event "RR", "OR", "SHR" "RR"

Inference and intervals (advanced)

Argument Meaning Default
conf.int Wald-type CI level 0.95
report.sandwich.conf Sandwich variance CIs TRUE
report.boot.conf Bootstrap CIs (used by "proportional-*" types) NULL
boot.bca Use BCa intervals (else normal approximation) FALSE
boot.multiplier Method for wild bootstrap "rademacher"
boot.replications Bootstrap replications 200
boot.seed Seed for resampling 46

Optimization & solver controls (advanced)

polyreg() solves estimating equations with optional inner routines.

Argument Role Default
nleqslv.method Root solver "Newton"
optim.parameter1, optim.parameter2 Outer / inner convergence tolerances 1e-6, 1e-6
optim.parameter3 Parameter absolute bound 100
optim.parameter4 Max outer iterations 50
optim.parameter5 Max nleqslv iterations per outer 50
optim.parameter6:13 Levenberg–Marquardt controls (iterations, tolerances, lambda) see defaults

Data handling and stability

Argument Meaning Default
subset.condition Expression (as character) to subset data NULL
na.action NA handling function stats::na.omit
normalize.covariate Center/scale nuisance covariates TRUE
terminate.time.point Truncate support by exposure-wise follow-up maxima TRUE
prob.bound Truncate probabilities away from 0/1 (numerical guard) 1e-5
data.initial.values Optional starting values data frame NULL

Downstream use

polyreg() returns an object of class "polyreg" that contains regression coefficients (coef), variance-covariance matrix (vcov) and a list of event-wise tidy and glance tables (summary). Users should typically access results via the S3 methods:

For backward compatibility, components named coefficient and cov may also be present and mirror coef and vcov, respectively. The summary component can be passed to external functions such as modelsummary() for further formatting, if desired.

Reproducibility and conventions

Value

A list of class "polyreg" containing the fitted exposure effects and supporting results. Key components and methods include:

Standard S3 methods are available: coef.polyreg(), vcov.polyreg(), nobs.polyreg(), and summary.polyreg().

Lifecycle

[Experimental]

References

Tanaka S, Scheike TH. Estimating effects on cumulative incidence probabilities by direct polytomous regression and polytomous log-odds product. Biometrics. 2026, 82(3), ujag160. doi:10.1093/biomtc/ujag160

See Also

cifcurve() for KM/AJ estimators; cifplot() for display of a CIF; cifpanel() for display of multiple CIFs; ggsurvfit::ggsurvfit, patchwork::patchwork and modelsummary::modelsummary for display helpers.

Examples

data(diabetes.complications)
output <- polyreg(
  nuisance.model = Event(t, epsilon) ~ +1,
  exposure = "fruitq1",
  data = diabetes.complications,
  effect.measure1 = "RR",
  effect.measure2 = "RR",
  time.point = 8,
  outcome.type = "competing-risk"
)

coef(output)
vcov(output)
nobs(output)
summary(output)

if (requireNamespace("gtsummary", quietly = TRUE) &&
    utils::packageVersion("gtsummary") >= "2.6.1") {
  gtsummary::tbl_regression(output, exponentiate = TRUE)
  gtsummary::tbl_regression(output, exponentiate = TRUE, event = "event2")
}


Methods for polyreg objects

Description

S3 methods to extract coefficients, variance-covariance matrix, sample size, formatted summaries, and tidy/glance/augment from objects returned by polyreg().

Usage

## S3 method for class 'polyreg'
coef(object, ...)

## S3 method for class 'polyreg'
vcov(
  object,
  type = c("default", "sandwich", "bootstrap"),
  variance = NULL,
  ...
)

## S3 method for class 'polyreg'
nobs(object, ...)

## S3 method for class 'polyreg'
summary(object, ...)

## S3 method for class 'summary.polyreg'
print(x, digits = 3, ...)

effect_label.polyreg(
  x,
  event = c("event1", "event2"),
  add.time.point = TRUE,
  add.outcome = TRUE,
  add.exposure.levels = TRUE,
  add.conf = TRUE,
  add.p = TRUE,
  value.time = NULL,
  unit.time = NULL,
  digits = 2,
  p_digits = 2,
  p_cut = 0.05,
  ...
)

## S3 method for class 'polyreg'
tidy(
  x,
  event = c("event1", "event2", "both"),
  conf.int = x$conf.int,
  variance = NULL,
  exponentiate = FALSE,
  conf.level = NULL,
  ...,
  vcov = NULL,
  coef_rename = FALSE
)

## S3 method for class 'polyreg'
glance(x, event = c("event1", "event2"), ..., gof_map = NULL)

## S3 method for class 'polyreg'
augment(x, ...)

## S3 method for class 'polyreg'
tbl_regression(x, ..., event = c("event1", "event2"))

Arguments

object

A polyreg object returned by polyreg().

...

Further arguments passed to or from methods.

type

Character string; one of "default", "sandwich", or "bootstrap". When "default", the function chooses between sandwich and bootstrap variance based on the original polyreg() settings, using outcome.type, report.sandwich.conf, and report.boot.conf. (Used only by vcov.polyreg().)

variance

Explicit covariance choice, "if" or "bootstrap". NULL preserves legacy selection. Explicit choices fail if unavailable.

x

Object to be printed or summarised. Typically a "summary.polyreg" object for print.summary.polyreg(), or a "polyreg" object for tidy.polyreg(), glance.polyreg(), augment.polyreg(), and effect_label.polyreg().

digits

Number of digits to print for parameter estimates or effect measures. Used by print.summary.polyreg() and effect_label.polyreg().

event

Character string indicating which event to extract. For effect_label.polyreg() and glance.polyreg() this is one of "event1" or "event2". For tidy.polyreg() it can also be "both" to return rows for all events.

add.time.point

Logical; if TRUE, effect_label.polyreg() appends the time point to the label (e.g., “at 5 years”).

add.outcome

Logical; if TRUE, effect_label.polyreg() appends the outcome/event description (e.g., “of event 1”).

add.exposure.levels

Logical; if TRUE, effect_label.polyreg() includes the exposure level in the label (e.g., treatment group).

add.conf

Logical; if TRUE, effect_label.polyreg() includes a confidence interval in the label.

add.p

Logical; if TRUE, effect_label.polyreg() includes a p-value or thresholded p-value (e.g. p < 0.05).

value.time

Optional numeric value overriding the time point stored in the "polyreg" object when constructing labels in effect_label.polyreg().

unit.time

Optional character string giving the time unit to display in labels constructed by effect_label.polyreg(), such as "years" or "months".

p_digits

Integer; number of digits used to format p-values in effect_label.polyreg().

p_cut

Numeric threshold used by effect_label.polyreg() to decide between printing p < p_cut and an exact p-value.

conf.int

Numeric interval level for tidy.polyreg(), defaulting to the level stored in the fit. A changed level uses normal Wald intervals; stored BCa intervals require refitting to change their level. A logical value is also accepted: TRUE includes confidence limits and FALSE omits them. Use conf.level to select the level in this form.

exponentiate

Logical; exponentiate effect estimates and confidence limits for reporting. Standard errors and statistics stay on the log scale.

conf.level

Optional confidence level for the broom-compatible logical conf.int interface. Defaults to the fitted level.

vcov

Compatibility argument for modelsummary. Only NULL is supported by tidy.polyreg(). Use variance to choose the covariance estimator.

coef_rename

Compatibility argument for modelsummary. Only FALSE is supported by tidy.polyreg().

gof_map

Table formatting argument forwarded by modelsummary and ignored by glance.polyreg().

Value

See Also

polyreg() for log odds product modeling of CIFs


Evaluate a censoring Kaplan-Meier distribution

Description

Evaluate a censoring Kaplan-Meier distribution

Usage

predict_censoring_km(
  object,
  time,
  strata = rep.int("pooled", length(time)),
  side = c("left", "right"),
  use = c("used", "raw")
)

Evaluate a working Aalen-Johansen distribution

Description

Evaluate a working Aalen-Johansen distribution

Usage

predict_working_aj(
  object,
  time,
  exposure,
  strata = rep.int("pooled", length(time)),
  side = c("left", "right"),
  use = c("used", "raw")
)

Data from a prostate cancer trial in Byer & Green (1980)

Description

Anonymized data from a randomized clinical trial of prostate cancer published in Byer & Green (1980).

Usage

data(prostate)

Format

A data frame with 502 observations and 18 variables, including:

dtime

Follow-up time in months.

status

Event status ("alive", "dead - prostatic ca", "dead - other ca", "dead - heart or vascular", "dead - cerebrovascular").

rx

Treatment assignment to diethylstilbestrol (DES) or a placebo.

age

Age at baseline (years).

wt

Weight in pounds.

pf

Performance status.

hx

History of cardiovascular disease.

sbp

Systolic blood pressure.

dbp

Diastolic blood pressure.

ekg

Electrocardiogram category.

hg

Hemoglobin level.

sz

Size of the primary tumor.

sg

Stage/grade of disease.

ap

Serum acid phosphatase.

bm

Bone metastases indicator.

stage

Clinical stage.

sdate

Start date.

patno

Patient number.

Details

The dataset records follow-up for cause of death together with treatment assignment and baseline characteristics. It is used in the package documentation to illustrate stratified cumulative incidence analyses.

Source

Byer, D. P. & Green, S. B. (1980), 'Prognostic variables for survival in a randomized comparison of treatments for prostatic cancer', Bulletin du Cancer 67, 477-488

Examples

data(prostate)
head(prostate)