Skip to content

Commit bdbf89a

Browse files
ddsjobergona-agent
andcommitted
Fix extract_strata() stripping parentheses from strata level labels
The greedy regex gsub('.*\\(', ...) in extract_strata() was intended to strip strata() wrappers but also destroyed parentheses in factor level values, e.g. 'Drug (B)' became 'B'. Replace with targeted patterns that only strip the strata() wrapper. Fixes ddsjoberg/gtsummary#2388 Co-authored-by: Ona <no-reply@ona.com>
1 parent 7c07c87 commit bdbf89a

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# cardx 0.3.2.9001
22

3+
* Fixed bug in `extract_strata()` where parentheses in strata level labels were incorrectly stripped, e.g. `"Drug (B)"` was truncated to `"B"`. (#2388)
4+
35
* Added fix to ensure `as_card` does not error after update to `cards`
46

57
# cardx 0.3.2

R/ard_survival_survfit.R

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,14 +357,22 @@ ard_survival_survfit.data.frame <- function(x, y,
357357

358358
# process stratifying variables
359359
extract_strata <- function(x, df_stat) {
360-
x_terms <- attr(stats::terms(stats::as.formula(x$call$formula)), "term.labels")
361-
x_terms <- gsub(".*\\(", "", gsub("\\)", "", x_terms))
360+
x_terms_raw <- attr(stats::terms(stats::as.formula(x$call$formula)), "term.labels")
361+
# strip function wrappers like strata(), factor() from term labels,
362+
# extracting only the first argument (the variable name)
363+
x_terms <- sub("^\\w+\\(\\s*([^,)]+).*\\)$", "\\1", x_terms_raw)
362364
if (length(x_terms) > 0L) {
365+
# build split pattern using the raw term labels (as they appear in strata strings)
366+
# escape each term for regex, then join with | alternation
367+
escaped_terms <- vapply(x_terms_raw, function(t) {
368+
paste0("(^|, )", gsub("([()|.^$*+?{}\\[\\]\\\\])", "\\\\\\1", t, perl = TRUE), "=")
369+
}, character(1), USE.NAMES = FALSE)
370+
split_pattern <- paste(escaped_terms, collapse = "|")
371+
363372
strata_lvls <- data.frame()
364373

365374
for (i in df_stat[["strata"]]) {
366-
i <- gsub(".*\\(", "", gsub("\\)", "", i))
367-
terms_str <- strsplit(i, paste(c(paste0(x_terms, "="), paste0(", ", x_terms, "=")), collapse = "|"))[[1]]
375+
terms_str <- strsplit(i, split_pattern)[[1]]
368376
s_lvl <- terms_str[nchar(terms_str) > 0]
369377
strata_lvls <- rbind(strata_lvls, s_lvl)
370378
}

tests/testthat/test-ard_survival_survfit.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,18 @@ test_that("ard_survival_survfit() works with '=' in strata variable level labels
210210
)
211211
})
212212

213+
test_that("ard_survival_survfit() preserves parentheses in strata level labels", {
214+
lung2 <- survival::lung %>%
215+
dplyr::mutate(sex_lbl = factor(ifelse(sex == 1, "Male (M)", "Female (F)")))
216+
217+
res <- survival::survfit(survival::Surv(time, status) ~ sex_lbl, data = lung2) |>
218+
ard_survival_survfit(times = 100)
219+
220+
levels <- unique(unlist(res$group1_level))
221+
levels <- levels[!is.na(levels)]
222+
expect_setequal(as.character(levels), c("Female (F)", "Male (M)"))
223+
})
224+
213225
test_that("ard_survival_survfit() follows ard structure", {
214226
expect_silent(
215227
survival::survfit(survival::Surv(AVAL, CNSR) ~ TRTA, cards::ADTTE) |>

0 commit comments

Comments
 (0)