--- title: "Table Styling and Formatting" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Table Styling and Formatting} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) options(gtsummary.print_engine = "gt") ``` ```{r setup} #| eval: false library(sumExtras) library(gtsummary) library(dplyr) library(gt) use_jama_theme() ``` ```{r setup2} #| echo: false #| message: false #| warning: false library(sumExtras) library(gtsummary) library(dplyr) library(gt) use_jama_theme() ``` ## Group Headers `gtsummary::add_variable_group_header()` creates section headers in your table. `{sumExtras}` provides functions to style them. ```{r} trial |> select(age, marker, grade, stage, response, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Demographics", variables = age ) |> add_variable_group_header( header = "Clinical Measures", variables = marker:response ) ``` The headers are there, but they don't stand out. That's where `add_group_styling()` comes in. ## `add_group_styling()` Adds bold and/or italic formatting to group headers. Also restores left-justified variable label indentation that `add_variable_group_header()` changes. :::::: {style="display: flex; gap: 15px; margin-bottom: 20px; align-items: flex-start;"} ::: {style="flex: 1; max-width: 48%;"} #### Without styling ```{r without-styling, eval=FALSE} trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Patient Variables", variables = age:stage ) ``` ::: ::: {style="flex: 1; max-width: 48%;"} #### With add_group_styling() ```{r with-styling, eval=FALSE} trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Patient Variables", variables = age:stage ) |> add_group_styling() ``` ::: :::::: ```{r build-styling, echo=FALSE} table_without <- trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Patient Variables", variables = age:stage ) table_with <- trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Patient Variables", variables = age:stage ) |> add_group_styling() ``` :::::: {style="display: flex; gap: 15px; margin-bottom: 30px; align-items: flex-start;"} ::: {style="flex: 1; max-width: 48%;"} ```{r render-without, echo=FALSE} table_without ``` ::: ::: {style="flex: 1; max-width: 48%;"} ```{r render-with, echo=FALSE} table_with ``` ::: :::::: The `format` argument controls the text style: ```{r} # Bold only trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Patient Characteristics", variables = age:stage ) |> add_group_styling(format = "bold") ``` Options are `"bold"`, `"italic"`, or `c("bold", "italic")` (the default). ## `add_group_colors()` Adds a background color to group header rows. This is a terminal operation in that it converts the table to `{gt}`. It must be the **last step** in your pipeline. ```{r} trial |> select(age, marker, grade, stage, response, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Demographics", variables = age ) |> add_variable_group_header( header = "Clinical Measures", variables = marker:response ) |> add_group_styling() |> add_group_colors(color = "#E3F2FD") ``` The default color is `"#E8E8E8"` (light gray). Pass any CSS color string, or a vector of colors (one per group): ```{r} trial |> select(age, marker, grade, stage, response, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Demographics", variables = age ) |> add_variable_group_header( header = "Clinical Measures", variables = marker:response ) |> add_group_styling() |> add_group_colors(color = c("#E3F2FD", "#FFF9E6")) ``` ## `get_group_rows()` If you need more control than `add_group_colors()` provides, `get_group_rows()` returns the row indices of group headers. You can then use those with `gt::tab_style()` directly: ```{r} my_table <- trial |> select(age, marker, grade, stage, trt) |> tbl_summary(by = trt) |> extras() |> add_variable_group_header( header = "Demographics", variables = age:marker ) |> add_variable_group_header( header = "Disease", variables = grade:stage ) |> add_group_styling() group_rows <- get_group_rows(my_table) my_table |> as_gt() |> gt::tab_style( style = list( gt::cell_fill(color = "#E8E8E8"), gt::cell_text(weight = "bold") ), locations = gt::cells_body(rows = group_rows) ) ``` ## Matching gt Tables with `theme_gt_compact()` If you mix `{gtsummary}` tables with plain `{gt}` tables in the same document, they won't match visually. `theme_gt_compact()` applies the same JAMA compact look to `{gt}` tables so everything is consistent: :::::: {style="display: flex; gap: 15px; margin-bottom: 20px; align-items: flex-start;"} ::: {style="flex: 1; max-width: 48%;"} #### gtsummary with extras() ```{r match-gtsummary, eval=FALSE} trial |> tbl_summary( by = trt, include = c(age, grade, marker) ) |> extras() ``` ::: ::: {style="flex: 1; max-width: 48%;"} #### gt with theme_gt_compact() ```{r match-gt, eval=FALSE} trial |> select(trt, age, grade, marker) |> head(10) |> gt() |> theme_gt_compact() ``` ::: :::::: ```{r build-match, echo=FALSE} table_gtsummary <- trial |> tbl_summary( by = trt, include = c(age, grade, marker) ) |> extras() table_gt <- trial |> select(trt, age, grade, marker) |> head(10) |> gt() |> theme_gt_compact() ``` :::::: {style="display: flex; gap: 15px; margin-bottom: 30px; align-items: flex-start;"} ::: {style="flex: 1; max-width: 48%;"} ```{r render-match-gtsummary, echo=FALSE} table_gtsummary ``` ::: ::: {style="flex: 1; max-width: 48%;"} ```{r render-match-gt, echo=FALSE} table_gt ``` ::: :::::: See `vignette("themes")` for more on theming. ## Complete Example ```{r} dictionary <- tibble::tribble( ~variable, ~description, "trt", "Treatment Assignment", "age", "Age at Baseline (years)", "marker", "Biomarker Level (ng/mL)", "stage", "Clinical Stage", "grade", "Tumor Grade", "response", "Treatment Response", "death", "Patient Died" ) trial |> select(trt, age, marker, grade, stage, response, death) |> tbl_summary(by = trt, missing = "no") |> add_auto_labels(dictionary = dictionary) |> extras() |> add_variable_group_header( header = "BASELINE CHARACTERISTICS", variables = age:marker ) |> add_variable_group_header( header = "DISEASE CHARACTERISTICS", variables = grade:stage ) |> add_variable_group_header( header = "OUTCOMES", variables = response:death ) |> add_group_styling() |> add_group_colors(color = "#E8E8E8") ``` ## More Vignettes * `vignette("sumExtras-intro")` -- getting started with extras() * `vignette("labeling")` -- dictionary-based labeling * `vignette("themes")` -- JAMA compact themes for `{gtsummary}` and `{gt}` tables * `vignette("options")` -- .Rprofile options for automatic labeling