Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make sure to display "zero rows" when using gtsummary::tbl_hierarchical?

Tags:

r

gtsummary

I want to count serious adverse events per subject per treatment arm, and display the occurrence for each preferred term (PT) within the corresponding system organ class (SOC). For this, I take the code proposed in the cardinal template catalog for creating safety tables.

However, it drops levels of SOC and PT which are 0 for all treatment arms. Is there a way to force displaying all factor levels in the table?

Compared to the code linked above, I tried to re-assign the factor levels in the data preprocessing step, but this has no effect. It still procudes the table as shown in the link, meaning it drops "empty" factor levels. I would love to produce the same table but having all factor levels displayed with "0" in all variables. This is the code I tried


# Load packages & data -------------------------------------
library(dplyr)
library(gtsummary)

adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae

# Capture factor levels
lev_soc <- levels(adae[["AESOC"]])
lev_decod <- levels(adae[["AEDECOD"]])

# Pre-processing --------------------------------------------

adae <- adae %>%
  filter(
    # only serious adverse events
    AESER == "Y"
  ) %>%
  # Re-assign factor levels
  mutate(
    AESOC = factor(AESOC, levels = lev_soc),
    AEDECOD = factor(AEDECOD, levels = lev_decod)
  )


# Generate table ---------------------------------------------

tbl <- adae |>
  tbl_hierarchical(
    variables = c(AESOC, AEDECOD), 
    by = ARM, 
    id = USUBJID,
    denominator = adsl,
    overall_row = TRUE,
    label = "..ard_hierarchical_overall.." ~ "Any SAE"
  )
tbl
like image 659
Jessica Avatar asked Dec 14 '25 03:12

Jessica


1 Answers

The tbl_hierarchical() function, by design, removes unobserved combinations, as this is the typical need. But to get all combinations, we can merge the serious AEs table with a table containing all the AEs. After the merge, we'll have all combinations.

# Load packages & data -------------------------------------
library(dplyr, warn.conflicts = FALSE)
library(gtsummary)

adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae[1:5,]

# Pre-processing --------------------------------------------
adae_ser <- adae %>%
  # only serious adverse events
  filter(AESER == "Y")

# Generate table ---------------------------------------------
# build table of serious events
tbl_ser <- adae_ser |>
  tbl_hierarchical(
    variables = c(AESOC, AEDECOD), 
    by = ARM, 
    id = USUBJID,
    denominator = adsl,
    overall_row = TRUE,
    label = "..ard_hierarchical_overall.." ~ "Any SAE"
  )

# build table of all AEs
tbl_all <- adae |>
  tbl_hierarchical(
    variables = c(AESOC, AEDECOD), 
    id = USUBJID,
    denominator = adsl,
    overall_row = TRUE,
    label = "..ard_hierarchical_overall.." ~ "Any SAE"
  ) |> 
  # hide statistics columns (since we do not need to see these results)
  modify_column_hide(all_stat_cols())

# merge the tables 
tbl_final <-
  list(tbl_all, tbl_ser) |> 
  tbl_merge(tab_spanner = FALSE) |> 
  # the missing cells are the non-serious AEs, fill them with zeros
  modify_missing_symbol(
    symbol = "0 (0%)",
    columns = all_stat_cols(),
    rows = TRUE
  )

enter image description here Created on 2025-08-01 with reprex v2.1.1

like image 197
Daniel D. Sjoberg Avatar answered Dec 15 '25 19:12

Daniel D. Sjoberg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!