13  Extension packages

The gt package has inspired the creation of extension packages that build upon its foundation to solve specialized problems. These packages demonstrate the flexibility of gt’s architecture and provide ready-made solutions for common table-making tasks in specific domains. In this chapter, we’ll explore gtsummary, one of the most impactful extension packages, which provides a streamlined workflow for creating clinical and analytical summary tables.

The gtsummary package wraps gt’s functionality to provide sensible defaults for its target use cases while still allowing full access to gt’s customization capabilities. This means you can use the package to quickly generate professional tables and then further refine them using the gt functions you’ve already learned.

13.1 gtsummary

The gtsummary package provides an elegant way to create publication-ready summary tables and regression model results. Originally developed for biomedical research, it has become an indispensable tool for anyone who needs to present descriptive statistics or model outputs in a professional format.

13.1.1 The problem gtsummary solves

Creating a proper “Table 1” for a research paper involves many tedious steps. You need to calculate summary statistics for continuous and categorical variables, handle missing data appropriately, compare groups using the right statistical tests, and format everything consistently. Before gtsummary, this process typically required hundreds of lines of code and careful attention to formatting details. The gtsummary package reduces this to just a few lines while producing tables that meet the exacting standards of medical journals.

The package automatically detects variable types and calculates appropriate descriptive statistics. Continuous variables get medians and interquartile ranges (or means and standard deviations), while categorical variables get counts and percentages. Missing values are tracked and reported. When comparing groups, the package selects appropriate statistical tests based on data characteristics.

13.1.2 Summarizing data with tbl_summary()

The tbl_summary() function is the workhorse of gtsummary. It takes a data frame and produces a formatted summary table with minimal code. The package includes a trial dataset for demonstrating its capabilities, which contains simulated data from 200 patients receiving chemotherapy treatments.

library(gtsummary)

trial |>
  select(trt, age, grade, response) |>
  tbl_summary()
Characteristic N = 2001
Chemotherapy Treatment
    Drug A 98 (49%)
    Drug B 102 (51%)
Age 47 (38, 57)
    Unknown 11
Grade
    I 68 (34%)
    II 68 (34%)
    III 64 (32%)
Tumor Response 61 (32%)
    Unknown 7
1 n (%); Median (Q1, Q3)

This simple call produces a table with properly formatted statistics, clear labels, and handling of missing values. The age variable is summarized with median and interquartile range because gtsummary detected it as continuous. The grade variable shows counts and percentages because it’s categorical. Missing values are reported as "Unknown" at the bottom of each variable’s section.

The real power of tbl_summary() emerges when comparing groups. By specifying a by variable, you can split your summary statistics across treatment arms or other groupings. Adding add_p() automatically selects and applies appropriate statistical tests for each variable.

trial |>
  select(trt, age, grade, response) |>
  tbl_summary(
    by = trt,
    missing = "ifany",
    label = list(
      age ~ "Patient Age (years)",
      grade ~ "Tumor Grade",
      response ~ "Tumor Response"
    )
  ) |>
  add_p() |>
  add_overall() |>
  modify_header(label = "**Characteristic**") |>
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Treatment Group**") |>
  bold_labels()
Characteristic Overall
N = 200
1
Treatment Group
p-value2
Drug A
N = 98
1
Drug B
N = 102
1
Patient Age (years) 47 (38, 57) 46 (37, 60) 48 (39, 56) 0.7
    Unknown 11 7 4
Tumor Grade


0.9
    I 68 (34%) 35 (36%) 33 (32%)
    II 68 (34%) 32 (33%) 36 (35%)
    III 64 (32%) 31 (32%) 33 (32%)
Tumor Response 61 (32%) 28 (29%) 33 (34%) 0.5
    Unknown 7 3 4
1 Median (Q1, Q3); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test

This example demonstrates several of gtsummary’s customization options. The label argument provides custom variable names. The add_overall() function adds a column with statistics for all patients combined. The modify_header() and modify_spanning_header() functions adjust column labels. Finally, bold_labels() applies bold formatting to variable names.

13.1.3 Presenting regression results with tbl_regression()

Clinical research frequently involves regression modeling, and gtsummary provides tbl_regression() to present model results in publication-ready format. The function works with many model types including linear models, logistic regression, Cox proportional hazards models, and mixed effects models.

# Fit a logistic regression model
model <- glm(
  response ~ age + stage + grade,
  data = trial,
  family = binomial
)

# Create a formatted table of results
model |>
  tbl_regression(
    exponentiate = TRUE,
    label = list(
      age ~ "Patient Age",
      stage ~ "T Stage",
      grade ~ "Tumor Grade"
    )
  ) |>
  bold_labels()
