From c50e95fa2919e665bb32e9494e0f13f79a5e59e6 Mon Sep 17 00:00:00 2001 From: fabian-s Date: Wed, 17 Jun 2026 13:50:20 +0200 Subject: [PATCH 1/3] Prepare 0.8.0 CRAN release Consolidate NEWS, bump version 0.7.6 -> 0.8.0, and fix R CMD check NOTEs ahead of the CRAN submission (CRAN currently has 0.7.4). - NEWS.md: collapse the GitHub-only 0.7.5/0.7.6 dev sections plus the merged backend/xgboost work (#292, #293) into a single categorized 0.8.0 section; drop the duplicate Enhancements heading. - DESCRIPTION: Version 0.8.0, Date 2026-06-17. - .Rbuildignore: exclude dev/check artifacts (Rplots.pdf, Rprof.out, *.Rcheck, *.tar.gz, *.patch, *.RData, attic, agent notes) so they cannot leak into the build tarball (fixes "Non-standard files at top level" NOTE). - R/zzz.R: register gg_state_occupation() NSE column names as global variables (fixes "no visible binding" NOTE). - R/add-functions.R: qualify utils::head() in get_cif() (fixes "no visible global function" NOTE). - R/as-ped.R: document forwarded `id`/`combine` in as_ped()'s `...` instead of as orphaned @param tags, and re-home @param combine on as_ped_cr where it is a formal argument (fixes "documented arguments not in usage" NOTE). - R/sim-ic.R: add_inspections() example \dontrun -> \donttest (runs in ~2s). - man/: regenerate (also syncs previously stale Rd, e.g. the missing maintainer entry on the package help page). - cran-comments.md: refresh for 0.8.0. Local R CMD check --as-cran: 0 errors | 0 warnings | 0 notes (the only local NOTE is the machine-specific "HTML Tidy not found"). Co-Authored-By: Claude Opus 4.8 (1M context) --- .Rbuildignore | 19 +++- DESCRIPTION | 6 +- NEWS.md | 164 +++++++++++++++++++---------------- R/add-functions.R | 2 +- R/as-ped.R | 22 ++--- R/sim-ic.R | 2 +- R/zzz.R | 6 +- cran-comments.md | 41 +++++++-- man/add_cif.Rd | 5 +- man/add_inspections.Rd | 2 +- man/add_trans_prob.Rd | 2 +- man/as_ped.Rd | 20 ++--- man/as_ped_cr.Rd | 20 +++-- man/geom_hazard.Rd | 2 - man/geom_stepribbon.Rd | 2 - man/interval_censored.Rd | 9 +- man/pammtools.Rd | 1 + man/split_data.Rd | 9 +- man/split_data_multistate.Rd | 9 +- 19 files changed, 209 insertions(+), 134 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index a436fd67..afc4a512 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -24,6 +24,19 @@ ^revdep$ ^\.github$ ^CRAN-SUBMISSION$ -^\sim -^\tmp -^\.claude$ \ No newline at end of file +^sim$ +^tmp$ +^\.claude$ +^Rplots\.pdf$ +^Rprof\.out$ +## dev / agent / check artifacts (must not leak into the build tarball) +^.*\.Rcheck$ +^.*\.tar\.gz$ +^.*\.patch$ +^.*\.RData$ +^attic$ +^\.codex$ +^.*\.council.* +^codex-.* +^pr-[0-9].* +^reprex-.* \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index cab60cf1..41193566 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: pammtools Title: Piece-Wise Exponential Additive Mixed Modeling Tools for Survival Analysis -Version: 0.7.6 -Date: 2026-05-19 +Version: 0.8.0 +Date: 2026-06-17 Authors@R: c( person("Andreas", "Bender", , "andreas.bender@stat.uni-muenchen.de", role = c("aut", "cre"), comment=c(ORCID = "0000-0001-5628-8611")), person("Fabian", "Scheipl", , "fabian.scheipl@stat.uni-muenchen.de", role = c("aut"), comment = c(ORCID = "0000-0001-8172-3603")), @@ -60,6 +60,6 @@ License: MIT + file LICENSE LazyData: true URL: https://adibender.github.io/pammtools/ BugReports: https://github.com/adibender/pammtools/issues -RoxygenNote: 7.3.2 Encoding: UTF-8 Roxygen: list(markdown = TRUE) +Config/roxygen2/version: 8.0.0 diff --git a/NEWS.md b/NEWS.md index 0e989c12..be047e50 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,20 +1,39 @@ -# pammtools 0.7.6 +# pammtools 0.8.0 -## Enhancements +This release collects all changes since the last CRAN version (0.7.4), +including the previously GitHub-only 0.7.5 and 0.7.6 development versions. + +## Breaking changes +* `make_newdata()` output no longer contains internal PED columns (`tstart`, + `intlen`, `interval`, `offset`, `ped_status`). Output now contains `tend` + + `id` + user covariates (plus `cause`/`transition` for competing risks / + multi-state models). `ped_info()` output is unchanged. `intlen` is + reconstructed on demand by downstream functions (`add_cumu_hazard()`, + `add_surv_prob()`, `add_cif()`, `add_trans_prob()`) and dropped from + user-facing output. +* `add_cif()` now uses the exact closed-form integral of the cumulative + incidence function under piecewise-exponential hazards instead of the previous + left-Riemann approximation. CIF estimates from existing user code change + numerically; results are now invariant to the time grid passed to + `make_newdata()`. +* Simulation-based confidence intervals (`ci_type = "sim"`) now use type-6 + empirical quantiles instead of the `stats::quantile()` default (type 7). + Type-7 quantiles made these intervals systematically too narrow for small + `nsim` (at the default `nsim = 100` the enclosed central mass is ~93% rather + than the nominal 95%); type-6 removes this inward bias (#288). As a result, + all simulation-based CI bounds change slightly (intervals widen at both ends) + relative to versions <= 0.7.4. + +## New features * Full support for shape-constrained additive models fit with `scam::scam()` (#286): the post-processing workflow (`add_hazard()`, `add_cumu_hazard()`, `add_surv_prob()`, `add_term()`, `add_cif()`, `add_trans_prob()`, `get_cumu_coef()`, `get_cumu_eff()`, `tidy_fixed()`, `tidy_smooth()`, `gg_smooth()`, ...) now works for `scam` fits exactly as for `gam` fits, - including delta-method and simulation-based confidence intervals. All + including delta-method and simulation-based confidence intervals. The calculations correctly use the re-parametrized coefficients - (`$coefficients.t`) and their covariance (`$Vp.t`); previously, some - functions silently used the unconstrained-scale coefficients/covariance - (`coef()`/`$Vp`), which yields incorrect results for `scam` objects. - `pamm()` gained `engine = "scam"`. See the new article - ["Shape-constrained effects (scam)"](https://adibender.github.io/pammtools/articles/shape-constraints.html). - -## New features + (`$coefficients.t`) and their covariance (`$Vp.t`). `pamm()` gained + `engine = "scam"`. See the new "Shape-constrained effects (scam)" article. * Interval-censored time-to-event data are now supported via a multiple- imputation (MI) workflow. Data specified with `Surv(L, R, type = "interval2")` are detected automatically by `as_ped()`. The new `pamm_ic()` (single event) @@ -25,86 +44,77 @@ `add_cif()` gain `pamm_ic` methods that combine per-imputation posterior draws (within- plus between-imputation variance). The `iter` argument enables chained (refit-and-reimpute) imputation, recommended for sparsely inspected - data; numerically degenerate imputation chains are flagged with a warning. - `add_inspections()` turns exact simulated times (e.g. from `sim_pexp()`) into - interval-censored panel data for testing and coverage studies. - `print()`/`summary()` of a `pamm_ic` report the *pooled* fit (Rubin-combined - coefficients and covariances, median-p term tests, fraction-of-missing- - information diagnostic); the object exposes a `pooled` entry and stores the - per-imputation fits in slimmed form so memory does not scale with the number - of imputations. See the new "Interval-Censored Data" vignette. + data. `add_inspections()` turns exact simulated times (e.g. from `sim_pexp()`) + into interval-censored panel data for testing and coverage studies. + `print()`/`summary()` of a `pamm_ic` report the *pooled* (Rubin-combined) fit. + See the new "Interval-Censored Data" vignette. +* The post-processing / confidence-interval machinery is now backend-pluggable: + all `add_*()` quantities and their delta-method and simulation-based CIs are + derived from two internal S3 primitives, `get_hazard()` and `sim_hazard()`, so + an alternative estimation backend only needs to provide methods for those two. + The new "Defining a new backend: gradient boosting with xgboost" vignette + demonstrates this end-to-end (and the Bayesian vignette was reworked to use + the same unified interface). +* `gg_state_occupation()` is now exported. + +## Enhancements +* `gg_smooth()` is now fully general across univariate smooth terms: a bare + variable name selects every 1d smooth over that variable (main effect plus any + `by`-variable or factor-smooth interaction term), `terms` is optional + (defaulting to all univariate smooths), and 1d `ti()` as well as factor-smooth + interactions (`bs = "fs"`, `bs = "sz"`) are supported. Factor-indexed smooths + are drawn in a single facet with one curve per factor level, identified by a + new `level` column in the `get_terms()` output. Random-effect smooths + (`bs = "re"`, `bs = "mrf"`) and multivariate/tensor smooths are excluded + (use `gg_re()` / `gg_tensor()`). +* `add_cif()` now supports arbitrary time points in `make_newdata()` (parity + with `add_cumu_hazard()`); missing breakpoints are inserted internally so CIF + estimates are independent of the chosen prediction grid. +* `add_surv_prob()`, `add_cif()`, `add_trans_prob()` and `add_cumu_hazard()` now + include plotting boundary rows at `tend = 0` (or the selected `time_var`). + Boundary values are set to their known limits, `S(0) = 1`, `CIF(0) = 0`, + off-diagonal transition probabilities `P_rs(0) = 0`, and `cumu_hazard = 0`, + with collapsed confidence-interval bounds when requested. Boundary rows are + added only for continuous-time models (`gam`/`scam`/`pamm`). +* Simulation-based CIs now draw a single shared posterior coefficient sample + across groups (consistent with `add_cif()` / `add_trans_ci()`); single-group + results are unchanged. +* `get_trans_prob()` now supports non-integer (categorical) state labels + (e.g. `"healthy->ill"`) in addition to integer-coded transitions. +* Transition probability calculation is faster due to a base R refactor. +* `expand_df()` preserves the `cause` column when `make_newdata()` is called with + only `tend` and `cause`, fixing a competing-risks edge case. +* `predictSurvProb.pamm()` now respects non-default `id` column names and works + when `trafo_args` are not attached to the fitted object. ## Bug fixes -* Simulation-based confidence intervals (`ci_type = "sim"` in `add_hazard()`, - `add_cumu_hazard()`, `add_surv_prob()`, as well as `add_cif()`, - `add_trans_prob()`/`add_trans_ci()` and the cumulative hazard differences - in `get_cumu_coef()`) now use type-6 empirical quantiles instead of the - `stats::quantile()` default (type 7). Type-7 quantiles made these intervals - systematically too narrow for small `nsim`: at the default `nsim = 100`, - the expected central mass of the draws enclosed by the bounds is ~93% - instead of the nominal 95%. Type-6 quantiles remove this systematic - inward bias (#288). As a consequence, all simulation-based CI bounds - change slightly (intervals widen at both ends) relative to versions - <= 0.7.5. -* `add_trans_prob()` and `add_trans_ci()` no longer require the input data to - be pre-sorted; the internal `arrange` call is now handled automatically, - fixing the user-facing sorting dependency reported in #255 and related to - #227. +* `add_trans_prob()` and `add_trans_ci()` no longer require the input data to be + pre-sorted (#255, related to #227). * Fixed transition probability matrix dimensions when transitions start from state 0 (off-by-one in state indexing). * `add_trans_prob()` / `add_trans_ci()` / `get_trans_prob()` now consistently - thread `time_var` and `interval_length`, removing hardcoded `tend` paths and - fixing argument forwarding when `add_trans_prob()` calls `add_cumu_hazard()` - with nonstandard column names. + thread `time_var` and `interval_length`, fixing argument forwarding for + nonstandard column names. * `add_counterfactual_transitions()` now fully honors `from_col`, `to_col`, and `transition_col`. -* `get_trans_prob()` now supports non-integer (categorical) state labels - (e.g. `"healthy->ill"`) in addition to integer-coded transitions. * `gg_smooth()` / `get_terms()` now select smooth terms via the model's `mgcv` smooth metadata instead of unanchored `grep()`, fixing two errors reported in - #283: passing a variable name matched by several smooths (e.g. `terms = "tend"` - in a time-varying-effects model) no longer fails with - `` `eff` must be size 100 or 1 ``, and factor terms no longer trigger - `'range' not meaningful for factors`. Names that match no smooth (e.g. - parametric factor effects) are now skipped with a warning rather than erroring. - -## Enhancements -* `gg_smooth()` is now fully general across univariate smooth terms: a bare - variable name selects every 1d smooth over that variable (main effect plus any - `by`-variable or factor-smooth interaction term), `terms` is optional - (defaulting to all univariate smooths), and 1d `ti()` as well as factor-smooth - interactions (`bs = "fs"`, `bs = "sz"`) are supported. Factor-indexed smooths - are drawn in a single facet with one coloured/filled curve per factor level, - identified by a new `level` column in the `get_terms()` output. Random-effect - smooths (`bs = "re"`, `bs = "mrf"`) and multivariate/tensor smooths are - excluded (use `gg_re()` / `gg_tensor()`). -* Transition probability calculation is faster due to a base R refactor - (previously used dplyr internally). -* `gg_state_occupation()` is now exported. Dead parameters `group_labels` and - `nrow` have been removed; user-supplied `ncol` is now respected. -* `add_surv_prob()`, `add_cif()`, and `add_trans_prob()` now include plotting - boundary rows at `tend = 0` (or the selected `time_var`). Boundary values are - set to their known limits, `S(0) = 1`, `CIF(0) = 0`, and off-diagonal - transition probabilities `P_rs(0) = 0`, with collapsed confidence interval - bounds when requested. `add_cumu_hazard()` keeps the original prediction grid. - -# pammtools 0.7.5 - -## Breaking changes -* `make_newdata()` output no longer contains internal PED columns (`tstart`, `intlen`, `interval`, `offset`, `ped_status`). Output now contains `tend` + `id` + user covariates (plus `cause`/`transition` for competing risks / multi-state models). `ped_info()` output is unchanged. -* `intlen` is now reconstructed on demand by downstream functions (`add_cumu_hazard`, `add_surv_prob`, `add_cif`, `add_trans_prob`) via the new internal helper `reconstruct_intlen()`, and dropped from user-facing output. -* `add_cif()` now uses the exact closed-form integral of the cumulative incidence function under piecewise-exponential hazards (`(h_j / Σh) · S(t_{i-1}) · (1 - exp(-Σh · Δt))`) instead of the previous left-Riemann approximation. CIF estimates from existing user code will change numerically; results are now invariant to the time grid passed to `make_newdata()`. - -## Enhancements -* `add_cif()` now supports arbitrary time points in `make_newdata()` (parity with `add_cumu_hazard()`); missing breakpoints are inserted internally so CIF estimates are independent of the chosen prediction grid. -* `expand_df()` preserves the `cause` column when `make_newdata()` is called with only `tend` and `cause`, fixing a competing-risks edge case. -* `predictSurvProb.pamm()` now respects non-default `id` column names and works when `trafo_args` are not attached to the fitted object. + #283 (variable names matched by several smooths, and factor terms). Names that + match no smooth are skipped with a warning rather than erroring. +* Fixed CIF cause mislabeling under non-alphabetical factor levels. +* Fixed interval-censored pooling regressions (backend-aware prediction, + boundary rows, and a survival-probability length mismatch). +* Registered the `.glm`/`.pamm` methods for the internal + `warn_about_new_time_points()` generic (previously "no applicable method"). +* Pooled `pamm_ic` adders now warn when given under-grouped `newdata`. ## Deprecations -* The `trafo_args` argument of `pamm()` is deprecated; convert data with `as_ped()` before calling `pamm()`. +* The `trafo_args` argument of `pamm()` is deprecated; convert data with + `as_ped()` before calling `pamm()`. ## Documentation -* Added derivation of the piecewise-exponential CIF integral to the competing-risks vignette. +* Added derivation of the piecewise-exponential CIF integral to the + competing-risks vignette. # pammtools 0.7.4 diff --git a/R/add-functions.R b/R/add-functions.R index af7b8a0d..2f267e10 100644 --- a/R/add-functions.R +++ b/R/add-functions.R @@ -1199,7 +1199,7 @@ get_cif.default <- function( # dCIF_k = (h_k / h.) * S(t-) * (1 - exp(-h. * dt)), S via all-cause hazard. cif_from_hazards <- function(haz_by_cause) { total <- Reduce(`+`, haz_by_cause) - surv <- c(1, head(exp(-cumsum(total * dt)), -1)) + surv <- c(1, utils::head(exp(-cumsum(total * dt)), -1)) incr <- ifelse( total > 0, (haz_by_cause[[cause_data]] / total) * surv * (1 - exp(-total * dt)), diff --git a/R/as-ped.R b/R/as-ped.R index 99f00f5c..2a9afe50 100644 --- a/R/as-ped.R +++ b/R/as-ped.R @@ -72,15 +72,6 @@ #' \code{formula} for concurrent and/or cumulative effects. #' @param censor_code Specifies the value of the status variable that indicates #' censoring. Often this will be \code{0}, which is the default. -#' @param combine Logical. Only relevant for competing risks data. If -#' \code{TRUE} (the default), cause-specific data sets are stacked into a -#' single data frame with an additional \code{cause} column, using split points -#' common to all event types. If \code{FALSE}, a list of cause-specific data -#' sets is returned. See the -#' \href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} -#' vignette for details. -#' @param id Character string. Name of the subject identifier variable in -#' \code{data}. #' @param transition Character string. Name of the column in \code{data} that #' identifies the transition type in multi-state models. When supplied, #' \code{as_ped} performs the multi-state PED transformation, stacking @@ -89,7 +80,14 @@ #' last transition) or \code{"calendar"} (time since study entry, not reset #' after each transition). #' @param ... Further arguments passed to the \code{data.frame} method and -#' eventually to \code{\link[survival]{survSplit}}. +#' eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +#' (character string) sets the name of the subject identifier variable in +#' \code{data}, and, for competing risks data, \code{combine} (logical, default +#' \code{TRUE}) controls whether cause-specific data sets are stacked into a +#' single data frame with an additional \code{cause} column (\code{TRUE}) or +#' returned as a list of cause-specific data sets (\code{FALSE}); see the +#' \href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +#' vignette for details. #' @importFrom Formula Formula #' @examples #' # Standard single-event transformation @@ -368,6 +366,10 @@ as_ped.pamm <- function(data, newdata, ...) { #' Competing risks trafo #' #' @inherit as_ped +#' @param combine Logical. If \code{TRUE} (the default), cause-specific data +#' sets are stacked into a single data frame with an additional \code{cause} +#' column, using split points common to all event types. If \code{FALSE}, a +#' list of cause-specific data sets is returned. #' @importFrom rlang .env #' #' @keywords internal diff --git a/R/sim-ic.R b/R/sim-ic.R index 7247c899..90aec157 100644 --- a/R/sim-ic.R +++ b/R/sim-ic.R @@ -40,7 +40,7 @@ #' @seealso \code{\link{pamm_ic}}, \code{\link{sim_pexp}} #' @importFrom stats rexp runif #' @examples -#' \dontrun{ +#' \donttest{ #' set.seed(1) #' df <- data.frame(x = runif(100, -1, 1)) #' sdf <- sim_pexp(~ -2 + 0.4 * x, df, cut = seq(0, 10, by = 0.5)) diff --git a/R/zzz.R b/R/zzz.R index 36b10dff..5c2d0e60 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -12,7 +12,11 @@ } if (getRversion() >= "2.5.1") { - utils::globalVariables(c(".", "id")) + utils::globalVariables(c( + ".", "id", + # NSE column names used in gg_state_occupation() + "df_long", "prob", "state", "time", "trans_prob_matrix" + )) } invisible() } diff --git a/cran-comments.md b/cran-comments.md index 6458b142..d8b45caa 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,12 +1,43 @@ -## Test environments -* Release and dev for linux, mac and windows +# pammtools 0.8.0 + +This is a feature release. It supersedes the GitHub-only 0.7.5 and 0.7.6 +development versions; the CRAN-published version is 0.7.4. ## R CMD check results 0 errors | 0 warnings | 0 notes +Checked locally with `R CMD check --as-cran` (including `--run-donttest` and the +PDF manual). The only local NOTE is "HTML Tidy not found", which is specific to +the local machine (no `tidy` binary installed) and does not occur on CRAN's +check infrastructure. + +## Test environments + +* local: Linux Mint 22.1 (Ubuntu 24.04 base), R 4.6.0 +* (recommended before upload: win-builder R-devel/R-release and R-hub + linux / macos / windows / nosuggests) + +## Major changes since 0.7.4 + +* New `scam` estimation engine for shape-constrained PAMMs (`pamm(engine = + "scam")`). +* Interval-censored data support via a multiple-imputation workflow + (`pamm_ic()`, `pamm_ic_cr()`, `add_inspections()`). +* The post-processing / confidence-interval machinery is now backend-pluggable + (internal `get_hazard()`/`sim_hazard()` S3 seam), demonstrated by a new + gradient-boosting (xgboost) vignette. +* Breaking change: `make_newdata()` output no longer contains internal PED + columns; `add_cif()` now uses an exact closed-form CIF integral; simulation + CIs now use type-6 quantiles. See NEWS.md for the full, categorized list. + ## Reverse dependencies -No problems. -## Comments -Adds multi-state support +Reverse dependencies on CRAN: adjustedCurves, autoReg, contsurvplot, KMunicate, +relsurv, robber, weightedsurv (pammtools is a Suggested dependency for all). + + + diff --git a/man/add_cif.Rd b/man/add_cif.Rd index 90cf1a9a..260148ef 100644 --- a/man/add_cif.Rd +++ b/man/add_cif.Rd @@ -55,10 +55,7 @@ the data set? Defaults to \code{FALSE}. If \code{TRUE}, columns with names \item{alpha}{Significance level for pooled confidence intervals.} -\item{nsim}{Total number of pooled posterior draws used for the interval. -For simulation-based intervals, the bounds are empirical type-6 quantiles of -the \code{nsim} draws; larger values of \code{nsim} yield more stable interval -bounds.} +\item{nsim}{Total number of pooled posterior draws used for the interval.} \item{cause_var}{Character. Column name of the 'cause' variable.} diff --git a/man/add_inspections.Rd b/man/add_inspections.Rd index 1dca467a..bc979592 100644 --- a/man/add_inspections.Rd +++ b/man/add_inspections.Rd @@ -69,7 +69,7 @@ and the first positive inspection. The exact time is retained (by default in column \code{true_time}) so that coverage can be scored against the truth. } \examples{ -\dontrun{ +\donttest{ set.seed(1) df <- data.frame(x = runif(100, -1, 1)) sdf <- sim_pexp(~ -2 + 0.4 * x, df, cut = seq(0, 10, by = 0.5)) diff --git a/man/add_trans_prob.Rd b/man/add_trans_prob.Rd index 317da698..68604584 100644 --- a/man/add_trans_prob.Rd +++ b/man/add_trans_prob.Rd @@ -72,7 +72,7 @@ requested, \code{trans_lower = trans_upper = 0}. If an interval-length column is present, it is set to \code{0} on the boundary row. } \examples{ -\dontshow{if (require("mstate")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +\dontshow{if (require("mstate")) withAutoprint(\{ # examplesIf} data("prothr", package = "mstate") prothr <- prothr |> mutate(transition = as.factor(paste0(from, "->", to)) diff --git a/man/as_ped.Rd b/man/as_ped.Rd index 14893222..5fafaa88 100644 --- a/man/as_ped.Rd +++ b/man/as_ped.Rd @@ -63,7 +63,14 @@ while the second (and potentially further data frames) contain information on time-dependent covariates and the times at which they have been observed.} \item{...}{Further arguments passed to the \code{data.frame} method and -eventually to \code{\link[survival]{survSplit}}.} +eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +(character string) sets the name of the subject identifier variable in +\code{data}, and, for competing risks data, \code{combine} (logical, default +\code{TRUE}) controls whether cause-specific data sets are stacked into a +single data frame with an additional \code{cause} column (\code{TRUE}) or +returned as a list of cause-specific data sets (\code{FALSE}); see the +\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +vignette for details.} \item{formula}{A two sided formula with a \code{\link[survival]{Surv}} object on the left-hand-side and covariate specification on the right-hand-side (RHS). @@ -100,17 +107,6 @@ after each transition).} \item{newdata}{A new data set (\code{data.frame}) that contains the same variables that were used to create the PED object (\code{data}).} - -\item{combine}{Logical. Only relevant for competing risks data. If -\code{TRUE} (the default), cause-specific data sets are stacked into a -single data frame with an additional \code{cause} column, using split points -common to all event types. If \code{FALSE}, a list of cause-specific data -sets is returned. See the -\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} -vignette for details.} - -\item{id}{Character string. Name of the subject identifier variable in -\code{data}.} } \value{ For standard and left-truncated data, a data frame of class diff --git a/man/as_ped_cr.Rd b/man/as_ped_cr.Rd index ac0ec558..16144c3e 100644 --- a/man/as_ped_cr.Rd +++ b/man/as_ped_cr.Rd @@ -44,16 +44,20 @@ administratively censored at \code{max_time}.} \item{censor_code}{Specifies the value of the status variable that indicates censoring. Often this will be \code{0}, which is the default.} -\item{combine}{Logical. Only relevant for competing risks data. If -\code{TRUE} (the default), cause-specific data sets are stacked into a -single data frame with an additional \code{cause} column, using split points -common to all event types. If \code{FALSE}, a list of cause-specific data -sets is returned. See the -\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} -vignette for details.} +\item{combine}{Logical. If \code{TRUE} (the default), cause-specific data +sets are stacked into a single data frame with an additional \code{cause} +column, using split points common to all event types. If \code{FALSE}, a +list of cause-specific data sets is returned.} \item{...}{Further arguments passed to the \code{data.frame} method and -eventually to \code{\link[survival]{survSplit}}.} +eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +(character string) sets the name of the subject identifier variable in +\code{data}, and, for competing risks data, \code{combine} (logical, default +\code{TRUE}) controls whether cause-specific data sets are stacked into a +single data frame with an additional \code{cause} column (\code{TRUE}) or +returned as a list of cause-specific data sets (\code{FALSE}); see the +\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +vignette for details.} } \value{ For standard and left-truncated data, a data frame of class diff --git a/man/geom_hazard.Rd b/man/geom_hazard.Rd index 4b10fdb3..881a62b7 100644 --- a/man/geom_hazard.Rd +++ b/man/geom_hazard.Rd @@ -1,6 +1,5 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/geom-hazard.R -\docType{data} \name{geom_hazard} \alias{geom_hazard} \alias{GeomHazard} @@ -175,4 +174,3 @@ ggplot(ndf, aes(x = tend, y = surv_prob)) + \code{\link[ggplot2]{geom_line}}, \code{\link[ggplot2]{geom_step}}. } -\keyword{datasets} diff --git a/man/geom_stepribbon.Rd b/man/geom_stepribbon.Rd index c03c8478..3b7bf7bf 100644 --- a/man/geom_stepribbon.Rd +++ b/man/geom_stepribbon.Rd @@ -1,6 +1,5 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ggplot-extensions.R -\docType{data} \name{geom_stepribbon} \alias{geom_stepribbon} \alias{GeomStepribbon} @@ -132,4 +131,3 @@ h + geom_ribbon(aes(ymin = level - 1, ymax = level + 1), fill = "grey70") + \seealso{ \code{\link[ggplot2]{geom_ribbon}} \code{geom_stepribbon} } -\keyword{datasets} diff --git a/man/interval_censored.Rd b/man/interval_censored.Rd index a6b1134a..5bc84f3b 100644 --- a/man/interval_censored.Rd +++ b/man/interval_censored.Rd @@ -48,7 +48,14 @@ Ignored for exact and right-censored rows.} \item{warn}{Logical; emit a one-time warning when rows are dropped.} \item{...}{Further arguments passed to the \code{data.frame} method and -eventually to \code{\link[survival]{survSplit}}.} +eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +(character string) sets the name of the subject identifier variable in +\code{data}, and, for competing risks data, \code{combine} (logical, default +\code{TRUE}) controls whether cause-specific data sets are stacked into a +single data frame with an additional \code{cause} column (\code{TRUE}) or +returned as a list of cause-specific data sets (\code{FALSE}); see the +\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +vignette for details.} } \description{ Interval-censored (IC) data record the event time of subject \eqn{i} only up diff --git a/man/pammtools.Rd b/man/pammtools.Rd index 6f8803c3..5b82b944 100644 --- a/man/pammtools.Rd +++ b/man/pammtools.Rd @@ -73,6 +73,7 @@ Useful links: Authors: \itemize{ + \item Andreas Bender \email{andreas.bender@stat.uni-muenchen.de} (\href{https://orcid.org/0000-0001-5628-8611}{ORCID}) \item Fabian Scheipl \email{fabian.scheipl@stat.uni-muenchen.de} (\href{https://orcid.org/0000-0001-8172-3603}{ORCID}) \item Johannes Piller \email{johannes.piller@lmu.de} (\href{https://orcid.org/0009-0008-3010-9556}{ORCID}) \item Philipp Kopper \email{philipp.kopper@stat.uni-muenchen.de} (\href{https://orcid.org/0000-0002-5037-7135}{ORCID}) diff --git a/man/split_data.Rd b/man/split_data.Rd index f389bc77..f1047d14 100644 --- a/man/split_data.Rd +++ b/man/split_data.Rd @@ -42,7 +42,14 @@ Defaults to \code{FALSE}, but is sometimes set to \code{TRUE}, e.g., in case of multi-state models with back transitions.} \item{...}{Further arguments passed to the \code{data.frame} method and -eventually to \code{\link[survival]{survSplit}}.} +eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +(character string) sets the name of the subject identifier variable in +\code{data}, and, for competing risks data, \code{combine} (logical, default +\code{TRUE}) controls whether cause-specific data sets are stacked into a +single data frame with an additional \code{cause} column (\code{TRUE}) or +returned as a list of cause-specific data sets (\code{FALSE}); see the +\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +vignette for details.} } \description{ Function to transform data without time-dependent covariates into piece-wise diff --git a/man/split_data_multistate.Rd b/man/split_data_multistate.Rd index 399795a9..a97f454d 100644 --- a/man/split_data_multistate.Rd +++ b/man/split_data_multistate.Rd @@ -50,7 +50,14 @@ administratively censored at \code{max_time}.} Defaults to \code{"gaptime"}.} \item{...}{Further arguments passed to the \code{data.frame} method and -eventually to \code{\link[survival]{survSplit}}.} +eventually to \code{\link[survival]{survSplit}}. Notably, \code{id} +(character string) sets the name of the subject identifier variable in +\code{data}, and, for competing risks data, \code{combine} (logical, default +\code{TRUE}) controls whether cause-specific data sets are stacked into a +single data frame with an additional \code{cause} column (\code{TRUE}) or +returned as a list of cause-specific data sets (\code{FALSE}); see the +\href{https://adibender.github.io/pammtools/articles/competing-risks.html}{competing-risks} +vignette for details.} } \description{ Currently, the input data must be in start-stop notation for each spell and From 9193c3f92bb04caf02e90dc67e3a30ef194682e4 Mon Sep 17 00:00:00 2001 From: fabian-s Date: Wed, 17 Jun 2026 14:12:41 +0200 Subject: [PATCH 2/3] Remove duplicate gg_state_occupation(); use .data pronoun for NSE gg_state_occupation() was defined identically in two files; R/ggplot-extensions.R won by source-collation order, leaving R/gg_state_occupation.R as dead code (and stale: it still carried the removed group_labels/nrow parameters). Delete the dead file. Address the "no visible binding for global variable" NOTE at the source by referencing NSE column names through the .data pronoun / tidyselect strings in the live gg_state_occupation() (trans_prob_matrix, df_long, time, prob, state), instead of widening the package-wide utils::globalVariables() allowlist with generic names. Revert zzz.R to the minimal c(".", "id") set. Local R CMD check --as-cran: 0 errors | 0 warnings | 0 notes (only the machine-specific "HTML Tidy not found" NOTE remains). Co-Authored-By: Claude Opus 4.8 (1M context) --- R/gg_state_occupation.R | 91 ----------------------------------------- R/ggplot-extensions.R | 10 ++--- R/zzz.R | 6 +-- 3 files changed, 6 insertions(+), 101 deletions(-) delete mode 100644 R/gg_state_occupation.R diff --git a/R/gg_state_occupation.R b/R/gg_state_occupation.R deleted file mode 100644 index 1ec619ff..00000000 --- a/R/gg_state_occupation.R +++ /dev/null @@ -1,91 +0,0 @@ -gg_state_occupation <- function( - newdata, - init_state, - group_var = NULL, - group_labels = NULL, - time_var = "tend", - ncol = NULL, - nrow = NULL - ) { - # newdata: your data object with attributes(newdata)$matrix - # group_var: column name to facet by, e.g., "treat" - # init_state: numeric vector for initial state, e.g., c(0,1,0,0) - - # Extract attribute matrix - mat_df <- attributes(newdata)$matrix - time_var <- sym(time_var) - - labels <- attr(newdata[[group_var]], "labels") - ncol <- length(unique(newdata[[group_var]])) - if (!is.null(labels)) { - newdata[[group_var]] <- factor( - newdata[[group_var]], - levels = names(labels), - labels = labels - ) - } - - if (!is.null(group_var)) { - # Iterate over groups - df_all <- mat_df %>% - mutate( - df_long = map(trans_prob_matrix, function(x) { - # x is a 4 × 4 × T array for ONE group - - res <- apply(x, 3, function(mat) init_state %*% mat) - - df <- as.data.frame(t(res)) - colnames(df) <- paste0("state_", seq_len(ncol(df))) - df$time <- unique(sort(newdata |> dplyr::pull(time_var))) - - df |> - pivot_longer( - cols = starts_with("state_"), - names_to = "state", - values_to = "prob" - ) - }) - ) %>% - select(-trans_prob_matrix) %>% - unnest(df_long) - - # plot - p <- ggplot(df_all, aes(x = time, y = prob, fill = state)) + - geom_area(color = "black", alpha = 0.8) + - facet_wrap(vars(.data[[group_var]]), ncol = ncol) + - labs( - x = "Time", - y = "State occupation probability", - fill = "State" - ) + - theme_minimal() - } else { - # process without grouping - x <- mat_df$trans_prob_matrix[[1]] # assume single matrix - res <- apply(x, 3, function(mat) init_state %*% mat) - df_all <- as.data.frame(t(res)) - colnames(df_all) <- paste0("state_", seq_len(ncol(df_all))) - df_all$time <- unique(sort(newdata |> dplyr::pull(time_var))) - - df_all <- df_all |> pivot_longer( - cols = starts_with("state_"), - names_to = "state", - values_to = "prob" - ) - - p <- ggplot(df_all, aes(x = time, y = prob, fill = state)) + - geom_area(color = "black", alpha = 0.8) + - labs( - x = "Time", - y = "State occupation probability", - fill = "State" - ) + - theme_minimal() - } - - return(p) - -} - -# Example usage: -# gg_state_occupation(newdata, group_var = "treat", init_state = c(0,1,0,0)) \ No newline at end of file diff --git a/R/ggplot-extensions.R b/R/ggplot-extensions.R index 2bf1f3fe..a2f29ef6 100644 --- a/R/ggplot-extensions.R +++ b/R/ggplot-extensions.R @@ -166,7 +166,7 @@ gg_state_occupation <- function( # Iterate over groups df_all <- mat_df %>% mutate( - df_long = map(trans_prob_matrix, function(x) { + df_long = map(.data[["trans_prob_matrix"]], function(x) { # x is a 4 × 4 × T array for ONE group res <- apply(x, 3, function(mat) init_state %*% mat) @@ -183,11 +183,11 @@ gg_state_occupation <- function( ) }) ) %>% - select(-trans_prob_matrix) %>% - unnest(df_long) + select(-dplyr::all_of("trans_prob_matrix")) %>% + unnest(cols = "df_long") # plot - p <- ggplot(df_all, aes(x = time, y = prob, fill = state)) + + p <- ggplot(df_all, aes(x = .data[["time"]], y = .data[["prob"]], fill = .data[["state"]])) + geom_area(color = "black", alpha = 0.8) + facet_wrap(vars(.data[[group_var]]), ncol = ncol) + labs( @@ -210,7 +210,7 @@ gg_state_occupation <- function( values_to = "prob" ) - p <- ggplot(df_all, aes(x = time, y = prob, fill = state)) + + p <- ggplot(df_all, aes(x = .data[["time"]], y = .data[["prob"]], fill = .data[["state"]])) + geom_area(color = "black", alpha = 0.8) + labs( x = "Time", diff --git a/R/zzz.R b/R/zzz.R index 5c2d0e60..36b10dff 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -12,11 +12,7 @@ } if (getRversion() >= "2.5.1") { - utils::globalVariables(c( - ".", "id", - # NSE column names used in gg_state_occupation() - "df_long", "prob", "state", "time", "trans_prob_matrix" - )) + utils::globalVariables(c(".", "id")) } invisible() } From 1f4f73526fb2643b46f94d5d836804bd50f6f6e3 Mon Sep 17 00:00:00 2001 From: fabian-s Date: Wed, 17 Jun 2026 17:44:28 +0200 Subject: [PATCH 3/3] cran-comments: record clean revdep results (0 new problems, 7 pkgs) Co-Authored-By: Claude Opus 4.8 (1M context) --- cran-comments.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/cran-comments.md b/cran-comments.md index d8b45caa..c0a9c978 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -33,11 +33,10 @@ check infrastructure. ## Reverse dependencies -Reverse dependencies on CRAN: adjustedCurves, autoReg, contsurvplot, KMunicate, -relsurv, robber, weightedsurv (pammtools is a Suggested dependency for all). - - - +We checked all 7 reverse dependencies (adjustedCurves, autoReg, contsurvplot, +KMunicate, relsurv, robber, weightedsurv; pammtools is a Suggested dependency +for all), comparing R CMD check results across the CRAN (0.7.4) and dev (0.8.0) +versions with `revdepcheck::revdep_check()`. + +* 0 new problems +* 0 packages failed to check