knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
mtcars <- mtcars
trial <- gtsummary::trial

Introduction

These vignettes will walk through examples for some of the most common tabling packages including gtsummary, kable/kableExtra, table1. All examples here work with the toy datasets such as mtcars.

gtsummary

gtsummary is commonly used for its flexibility and compatability with different types of output. The syntax is pretty straightforward and can make a table of all variables with one line of code and minimal adjusting.

gtsummary::tbl_summary(mtcars) 

You can stratify by multiple variables using tbl_strata

trial |>
  gtsummary::tbl_strata(
    strata = trt,
    .tbl_fun =
      ~ .x |>
        gtsummary::tbl_summary(by = stage) 
  ) 

You can split tables by a variable, add missingness, change variable labels, adjust which statistics are presented and more... It is a very flexible package.

gtsummary::tbl_summary(trial, 
            by = trt,
            missing = "ifany",
            missing_text = "Missing",
            label = grade ~ "Tumor Grade",
            statistic = list(age~"{median} ({p25},{p75})",
                             marker ~ "{mean} ({sd})",
                             gtsummary::all_categorical() ~ "{n}/{N}")) |>
    gtsummary::add_p(pvalue_fun = ~ gtsummary::style_pvalue(.x, digits = 2)) |>
    gtsummary::add_overall() |>
    gtsummary::add_q(method = "fdr") |>
    gtsummary::modify_header(label = "**Variables**") |>
    gtsummary::bold_labels() |>
    gtsummary::italicize_levels() |>
    gtsummary::modify_caption("**Table 1**") 

gtsummary has themes that can be adjusted as shown below. This code sets the default gtsummary package theme to be "jama" theme" and will be used for all gtsummary objects unless otherwise specified.

# changing aesthetics using themes
gtsummary::theme_gtsummary_journal("jama", set_theme = T)
gtsummary::tbl_summary(mtcars) 

Themes can apply to more than visual aspects and can set how certain variables are displayed

# changing how continuous variables are presented using themes
gtsummary::theme_gtsummary_mean_sd(set_theme = TRUE)
gtsummary::tbl_summary(mtcars) 

Note this theme shows median, mean and IQR

gtsummary::theme_gtsummary_eda(set_theme = TRUE) #note this theme shows median, mean and IQR
gtsummary::tbl_summary(mtcars) 

Explore ?theme_gtsummary for more ways to set themes for GT Summary Tables.

Other functions that may be of interest:

tbl_uvregression() - For running a series of univariate analyses

gtsummary::tbl_uvregression(
  trial,
  method = glm,
  y = response,
  method.args = list(family = binomial),
  exponentiate = TRUE,
  include = c("age", "grade", "stage")
)

tbl_regression() - For summarizing a single regression model. Also supports survival models, and some Bayesian models from the rstanarm and brms packages

stats::glm(response ~ trt, data= trial) |> 
  gtsummary::tbl_regression(exponentiate = TRUE)

tbl_stack() or tbl_merge - to combine table results

# stacking two tbl_regression objects
t1 <-
  stats::glm(response ~ trt, trial, family = binomial) |>
  gtsummary::tbl_regression(
    exponentiate = TRUE,
    label = list(trt ~ "Treatment (unadjusted)")
  )

t2 <-
  stats::glm(response ~ trt + grade + stage + marker, trial, family = binomial) |>
  gtsummary::tbl_regression(
    include = "trt",
    exponentiate = TRUE,
    label = list(trt ~ "Treatment (adjusted)")
  )

gtsummary::tbl_stack(list(t1, t2))
t3 <-
  stats::glm(response ~ trt + grade + age, trial, family = binomial) |>
  gtsummary::tbl_regression(exponentiate = TRUE)
t4 <-
  survival::coxph(survival::Surv(ttdeath, death) ~ trt + grade + age, trial) |>
  gtsummary::tbl_regression(exponentiate = TRUE)

gtsummary::tbl_merge(
  tbls = list(t3, t4),
  tab_spanner = c("**Tumor Response**", "**Time to Death**")
)

Flextable

Flextable plays well with gtsummary with the function as_flex_table. This may be of interest as flextable advertises itself as one of the few tabling packages that plays well with HTML, PDF and Word outputs. Most packages handle html well but sometimes struggle with losing capability with word or pdf outputting. Note the autofit function should fix any width problems that may occur with tables running off the page.

ft <- flextable::flextable(airquality[ sample.int(10),])
ft <- flextable::add_header_row(ft,
  colwidths = c(4, 2),
  values = c("Air quality", "Time")
)
ft <- flextable::theme_vanilla(ft)
ft <- flextable::add_footer_lines(ft, "Daily air quality measurements in New York, May to September 1973.")
ft <- flextable::color(ft, part = "footer", color = "#666666")
ft <- flextable::set_caption(ft, caption = "New York Air Quality Measurements")
ft

Flextable also offers a variety of themes / settings that can be adjusted.

flextable::flextable(airquality[ sample.int(10),]) |> flextable::theme_box()

Or changing default settings like below

flextable::set_flextable_defaults(
  font.size = 10, theme_fun = flextable::theme_vanilla,
  padding = 6,
  background.color = "#EFEFEF")
flextable::flextable(airquality[ sample.int(10),]) |> flextable::autofit()

Kable/KableExtra

Kable can be viewed as the base package that can be built on or styled with KableExtra. Note if you load KableExtra, kable will be loaded in the background if it is not already. KableExtra also allows working with piping (%>% or |> ) for added simplicity when editing a table.

The first step, the kable call is pretty simple but is fairly limited in themes etc.

kableExtra::kable(mtcars, align = "lccrr")

Adding a simple kable_styling() call makes it much better visually

kableExtra::kable(mtcars, align = "lccrr") |> kableExtra::kable_styling()

Below are a handful of other options found within the "Kable universe".

mtcars |>
  kableExtra::kbl(caption = "Recreating booktabs style table") |>
  kableExtra::kable_classic(full_width = F, html_font = "Cambria")
mtcars |>
  kableExtra::kbl() |>
  kableExtra::kable_material(c("striped", "hover"))
mtcars |>
  kableExtra::kbl() |>
  kableExtra::kable_paper(bootstrap_options = "striped", full_width = F)

Please visit the following website for more examples on the kable package: https://cran.r-project.org/web/packages/kableExtra/vignettes/awesome_table_in_html.html

Table1

Table1 uses quick and easy syntax but is not very friendly with testing/pvals. Note the label function is helpful here (changed the names / levels of wt to weight and am to automatic)

Hmisc::label(mtcars$wt) <- "weight"

mtcars$am <- 
  factor(mtcars$am, 
         levels=c(0,1),
         labels=c("Automatic", # Reference
                  "Manual"))

table1::table1(~ mpg + cyl + wt | am * vs, data=mtcars)

tableone

Here is the simplest approach to creating a summary table with the tableone package.

tableone::CreateTableOne(data = mtcars)

You can specify which variables in included and which are factor variables easily in the table call.

tableone::CreateTableOne(data = mtcars,
               vars = c("mpg", "cyl", "disp", "hp"),
               factorVars = c("cyl"))


CIDA-CSPH/CIDAtools documentation built on July 5, 2025, 1:36 a.m.