Characteristic OR 95% CI p-value
Patient Age 1.02 1.00, 1.04 0.092
T Stage


    T1
    T2 0.57 0.23, 1.34 0.2
    T3 0.91 0.37, 2.22 0.8
    T4 0.76 0.31, 1.85 0.6
Tumor Grade


    I
    II 0.84 0.38, 1.85 0.7
    III 1.05 0.49, 2.25 >0.9
Abbreviations: CI = Confidence Interval, OR = Odds Ratio

The exponentiate = TRUE argument transforms coefficients to odds ratios, which is the standard presentation for logistic regression. Reference categories are automatically identified and marked. The package also provides functions like add_global_p() to add overall p-values for categorical variables with multiple levels, though these require additional dependencies.

13.1.4 Combining multiple tables

Research papers often present multiple models side by side or combine different analyses into a single display. The gtsummary package provides tbl_merge() and tbl_stack() for these situations.

# Create two regression tables
model1 <- glm(response ~ age + grade, data = trial, family = binomial)
model2 <- glm(response ~ age + stage, data = trial, family = binomial)

tbl1 <- tbl_regression(model1, exponentiate = TRUE)
tbl2 <- tbl_regression(model2, exponentiate = TRUE)

# Merge them side by side
tbl_merge(
  tbls = list(tbl1, tbl2),
  tab_spanner = c("**Model 1**", "**Model 2**")
)
The number rows in the tables to be merged do not match, which may result in
rows appearing out of order.
ℹ See `tbl_merge()` (`?gtsummary::tbl_merge()`) help file for details. Use
  `quiet=TRUE` to silence message.
Characteristic
Model 1
Model 2
OR 95% CI p-value OR 95% CI p-value
Age 1.02 1.00, 1.04 0.10 1.02 1.00, 1.04 0.091
Grade





    I



    II 0.85 0.39, 1.85 0.7


    III 1.01 0.47, 2.16 >0.9


T Stage





    T1



    T2


0.58 0.24, 1.37 0.2
    T3


0.94 0.39, 2.28 0.9
    T4


0.79 0.33, 1.90 0.6
Abbreviations: CI = Confidence Interval, OR = Odds Ratio

This approach is particularly useful for showing how results change as you add or remove covariates, or for presenting models with different outcomes.

13.1.5 Converting to gt for additional customization

Every gtsummary table can be converted to a gt object using as_gt(), which opens up all of gt’s formatting capabilities. This is useful when you need styling options beyond what gtsummary provides natively.

trial |>
  select(trt, age, marker) |>
  tbl_summary(by = trt) |>
  add_p() |>
  as_gt() |>
  tab_header(
    title = md("**Patient Characteristics by Treatment**"),
    subtitle = "Simulated Clinical Trial Data"
  ) |>
  tab_source_note("Data simulated for demonstration purposes")
Patient Characteristics by Treatment
Simulated Clinical Trial Data
Characteristic Drug A
N = 98
1
Drug B
N = 102
1
p-value2
Age 46 (37, 60) 48 (39, 56) 0.7
    Unknown 7 4
Marker Level (ng/mL) 0.84 (0.23, 1.60) 0.52 (0.18, 1.21) 0.085
    Unknown 6 4
1 Median (Q1, Q3)
2 Wilcoxon rank sum test
Data simulated for demonstration purposes

This workflow demonstrates how gtsummary and gt complement each other. You get the convenience of gtsummary’s automatic calculations and sensible defaults, then add gt’s rich formatting options for the final presentation.

As you develop your table-making skills, extension packages like gtsummary become valuable tools in your toolkit. They handle common tasks efficiently while remaining flexible enough for customization. In the next chapter, we’ll explore how you can create your own gt extensions to share solutions with the broader community.

13.2 Summary

This chapter has introduced gtsummary, a powerful extension package that builds upon gt’s foundation for creating statistical summary tables.

The key capabilities we’ve explored:

  • gtsummary transforms statistical analysis into publication-ready tables. tbl_summary() creates descriptive statistics tables with automatic variable detection and appropriate statistics. tbl_regression() formats model outputs with proper coefficient presentation. tbl_merge() and tbl_stack() combine multiple tables for comprehensive reporting.
  • integration with gt: gtsummary produces gt objects, meaning you can further customize its output using any gt function. Apply additional formatting, add footnotes, adjust styling (the full gt toolkit remains available).

Extension packages embody a powerful pattern: domain experts identifying common needs and encoding solutions in reusable code. The tables they produce meet professional standards while requiring minimal code from users.

The final chapter shows how you can create your own extensions, building functions and packages that address the specific table-making challenges in your domain.