Search code examples
rgtsummary

gtsummmary::modify_header() with overall column


I would like to modify the column header formatting in a {gtsummary} table with a categorical varible (two levels) and an overall column, as in With gtsummary, is it possible to have N on a separate row to the column name?. I'm having trouble figuring out the correct gtsummary variable name to access the various column names. I currently have a workaround in which I first modify the categorical levels headers, and then add the overall and modify it. However, I'm wondering if there is a better way to do this in a single modify_header line. Reprex with various attempts below.

library(gtsummary)
library(dplyr)

# Shorten trial for examples
trial <- select(trial, trt, age)

# Modify headers
trial %>%
  tbl_summary(by = trt) %>%
  modify_header(update = all_stat_cols() ~ "**{level}**<br>N = {N}") %>%
  as_kable()
Characteristic Drug A
N = 200
Drug B
N = 200
Age 46 (37, 59) 48 (39, 56)
Unknown 7 4
# Adding overall before modifying stats columns doesn't work with {level} or {label}
try(
  trial %>%
    tbl_summary(by = trt) %>%
    add_overall() %>%
    modify_header(update = all_stat_cols() ~ "**{level}**<br>N = {N}") %>%
    as_kable()
)
#> Error in eval(parse(text = text, keep.source = FALSE), envir) : 
#>   object 'level' not found

try(
  trial %>%
    tbl_summary(by = trt) %>%
    add_overall() %>%
    modify_header(update = all_stat_cols() ~ "**{label}**<br>N = {N}") %>%
    as_kable()
)
#> Error in eval(parse(text = text, keep.source = FALSE), envir) : 
#>   object 'label' not found

# Adding overall before modifying stats columns does work with plain text
trial %>%
  tbl_summary(by = trt) %>%
  add_overall() %>%
  modify_header(update = all_stat_cols() ~ "**THIS WORKS**<br>N = {N}") %>%
  as_kable()
Characteristic THIS WORKS
N = 200
THIS WORKS
N = 200
THIS WORKS
N = 200
Age 47 (38, 57) 46 (37, 59) 48 (39, 56)
Unknown 11 7 4
# And with {column} but then gives the gtsummary backend column name
trial %>%
  tbl_summary(by = trt) %>%
  add_overall() %>%
  modify_header(update = all_stat_cols() ~ "**{column}**<br>N = {N}") %>%
  as_kable()
Characteristic stat_0
N = 200
stat_1
N = 200
stat_2
N = 200
Age 47 (38, 57) 46 (37, 59) 48 (39, 56)
Unknown 11 7 4
# Adding overall after modifying stats columns does work, but need to change label separately
trial %>%
  tbl_summary(by = trt) %>%
  modify_header(update = all_stat_cols() ~ "**{level}**<br>N = {N}") %>%
  add_overall(col_label = "**Overall**<br>N = {N}") %>%
  as_kable()
Characteristic Overall
N = 200
Drug A
N = 200
Drug B
N = 200
Age 47 (38, 57) 46 (37, 59) 48 (39, 56)
Unknown 11 7 4

Created on 2021-08-20 by the reprex package (v2.0.0)


Solution

  • The issue you are running into is that all_stat_cols(), by default, selects the overall column and the other columns. Depending on whether you're assigning a label to the overall or split columns, you'll want to use slightly different syntax.

    Example below!

    library(gtsummary)
    
    tbl <-
      trial %>%
      select(trt, age) %>%
      tbl_summary(by = trt, missing = "no") %>%
      add_overall() %>%
      modify_header(
        update = list(all_stat_cols(FALSE) ~ "**{level}**<br>N = {n}",
                      stat_0 ~ "**Overall**<br>N = {N}"))
    

    enter image description here

    show_header_names(tbl)
    #> i As a usage guide, the code below re-creates the current column headers.
    #> modify_header(update = list(
    #>   label ~ "**Characteristic**",
    #>   stat_0 ~ "**Overall**<br>N = 200",
    #>   stat_1 ~ "**Drug A**<br>N = 98",
    #>   stat_2 ~ "**Drug B**<br>N = 102"
    #> ))
    #> 
    #> 
    #> Column Name   Column Header          
    #> ------------  -----------------------
    #> label         **Characteristic**     
    #> stat_0        **Overall**<br>N = 200 
    #> stat_1        **Drug A**<br>N = 98   
    #> stat_2        **Drug B**<br>N = 102
    

    Created on 2021-08-20 by the reprex package (v2.0.1)