Skip to content

tbl_strata_nested_stack strata bug #284

Description

@wzfrank

For the LBT08 template in tlg.template, we changed strata = c(PARAMCD, direction_label) to strata = c(PARAM, direction_label). This caused the values in the result table to change, which should not happen. We suspect there is an issue with the tbl_strata_nested_stack() function. Please check the below R code.

Click to expand the R code
# Load Libraries ---------------------------------------------------------------
library(NEST.TLGs)
library(tidyverse)

# Load data frames from {syntheticadam} into named list
adam_db <- syntheticadam::get_data(c("adsl", "adlb"))
# set paths for sample {citril} metadata
tlg.templates::set_citril_options()

# Get command line arguments ---------------------------------------------------
filter_abbrev <- get_cmdarg("filter", suggest_filter("t_lb_ctc"))
tlg_name <- parse_tlg_name("t_lb_ctc", filter_abbrev)
output <- get_cmdarg("output", "t_lb_ctc_GEN.docx")

# Load metadata ----------------------------------------------------------------
reporting_info <- read_reporting_info(report_event = get_reporting_event())
lopo <- read_lopo(entry = tlg_name)
read_whiskers()

# Filter and reformat data -----------------------------------------------------
adam_db <- adam_db |>
  filter_with_suffix(suffix = filter_abbrev, suffix_list = read_filters()) |>
  dunlin::reformat(
    format = extract_rules(
      format_list = read_formats()[[tlg_name]],
      rules_list = read_rules(),
      default = read_formats()[["all"]]
    )
  )

# Outline ----------------------------------------------------------------------
# LBT08: Laboratory Abnormalities Worsened from Baseline by Worst Grade
# Shows patients whose lab toxicity grade increased from baseline to post-baseline
# Stratified by lab parameter and direction of abnormality (Low/High)

# data pre-processing ----------------------------------------------------------
# Filter ADLB for on-treatment records
df_lbt08 <- adam_db$adlb |>
  filter(
    # Safety population
    SAFFL == "Y",
    # On treatment records only
    ONTRTFL == "Y"
  )

# Derive GRADDR (direction of abnormality) if not present
if (!"GRADDR" %in% names(df_lbt08)) {
  df_lbt08 <- df_lbt08 |>
    mutate(
      # Derive GRADDR: L=Low only, H=High only, B=Both
      # Based on whether low/high grade variables have non-missing values
      graddr_derived = case_when(
        !is.na(ATOXGRL) & !is.na(ATOXGRH) ~ "B",
        !is.na(ATOXGRL) ~ "L",
        !is.na(ATOXGRH) ~ "H",
        TRUE ~ NA_character_
      )
    ) |>
    rename(GRADDR = graddr_derived)
}

df_lbt08 <- df_lbt08 |>
  filter(
    # Direction of abnormality must be specified
    !is.na(GRADDR) & GRADDR != ""
  )

# Process low direction worsening - keep worst grade records
df_low <- df_lbt08 |>
  filter(
    # Filter for low direction
    GRADDR %in% c("L", "B"),
    # Keep worst grade records
    WGRLOFL == "Y"
  ) |>
  mutate(
    # Convert grades to numeric for comparison
    grade_post = as.numeric(as.character(ATOXGRL)),
    grade_bl = as.numeric(as.character(BTOXGRL)),
    # Replace NA baseline with 0 (assume normal)
    grade_bl = if_else(is.na(grade_bl), 0, grade_bl),
    # Flag if grade worsened from baseline
    worsened = grade_post > grade_bl,
    # Direction label
    direction_label = "Low"
  )

# Process high direction worsening - keep worst grade records
df_high <- df_lbt08 |>
  filter(
    # Filter for high direction
    GRADDR %in% c("H", "B"),
    # Keep worst grade records
    WGRHIFL == "Y"
  ) |>
  mutate(
    # Convert grades to numeric for comparison
    grade_post = as.numeric(as.character(ATOXGRH)),
    grade_bl = as.numeric(as.character(BTOXGRH)),
    # Replace NA baseline with 0 (assume normal)
    grade_bl = if_else(is.na(grade_bl), 0, grade_bl),
    # Flag if grade worsened from baseline
    worsened = grade_post > grade_bl,
    # Direction label
    direction_label = "High"
  )

# Combine low and high direction data
df_worsen <- bind_rows(df_low, df_high) |>
  filter(worsened) |>
  mutate(
    # Create grade factor for display
    worst_grade = factor(
      grade_post,
      levels = c(1, 2, 3, 4),
      labels = c("Grade 1", "Grade 2", "Grade 3", "Grade 4")
    ),
    # Create direction factor
    direction_label = factor(direction_label, levels = c("Low", "High"))
  )

# build LBT08 ------------------------------------------------------------------
# Create summary by parameter, direction, and grade
gts_lbt08 <-
  df_worsen |>
  tbl_strata_nested_stack(
    strata = c(PARAM, direction_label),
    .tbl_fun = ~ .x |>
      tbl_roche_summary(
        by = "TRT01A",
        include = worst_grade,
        nonmissing = "always",
        nonmissing_text = "Any",
        percent = adam_db$adsl
      ) |>
      remove_row_type(type = "header"),
    .quiet = TRUE
  ) |>
  # Update column headers
  modify_header(
    label = paste("Laboratory Test", "\n", "Direction of Abnormality", "\n", "    Highest NCI CTCAE Grade"),
    all_stat_cols() ~ "{level}  \n(N = {n})"
  ) |>
  # Remove default footnotes
  remove_footnote_header()

# extract ard ------------------------------------------------------------------
ard_lbt08 <- gather_ard(gts_lbt08)

# decorate with {citril} -------------------------------------------------------
dec_lbt08 <- gts_lbt08 |>
  decorate_tlg(
    main =
      append_filter_title(
        main = lopo$lopo_titles,
        suffix = strsplit(filter_abbrev, "_")[[1]],
        filter_list = read_filters(),
        targets = "adsl"
      ),
    sub = reporting_info$title,
    footnote = c(lopo$lopo_footnotes, reporting_info$footnote),
    sup_footnote = run_information(output),
    pagesize = "P8"
  )

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions