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 two of the most impactful extension packages: gtsummary for clinical and analytical summary tables, and gtExtras for enhanced visual elements and styling.
Both packages follow a similar philosophy: they wrap gt’s functionality to provide sensible defaults for their target use cases while still allowing full access to gt’s customization capabilities. This means you can use these packages to quickly generate professional tables and then further refine them using the gt functions you’ve already learned.
13.1gtsummary
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.
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.
2Wilcoxon 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 modelmodel<-glm(response~age+stage+grade, data =trial, family =binomial)# Create a formatted table of resultsmodel|>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 tablesmodel1<-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 sidetbl_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 = 981
Drug B
N = 1021
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
1Median (Q1, Q3)
2Wilcoxon 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.
13.2gtExtras
While gtsummary focuses on statistical summaries, gtExtras enhances gt’s visual capabilities. gtExtras provides functions for adding inline graphics, applying publication-quality themes, and handling common formatting tasks that would otherwise require repetitive code.
13.2.1 Themes for instant polish
One of gtExtras’ most immediately useful features is its collection of themes. These functions apply comprehensive styling to transform a basic gt table into something that looks like it belongs in a major publication! Each theme adjusts fonts, colors, borders, and spacing to match the visual identity of well-known outlets.
Table has no assigned ID, using random ID 'thveeuenrw' to apply `gt::opt_css()`
Avoid this message by assigning an ID: `gt(id = '')` or `gt_theme_538(quiet = TRUE)`
Vehicle Specifications
car
mpg
hp
wt
Mazda RX4
21.0
110
2.620
Mazda RX4 Wag
21.0
110
2.875
Datsun 710
22.8
93
2.320
Hornet 4 Drive
21.4
110
3.215
Hornet Sportabout
18.7
175
3.440
Valiant
18.1
105
3.460
Duster 360
14.3
245
3.570
Merc 240D
24.4
62
3.190
The gt_theme_538() function applies styling inspired by FiveThirtyEight’s data journalism. Other available themes include gt_theme_nytimes() for New York Times styling, gt_theme_espn() for sports-focused tables, and gt_theme_guardian() for The Guardian’s aesthetic. There’s even gt_theme_excel() for those times when you need that familiar spreadsheet look.
These themes handle the tedious details of professional table design, including font choices, cell padding, border styles, and color schemes. They’re particularly valuable when you need consistent styling across multiple tables in a report or presentation.
13.2.2 Inline visualizations with sparklines and bar charts
Tables are really good at showing exact values, while charts reveal patterns and relationships. The gtExtras package bridges this gap by embedding small visualizations directly within table cells. These inline graphics help readers quickly grasp trends and comparisons without leaving the tabular format.
Sparklines are miniature line charts that show the shape of data over time or across observations. To create them, you first need to prepare your data so that each row contains a list-column of values to plot.
# Prepare data with list columns for plottingcar_summary<-mtcars|>group_by(cyl)|>summarize( n =n(), avg_mpg =mean(mpg), mpg_data =list(mpg), hp_data =list(hp), .groups ="drop")# Create table with sparklinescar_summary|>gt()|>gt_plt_sparkline(mpg_data, same_limit =TRUE, label =FALSE)|>gt_plt_sparkline(hp_data, same_limit =FALSE, label =FALSE)|>fmt_number(avg_mpg, decimals =1)|>cols_label( cyl ="Cylinders", n ="Count", avg_mpg ="Avg MPG", mpg_data ="MPG Distribution", hp_data ="HP Distribution")|>tab_header(title ="Vehicle Statistics by Cylinder Count")
Vehicle Statistics by Cylinder Count
Cylinders
Count
Avg MPG
MPG Distribution
HP Distribution
4
11
26.7
6
7
19.7
8
14
15.1
The gt_plt_sparkline() function converts each list-column into a small line chart. The same_limit argument controls whether all sparklines share the same y-axis scale (useful for direct comparisons) or each gets its own scale (useful for showing patterns regardless of magnitude).
For categorical comparisons, bar charts often work better than line charts. The gt_plt_bar_pct() function creates horizontal bars that represent values as percentages of the maximum.
These bar visualizations make it immediately apparent which cars have the highest or lowest values for each metric, without requiring readers to mentally compare numbers.
13.2.3 Distribution plots
Sometimes you want to show not just the values themselves but their distribution. The gt_plt_dist() function can create density plots or histograms within table cells, giving readers insight into the spread and shape of your data.
mtcars|>group_by(cyl)|>summarize( n =n(), mean_mpg =mean(mpg), mpg_dist =list(mpg), .groups ="drop")|>gt()|>gt_plt_dist(mpg_dist, type ="density", line_color ="darkblue", fill_color ="lightblue")|>fmt_number(mean_mpg, decimals =1)|>cols_label( cyl ="Cylinders", n ="Count", mean_mpg ="Mean MPG", mpg_dist ="Distribution")
Cylinders
Count
Mean MPG
Distribution
4
11
26.7
6
7
19.7
8
14
15.1
Distribution plots are especially valuable when comparing groups. At a glance, you can see not just the central tendency but also the spread and shape of each group’s data.
13.2.4 Color scales and conditional formatting
The gtExtras package provides several functions for applying color scales to numeric data. The gt_color_rows() function applies a color gradient across specified columns, making it easy to spot high and low values.
Warning: Domain not specified, defaulting to observed range within each
specified column.
Warning: Domain not specified, defaulting to observed range within each
specified column.
Warning: Domain not specified, defaulting to observed range within each
specified column.
car
mpg
hp
wt
qsec
Mazda RX4
21.0
110
2.620
16.46
Mazda RX4 Wag
21.0
110
2.875
17.02
Datsun 710
22.8
93
2.320
18.61
Hornet 4 Drive
21.4
110
3.215
19.44
Hornet Sportabout
18.7
175
3.440
17.02
Valiant
18.1
105
3.460
20.22
Duster 360
14.3
245
3.570
15.84
Merc 240D
24.4
62
3.190
20.00
Merc 230
22.8
95
3.150
22.90
Merc 280
19.2
123
3.440
18.30
The palette argument accepts color palettes from the paletteer package, giving you access to hundreds of carefully designed color schemes. You can also specify custom colors using the standard gt approach.
For a more distinctive look, gt_hulk_col_numeric() applies a purple-to-green gradient that works well for highlighting ranges of values.
The gtExtras package includes helper functions for common cell manipulations. The gt_merge_stack() function combines two columns into one, with the second value displayed below the first in a smaller font. This technique is useful for showing primary and secondary information without using extra columns.
This stacked presentation saves horizontal space while keeping related information visually connected.
13.2.6 Highlighting rows and columns
When you want to draw attention to specific parts of your table, gt_highlight_rows() and gt_highlight_cols() provide quick ways to apply background colors.
The bold_target_only argument lets you emphasize the value that triggered the highlighting while keeping other columns in their normal weight.
13.2.7 Adding images and icons
Tables in modern reports often need to include images, logos, or icons. The gtExtras package simplifies this with functions like gt_img_rows() for embedding images and gt_fa_rating() for adding icon-based ratings.
Warning in stopifnot(`Column must be integers` = is.integer(as.integer(vals))):
NAs introduced by coercion
product
rating
trend
Widget A
up
Widget B
down
Widget C
same
The gt_fa_rating() function converts numeric ratings to filled icons, while gt_fa_rank_change() adds directional arrows or indicators based on categorical values.
13.2.8 When to use each package
The gtsummary and gtExtras packages serve different but complementary purposes. Use gtsummary when you need to present statistical summaries or regression results, particularly in clinical or research contexts. The package’s automatic calculations and journal-ready defaults will save significant time and reduce errors. Use gtExtras when you need enhanced visual elements like sparklines, color scales, or themed styling. The package is great at making data patterns visible within a tabular format.
Many projects benefit from both packages. You might use gtsummary to create a baseline characteristics table, then use gtExtras themes to style it consistently with other tables in your report. Or you might start with a gtExtras-styled data table and add it alongside gtsummary regression results. Since both packages ultimately produce gt objects, you can combine their outputs using gt’s own functions for merging and arranging tables.
As you develop your table-making skills, these extension packages 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.3 Summary
This chapter has introduced two powerful extension packages that build upon gt’s foundation: gtsummary for statistical summary tables and gtExtras for enhanced visual elements.
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: both packages produce gt objects, meaning you can further customize their output using any gt function. Apply additional formatting, add footnotes, adjust styling (the full gt toolkit remains available).
complementary purposes: use gtsummary when you need statistically rigorous summary tables, especially in research or clinical contexts. Use gtExtras when you want enhanced visuals, sparklines, or quick access to polished themes.
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.