Your Table 1, in one line, with gtsummary

clinical
biostatistics
gtsummary
reporting
Baseline characteristics tables are the most-copied, most-error-prone table in clinical papers. gtsummary generates a publication-ready one — with the right summary and test per variable — from a single call.
Author

Rverse Analytics

Published

July 9, 2026

Every clinical paper opens with the same table: participant characteristics, split by group. Built by hand it is tedious and easy to get wrong — the wrong summary statistic, the wrong test, a percentage that doesn’t add up. gtsummary builds it correctly from one function call, and regenerates it the moment your data changes.

The one-liner

We’ll use the trial dataset that ships with gtsummary — a small clinical-trial example:

library(gtsummary)

trial |>
  dplyr::select(trt, age, grade, marker, stage) |>
  tbl_summary(by = trt) |>
  add_p()
Characteristic Drug A
N = 981
Drug B
N = 1021
p-value2
Age 46 (37, 60) 48 (39, 56) 0.7
    Unknown 7 4
Grade

0.9
    I 35 (36%) 33 (32%)
    II 32 (33%) 36 (35%)
    III 31 (32%) 33 (32%)
Marker Level (ng/mL) 0.84 (0.23, 1.60) 0.52 (0.18, 1.21) 0.085
    Unknown 6 4
T Stage

0.9
    T1 28 (29%) 25 (25%)
    T2 25 (26%) 29 (28%)
    T3 22 (22%) 21 (21%)
    T4 23 (23%) 27 (26%)
1 Median (Q1, Q3); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test

That’s the whole table. tbl_summary() picks median (IQR) for continuous variables and n (%) for categoricals; add_p() chooses an appropriate test for each row (Wilcoxon, chi-squared, Fisher) and reports the p-value. No manual test selection, no transcription.

Making it publication-ready

A few extra verbs turn it into something you can paste straight into a manuscript:

trial |>
  dplyr::select(trt, age, grade, marker) |>
  tbl_summary(
    by = trt,
    label = list(age ~ "Age (years)", marker ~ "Marker (ng/mL)"),
    statistic = list(all_continuous() ~ "{mean} ({sd})"),
    missing_text = "Missing"
  ) |>
  add_p() |>
  add_overall() |>
  bold_labels() |>
  modify_caption("**Table 1. Baseline characteristics by treatment**")
Table 1. Baseline characteristics by treatment
Characteristic Overall
N = 2001
Drug A
N = 981
Drug B
N = 1021
p-value2
Age (years) 47 (14) 47 (15) 47 (14) 0.7
    Missing 11 7 4
Grade


0.9
    I 68 (34%) 35 (36%) 33 (32%)
    II 68 (34%) 32 (33%) 36 (35%)
    III 64 (32%) 31 (32%) 33 (32%)
Marker (ng/mL) 0.92 (0.86) 1.02 (0.89) 0.82 (0.83) 0.085
    Missing 10 6 4
1 Mean (SD); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test

Here we switched continuous summaries to mean (SD), relabelled variables, added an overall column, and counted missing values explicitly instead of dropping them silently — a small honesty that reviewers notice.

Why it matters

The value isn’t saving five minutes once; it’s that the table is code. Clean a data point, rerun, and every number updates — including the tests and the percentages. There is no window where the manuscript and the data disagree. That’s the whole philosophy behind how we work, applied to the humblest table in the paper.


More clinical recipes live in our Clinical R toolkit. Need this on your own data? Get in touch.