Search code examples
rr-markdownkablegtsummarygt

Row groups or headers in gt/gtsummary by a second variable


I am attempting to summarize count data for a variable grouped by a second variable in long (not wide) format. I would like to programmatically insert row headers or tab_row_group() based on the second variable which categorizes the primary variable using either gt or gtsummary.

library(gt)
library(gtsummary)
library(tidyverse)

# reprex data

aes <- data.frame(
  preferred_term = c("Headache", "Fatigue", "Anxiety", "Anxiety", "Headache",
                     "Contusion", "Depressed Mood", "Gait disturbance"),
  system_organ_class = c("Nervous System Disorders",
                         "General disorders and administration site conditions",
                         "Psychiatric disorders", "Psychiatric disorders",
                         "Nervous System Disorders", 
                         "Skin and subcutaneous tissue disorders",
                         "Psychiatric disorders",
                         "General disorders and administration site conditions")
)
# manual approach with gt()

left_join(
  aes %>% 
    group_by(preferred_term) %>% 
    summarize(n = n()) %>% 
    mutate(
      p = round((n / sum(n)) * 100, 1),
      n_p = paste0(n, " (", p, ")")
    ),
  aes %>% 
    distinct(),
  by = "preferred_term"
) %>% 
  arrange(system_organ_class) %>% 
  select(-c(n, p, system_organ_class)) %>% 
  gt() %>% 
  tab_row_group(
    label = "General disorders and administration site conditions", rows = 1:2
  ) %>% 
  tab_row_group(
    label = "Nervous System Disorders", rows = 3:3
  ) %>% 
  tab_row_group(
    label = "Psychiatric disorders", rows = 4:5
  ) %>% 
  tab_row_group(
    label = "Skin and subcutaneous tissue disorders", rows = 6:6
  )
# wide summary via gtsummary::tbl_summary()

aes %>%
  tbl_summary(by = system_organ_class)
# manual approach with gtsummary::tbl_summary() and gtsummary::modify_table_body()

aes %>% 
  tbl_summary(
    include = preferred_term
  ) %>%
  modify_table_body(
    mutate,
    groupname_col = case_when(
      label %in% c("Fatigue", "Gait disturbance") ~ "General disorders and administration site conditions",
      label == "Headache" ~ "Nervous System Disorders",
      label %in% c("Anxiety", "Depressed Mood") ~ "Psychiatric disorders",
      label == "Contusion" ~ "Skin and subcutaneous tissue disorders",
      TRUE ~ ""
    )
  )
# hypothetical solution
aes %>% 
  tbl_summary(
    include = preferred_term
  ) %>%
  modify_table_body(
    mutate,
# referring to corresponding class column directly
    groupname_col = .x$inputs$data$system_organ_class
  )

Solution

  • You can merge in the system organ class variable into the table body before setting it to the groupname column.

    First, create a lookup table for the system organ class:

    aes_lookup <- aes %>% 
      select(preferred_term, system_organ_class) %>% 
      unique()
    

    Then create the main tbl_summary table:

    aestab <- aes %>%
       tbl_summary(include=preferred_term)
    

    Finally, merge in the system organ class to the table body, and make it a grouping variable:

    aestab %>% 
       modify_table_body(~.x %>% 
          left_join(aes_lookup, by=c("label"="preferred_term")) %>% 
          mutate(groupname_col = replace_na(system_organ_class, ""))) 
          
    

    The replace_na part was needed to ensure that the variable label does not get assigned to a "missing" group.

    final table