The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
The descriptive table builder is the centrepiece of gtstats. It lets you assemble a publication-ready “Table 1” — the standard baseline characteristics table used in clinical and epidemiological papers — through a simple, pipe-based workflow.
Think of the table as layers. Start with the descriptive foundation, then add only the layers required by the report:
| Step | Function | What it does |
|---|---|---|
| 1 | summary_table() |
Builds summaries, grouping and the Overall column |
| 2 | add_ci() |
Adds CIs globally or to selected variables |
| 3 | add_p() |
Adds a p-value column when comparisons are appropriate |
| 4 | add_proportion() |
Highlights one selected event as a new row |
| 5 | add_rate() |
Adds an event-rate row |
| 6 | add_total() |
Adds a participant-count row |
| 7 | add_row() |
Adds a free-text row |
| 8 | customise_table() |
Finishes appearance and labels |
For an ordinary Table 1, select all variable types together. There is no need to add continuous and categorical variables separately.
Characteristic | 1 | 0 |
|---|---|---|
mpg | 24.4 (6.2) | 17.1 (3.8) |
wt | 2.4 (0.6) | 3.8 (0.8) |
cyl | ||
4 | 8 (61.5%) | 3 (15.8%) |
6 | 3 (23.1%) | 4 (21.1%) |
8 | 2 (15.4%) | 12 (63.2%) |
Continuous data are mean (SD). Categorical data are n (%). | ||
by = am groups the table by the am variable
(transmission type). Each level becomes a column.
Set overall = TRUE to include an additional column
showing statistics for the full sample.
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
cyl | |||
4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
Continuous data are mean (SD). Categorical data are n (%). | |||
The default call is deliberately simple. These global options cover the most common reporting choices without requiring separate continuous and categorical workflows.
| Reporting choice | Option | Example |
|---|---|---|
| Overall column | overall |
TRUE, "first", or "last" |
| Continuous summary | statistic |
"recommended", "mean_sd",
"mean_ci", "median_iqr", or
"both" |
| Categorical display | categorical |
"n_percent", "n_over_N_percent",
"n", or "percent" |
| Categorical columns | categorical_layout |
"combined" (default) or "separate" for
categorical-only tables without CIs |
| Overall categorical cells | overall_categorical |
"auto" (default), "n_percent",
"n_over_N_percent", "n", or
"percent" |
| Binary rows | show_dichotomous |
"all_levels" (default) or
"single_row" |
| Binary event | value |
Named choices such as c(smoke = "Yes"); otherwise the
second level is used |
| Percentage denominator | percent |
"column", "row", "overall",
or "none" |
| Precision | digits |
c(continuous = 1, percent = 0, ci = 1) |
| Missing-value handling | missing |
"ifany", "always", "no", or
"as_category" |
| CI layout | layout |
"compact" (default) or "separate" |
For a row-percentage table, overall_categorical = "auto"
deliberately shows Overall categorical counts. A percentage of the
entire sample is usually not the same estimand as the grouped row
percentages. Override this with
overall_categorical = "n_percent" only when that is the
intended display.
The defaults are deliberately useful, but they never lock the user in. A single value applies to every eligible variable. A named vector changes only the named variables; all unlisted variables continue to use the recommended summary.
# Mean (SD) for every continuous variable
summary_table(
birthwt,
include = c(age, lwt, bwt, smoke),
statistic = "mean_sd"
)Characteristic | Overall |
|---|---|
Maternal age (years) | 23.2 (5.3) |
Maternal weight (lb) | 129.8 (30.6) |
Birth weight (g) | 2944.6 (729.2) |
Smoking during pregnancy | |
No | 115 (60.8%) |
Yes | 74 (39.2%) |
Continuous data are mean (SD). Categorical data are n (%). | |
# Recommended summaries for all variables except maternal weight
summary_table(
birthwt,
include = c(age, lwt, bwt, smoke),
statistic = c(lwt = "median_iqr")
)Characteristic | Overall |
|---|---|
Maternal age (years) | 23.2 (5.3) |
Maternal weight (lb) | 121.0 (110.0–140.0) |
Birth weight (g) | 2944.6 (729.2) |
Smoking during pregnancy | |
No | 115 (60.8%) |
Yes | 74 (39.2%) |
Continuous data: Maternal age (years): mean (SD); Maternal weight (lb): median (IQR); Birth weight (g): mean (SD). Categorical data are n (%). | |
The same principle applies to label, value,
and the named precision settings. This makes the short call
beginner-friendly while preserving precise control for a manuscript.
Two similarly named options solve different reporting problems:
| Need | Use | Result |
|---|---|---|
Keep ordinary categorical values as n (%) |
categorical_layout = "combined" |
One summary column per cohort |
Put n and % in different columns |
categorical_layout = "separate" |
Separate count and percentage child columns; intended for categorical-only tables without CIs |
| Keep an estimate and its CI together | layout = "compact" plus add_ci() |
One concise cell per cohort |
| Put estimates and CIs in different columns | layout = "separate" plus add_ci() |
A cohort spanner with an estimate column and an explicit confidence-interval column |
layout = "separate" does not create empty
confidence-interval columns. The CI columns appear only after
add_ci(), add_proportion(ci = TRUE), or an
equivalent CI layer is present.
show_dichotomous = "single_row" is a display choice for
common Yes/No and Present/Absent variables. It does not turn a two-level
association test into a one-level test. By default, gtstats displays the
second declared factor level. Use value whenever the event
should be explicit.
summary_table(
birthwt,
by = low,
include = c(smoke, ht, race),
show_dichotomous = "single_row",
value = c(smoke = "Yes", ht = "Yes")
) |>
add_p()Characteristic | Normal birth weight | Low birth weight | p-value |
|---|---|---|---|
Smoking during pregnancy | 44 (33.8%) | 30 (50.8%) | 0.040ᵃ |
Hypertension | 5 (3.8%) | 7 (11.9%) | |
Maternal race | 0.082ᵃ | ||
Black | 15 (11.5%) | 11 (18.6%) | |
Other | 42 (32.3%) | 25 (42.4%) | |
White | 73 (56.2%) | 23 (39.0%) | |
Categorical data are n (%). | |||
ᵃ Chi-square test | |||
Here smoke and ht occupy one row each,
race retains all levels, and add_p() still
tests each complete source variable.
Use one number when all displayed values need the same precision, or name the parts that differ:
summary_table(
birthwt,
by = low,
include = c(age, smoke),
digits = c(continuous = 1, percent = 0, ci = 1),
label = c(
age = "Maternal age, years",
smoke = "Smoking during pregnancy"
)
)Characteristic | Normal birth weight | Low birth weight |
|---|---|---|
Maternal age, years | 23.7 (5.6) | 22.3 (4.5) |
Smoking during pregnancy | ||
No | 86 (66%) | 29 (49%) |
Yes | 44 (34%) | 30 (51%) |
Continuous data are mean (SD). Categorical data are n (%). | ||
Variable labels affect presentation only. They do not rename the columns in the source data or alter automatic test selection.
Confidence intervals are deliberately a visible second layer:
1 | 0 | |||
|---|---|---|---|---|
Characteristic | Summary | 95% CI | Summary | 95% CI |
mpg | 24.4 (6.2) | 20.7–28.1 | 17.1 (3.8) | 15.3–19.0 |
cyl | ||||
4 | 8 (61.5%) | 35.5–82.3% | 3 (15.8%) | 5.5–37.6% |
6 | 3 (23.1%) | 8.2–50.3% | 4 (21.1%) | 8.5–43.3% |
8 | 2 (15.4%) | 4.3–42.2% | 12 (63.2%) | 41.0–80.9% |
vs | ||||
0 | 6 (46.2%) | 23.2–70.9% | 12 (63.2%) | 41.0–80.9% |
1 | 7 (53.8%) | 29.1–76.8% | 7 (36.8%) | 19.1–59.0% |
Continuous data are mean (SD). Categorical data are n (%). Categorical proportions include 95% Wilson score CIs. Continuous means include 95% t-based CIs. | ||||
summary_table(
mtcars,
by = am,
include = c(mpg, cyl, vs),
layout = "separate"
) |>
add_ci(vars = c(mpg, vs), conf.level = 0.90)1 | 0 | |||
|---|---|---|---|---|
Characteristic | Summary | 90% CI | Summary | 90% CI |
mpg | 24.4 (6.2) | 21.3–27.4 | 17.1 (3.8) | 15.6–18.7 |
cyl | ||||
4 | 8 (61.5%) | 3 (15.8%) | ||
6 | 3 (23.1%) | 4 (21.1%) | ||
8 | 2 (15.4%) | 12 (63.2%) | ||
vs | ||||
0 | 6 (46.2%) | 26.1–67.5% | 12 (63.2%) | 44.4–78.6% |
1 | 7 (53.8%) | 32.5–73.9% | 7 (36.8%) | 21.4–55.6% |
Continuous data are mean (SD). Categorical data are n (%). Selected categorical proportions include 90% Wilson score CIs. Continuous means include 90% t-based CIs. | ||||
For a categorical-only table without confidence intervals, counts and percentages can instead occupy distinct child columns:
1 | 0 | |||
|---|---|---|---|---|
Characteristic | n | % | n | % |
cyl | ||||
4 | 8 | 61.5% | 3 | 15.8% |
6 | 3 | 23.1% | 4 | 21.1% |
8 | 2 | 15.4% | 12 | 63.2% |
vs | ||||
0 | 6 | 46.2% | 12 | 63.2% |
1 | 7 | 53.8% | 7 | 36.8% |
Categorical data are n and %. | ||||
For compact clinical Table 1 layouts, binary variables can occupy one row while ordinary categorical variables continue to show every level:
summary_table(
birthwt,
by = low,
include = c(smoke, ht, race),
show_dichotomous = "single_row",
value = c(smoke = "Yes", ht = "Yes")
)Characteristic | Normal birth weight | Low birth weight |
|---|---|---|
Smoking during pregnancy | 44 (33.8%) | 30 (50.8%) |
Hypertension | 5 (3.8%) | 7 (11.9%) |
Maternal race | ||
Black | 15 (11.5%) | 11 (18.6%) |
Other | 42 (32.3%) | 25 (42.4%) |
White | 73 (56.2%) | 23 (39.0%) |
Categorical data are n (%). | ||
This changes presentation only. add_p() still tests the
full binary variable.
For different continuous summaries by variable, provide a named vector:
summary_table(
mtcars,
by = am,
include = c(mpg, wt, cyl),
statistic = c(mpg = "mean_ci", wt = "median_iqr"),
overall = "last"
)Characteristic | 1 | 0 | Overall |
|---|---|---|---|
mpg | 24.4 (20.7–28.1) | 17.1 (15.3–19.0) | 20.1 (17.9–22.3) |
wt | 2.3 (1.9–2.8) | 3.5 (3.4–3.8) | 3.3 (2.6–3.6) |
cyl | |||
4 | 8 (61.5%) | 3 (15.8%) | 11 (34.4%) |
6 | 3 (23.1%) | 4 (21.1%) | 7 (21.9%) |
8 | 2 (15.4%) | 12 (63.2%) | 14 (43.8%) |
Continuous data: mpg: mean (95% CI); wt: median (IQR). Categorical data are n (%). | |||
Categorical percentages should always identify their denominator:
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
cyl | |||
4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
vs | |||
0 | 18 (56.2%) | 6 (46.2%) | 12 (63.2%) |
1 | 14 (43.8%) | 7 (53.8%) | 7 (36.8%) |
Categorical data are n (%). | |||
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
cyl | |||
4 | 11 | 8 (72.7%) | 3 (27.3%) |
6 | 7 | 3 (42.9%) | 4 (57.1%) |
8 | 14 | 2 (14.3%) | 12 (85.7%) |
vs | |||
0 | 18 | 6 (33.3%) | 12 (66.7%) |
1 | 14 | 7 (50.0%) | 7 (50.0%) |
Categorical data are n (%). Percentages use row denominators. Overall categorical values are counts; grouped percentages use row denominators. | |||
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
cyl | |||
4 | 11 (34.4%) | 8 (25.0%) | 3 (9.4%) |
6 | 7 (21.9%) | 3 (9.4%) | 4 (12.5%) |
8 | 14 (43.8%) | 2 (6.2%) | 12 (37.5%) |
vs | |||
0 | 18 (56.2%) | 6 (18.8%) | 12 (37.5%) |
1 | 14 (43.8%) | 7 (21.9%) | 7 (21.9%) |
Categorical data are n (%). Percentages use overall denominators. | |||
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
cyl | |||
4 | 11 | 8 | 3 |
6 | 7 | 3 | 4 |
8 | 14 | 2 | 12 |
vs | |||
0 | 18 | 6 | 12 |
1 | 14 | 7 | 7 |
Categorical data are counts. | |||
"column" describes levels within each group,
"row" distributes each level across groups,
"overall" uses the full non-missing variable denominator,
and "none" displays counts only. The selected rule is
retained in the object and shown in the table footnote.
Missing-value rows are equally explicit:
Characteristic | Overall | 1 | 0 |
|---|---|---|---|
mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
vs | |||
0 | 18 (56.2%) | 6 (46.2%) | 12 (63.2%) |
1 | 14 (43.8%) | 7 (53.8%) | 7 (36.8%) |
Continuous data are mean (SD). Categorical data are n (%). | |||
Use "always" to show zero-missing rows or
"no" to suppress them. With these settings,
observed-category percentages use non-missing values. Use
missing = "as_category" to display Missing as a category
and include it when calculating categorical percentages.
missing_example <- data.frame(
catheter = factor(
c(rep("Yes", 32), rep(NA_character_, 68)),
levels = c("No", "Yes")
)
)
summary_table(
missing_example,
include = catheter,
missing = "as_category"
)Characteristic | Overall |
|---|---|
catheter | |
No | 0 (0.0%) |
Yes | 32 (32.0%) |
Missing | 68 (68.0%) |
Categorical data are n (%). | |
Use categorical = "n_over_N_percent" when the table
itself should show the non-missing denominator for every category. This
is particularly helpful for small groups, supplementary tables, and
teaching.
summary_table(
mtcars,
by = am,
include = cyl,
categorical = "n_over_N_percent",
percent = "column",
digits = c(percent = 0)
)Characteristic | 1 | 0 |
|---|---|---|
cyl | ||
4 | 8/13 (62%) | 3/19 (16%) |
6 | 3/13 (23%) | 4/19 (21%) |
8 | 2/13 (15%) | 12/19 (63%) |
Categorical data are n (%). | ||
Use add_ci() when the goal is descriptive precision
rather than a p-value. For a mean-based continuous summary it adds a t
confidence interval while retaining the displayed mean (SD).
summary_table(
mtcars,
include = c(mpg, wt),
statistic = "mean_sd",
layout = "separate"
) |>
add_ci()Overall | ||
|---|---|---|
Characteristic | Mean (SD) | 95% CI |
mpg | 20.1 (6.0) | 17.9–22.3 |
wt | 3.2 (1.0) | 2.9–3.6 |
Continuous data are mean (SD). Continuous means include 95% t-based CIs. | ||
add_proportion() is a specialist layer that adds one
highlighted event row for a binary or categorical variable. Optionally
add Wilson confidence intervals (the default) or request exact binomial
confidence intervals with ci = TRUE.
When confidence intervals make a table too dense, use
layout = "separate". Each displayed cohort then becomes a
spanning header with a dynamically labelled summary column and an
explicit 95% CI column (or the selected confidence
level). The confidence level and method are stated once in the footnote.
Separate child columns appear only after a CI layer is added, so
layout = "separate" alone does not create empty columns.
The compact layout remains the default for ordinary Table 1 output.
summary_table(
birthwt,
by = smoke,
include = c(age, low),
overall = "first",
layout = "separate"
) |>
add_ci()Overall | No | Yes | ||||
|---|---|---|---|---|---|---|
Characteristic | Summary | 95% CI | Summary | 95% CI | Summary | 95% CI |
Maternal age (years) | 23.2 (5.3) | 22.5–24.0 | 23.4 (5.5) | 22.4–24.4 | 22.9 (5.0) | 21.8–24.1 |
Birth-weight outcome | ||||||
Normal birth weight | 130 (68.8%) | 61.9–75.0% | 86 (74.8%) | 66.1–81.8% | 44 (59.5%) | 48.1–69.9% |
Low birth weight | 59 (31.2%) | 25.0–38.1% | 29 (25.2%) | 18.2–33.9% | 30 (40.5%) | 30.1–51.9% |
Continuous data are mean (SD). Categorical data are n (%). Categorical proportions include 95% Wilson score CIs. Continuous means include 95% t-based CIs. | ||||||
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs) |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
|---|---|---|---|
| mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
| wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
| cyl | |||
| 4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
| 6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
| 8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
| vs (1) | 14 (43.8%); 28.2–60.7% | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% |
| 1 Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | |||
To display confidence intervals and pin the row to a specific level:
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs, level = "1", ci = TRUE) |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
|---|---|---|---|
| mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
| wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
| cyl | |||
| 4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
| 6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
| 8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
| vs (1) | 14 (43.8%); 28.2–60.7% | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% |
| 1 Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | |||
add_total() appends a row at the bottom showing the
total N per group.
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs) |>
add_total() |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
|---|---|---|---|
| mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
| wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
| cyl | |||
| 4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
| 6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
| 8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
| vs (1) | 14 (43.8%); 28.2–60.7% | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% |
| Total (N) | 32 | 13 | 19 |
| 1 Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | |||
The rendered table footnote is data-driven: it mentions continuous summaries only when continuous variables are present, and categorical displays only when categorical variables are present.
add_p() appends a p-value column. Its automatic route is
identical to compare_groups(test = "auto"):
var_equal = TRUE only when an
equal-variance assumption is justified, to select Student’s t-test or
classical ANOVAadd_p() uses the same automatic-selection policy as
compare_groups(). The publication table stays concise: its
p-value markers identify the test, while the variable-specific checks
remain available in the audit components. var_equal is a
user-specified analytical assumption; it is not inferred by a variance
hypothesis test.
Use include when a displayed variable should remain
descriptive but should not be tested. This is important when the
grouping variable was derived from a displayed variable or when a
comparison was not prespecified.
Characteristic | Normal birth weight | Low birth weight | p-value |
|---|---|---|---|
Maternal age (years) | 23.7 (5.6) | 22.3 (4.5) | 0.078ᵃ |
Birth weight (g) | 3267.0 (2948.0–3651.0) | 2211.0 (1928.0–2395.5) | |
Smoking during pregnancy | 0.040ᵇ | ||
No | 86 (66.2%) | 29 (49.2%) | |
Yes | 44 (33.8%) | 30 (50.8%) | |
Continuous data: Maternal age (years): mean (SD); Birth weight (g): median (IQR). Categorical data are n (%). | |||
ᵃ Welch t-test; ᵇ Chi-square test | |||
For independent ordered factors, Auto compares the complete
distribution of levels using chi-square/Fisher. Specify
test = "wilcox" or "kruskal" only when the
planned estimand is an ordered rank shift. Paired and repeated outcomes
use their design-specific routes: paired t/Wilcoxon signed-rank,
repeated-measures ANOVA/Friedman, McNemar, or Cochran’s Q.
summary_table(mtcars, by = am, include = c(mpg, wt, cyl)) |>
add_proportion(var = vs) |>
add_p() |>
to_gt()| Characteristic1 | 1 N = 131 |
0 N = 191 |
p-value2 |
|---|---|---|---|
| mpg | 24.4 (6.2) | 17.1 (3.8) | 0.001ᵃ |
| wt | 2.4 (0.6) | 3.8 (0.8) | <0.001ᵃ |
| cyl | 0.007ᵇ | ||
| 4 | 8 (61.5%) | 3 (15.8%) | |
| 6 | 3 (23.1%) | 4 (21.1%) | |
| 8 | 2 (15.4%) | 12 (63.2%) | |
| vs (1) | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% | |
| 1 Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | |||
| 2 ᵃ Welch t-test; ᵇ Fisher's exact test (Monte Carlo p-value) | |||
Raw and multiplicity-adjusted values are retained separately:
adjusted <- summary_table(mtcars, by = am, include = c(mpg, wt, cyl, vs)) |>
add_p(p_adjust = "BH")
adjusted$p_values
#> # A tibble: 4 × 8
#> variable label row_index test symbol p_value p_adjusted p_adjust_method
#> <chr> <chr> <int> <chr> <chr> <dbl> <dbl> <chr>
#> 1 mpg mpg 1 Welch t-te… ᵃ 1.37e-3 0.00275 BH
#> 2 wt wt 2 Welch t-te… ᵃ 6.27e-6 0.0000251 BH
#> 3 cyl cyl 3 Fisher's e… ᵇ 7.10e-3 0.00947 BH
#> 4 vs vs 6 Chi-square… ᶜ 5.56e-1 0.556 BH
adjusted$assumptions
#> # A tibble: 10 × 6
#> assumption status result detail variable analysis_component
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 Independent observations user_… not_c… Confi… mpg add_p
#> 2 Distribution and influentia… partl… no_sk… Inspe… mpg add_p
#> 3 Independent observations user_… not_c… Confi… wt add_p
#> 4 Distribution and influentia… partl… no_sk… Inspe… wt add_p
#> 5 Independent observations user_… not_c… Confi… cyl add_p
#> 6 Mutually exclusive categori… user_… not_c… Confi… cyl add_p
#> 7 Adequate expected cell coun… check… sparse Autom… cyl add_p
#> 8 Independent observations user_… not_c… Confi… vs add_p
#> 9 Mutually exclusive categori… user_… not_c… Confi… vs add_p
#> 10 Adequate expected cell coun… check… guida… Autom… vs add_p
adjusted$diagnostics
#> # A tibble: 18 × 7
#> check result value threshold detail variable analysis_component
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 Comparison design indep… Inde… Defined … Indep… mpg add_p
#> 2 Variance assumption welch… var_… User-spe… Welch… mpg add_p
#> 3 Automatic test sel… Welch… Appr… No marke… Two-g… mpg add_p
#> 4 Distribution guida… param… Appr… Marked a… Asses… mpg add_p
#> 5 Observed group spr… descr… 0 (n… Descript… Obser… mpg add_p
#> 6 Comparison design indep… Inde… Defined … Indep… wt add_p
#> 7 Variance assumption welch… var_… User-spe… Welch… wt add_p
#> 8 Automatic test sel… Welch… Poss… No marke… Two-g… wt add_p
#> 9 Distribution guida… param… Poss… Marked a… Asses… wt add_p
#> 10 Observed group spr… descr… 0 (n… Descript… Obser… wt add_p
#> 11 Comparison design indep… Inde… Defined … Indep… cyl add_p
#> 12 Variance assumption not_a… var_… Applies … `var_… cyl add_p
#> 13 Automatic test sel… Fishe… 2.84 No expec… Indep… cyl add_p
#> 14 Expected cell coun… sparse 2.84 No expec… Fishe… cyl add_p
#> 15 Comparison design indep… Inde… Defined … Indep… vs add_p
#> 16 Variance assumption not_a… var_… Applies … `var_… vs add_p
#> 17 Automatic test sel… Chi-s… 5.69 No expec… Indep… vs add_p
#> 18 Expected cell coun… guida… 5.69 No expec… Fishe… vs add_p
adjusted$denominators
#> # A tibble: 14 × 9
#> variable level group n_total n_nonmissing n_missing numerator denominator
#> <chr> <chr> <chr> <int> <int> <int> <dbl> <dbl>
#> 1 mpg <NA> am = 1 13 13 0 NA 13
#> 2 mpg <NA> am = 0 19 19 0 NA 19
#> 3 wt <NA> am = 1 13 13 0 NA 13
#> 4 wt <NA> am = 0 19 19 0 NA 19
#> 5 cyl 4 am = 1 13 13 0 8 13
#> 6 cyl 4 am = 0 19 19 0 3 19
#> 7 cyl 6 am = 1 13 13 0 3 13
#> 8 cyl 6 am = 0 19 19 0 4 19
#> 9 cyl 8 am = 1 13 13 0 2 13
#> 10 cyl 8 am = 0 19 19 0 12 19
#> 11 vs 0 am = 1 13 13 0 6 13
#> 12 vs 0 am = 0 19 19 0 12 19
#> 13 vs 1 am = 1 13 13 0 7 13
#> 14 vs 1 am = 0 19 19 0 7 19
#> # ℹ 1 more variable: rule <chr>For a readable audit table, use
diagnostics_stats(adjusted). For continuous variables it
includes observed group SDs and variances as descriptive context; these
values do not act as a variance-test gatekeeper because Welch methods do
not require equal variances.
denominators_stats(adjusted) provides a compact audit
table showing the observations contributing to every variable and
group.
Pass a named character vector to test to override the
automatic selection for specific variables:
summary_table(mtcars, by = am, include = c(mpg, wt, cyl)) |>
add_p(test = c(mpg = "welch_t", wt = "wilcox", cyl = "chisq")) |>
to_gt()| Characteristic1 | 1 N = 131 |
0 N = 191 |
p-value2 |
|---|---|---|---|
| mpg | 24.4 (6.2) | 17.1 (3.8) | 0.001ᵃ |
| wt | 2.4 (0.6) | 3.8 (0.8) | <0.001ᵇ |
| cyl | 0.013ᶜ | ||
| 4 | 8 (61.5%) | 3 (15.8%) | |
| 6 | 3 (23.1%) | 4 (21.1%) | |
| 8 | 2 (15.4%) | 12 (63.2%) | |
| 1 Continuous data are mean (SD). Categorical data are n (%). | |||
| 2 ᵃ Welch t-test; ᵇ Wilcoxon rank-sum test; ᶜ Chi-square test | |||
Supported methods: "auto", "welch_t",
"t_test", "wilcox", "anova",
"welch_anova", "rm_anova",
"kruskal", "friedman", "chisq",
"fisher", "mcnemar", and
"cochran_q".
For before/after or matched data, use paired = TRUE:
dat <- data.frame(
id = rep(1:4, 2),
period = c("before", "before", "before", "before",
"after", "after", "after", "after"),
score = c(10, 12, 9, 11, 13, 16, 11, 15)
)
summary_table(dat, by = period, include = score) |>
add_p(paired = TRUE, id = id, test = "wilcox") |>
to_gt()| Characteristic1 | before N = 41 |
after N = 41 |
p-value2,3 |
|---|---|---|---|
| score | 10.5 (1.3) | 13.8 (2.2) | 0.098ᵃ |
| 1 Continuous data are mean (SD). | |||
| 2 ᵃ Wilcoxon signed-rank test | |||
| 3 score: paired p-value used 4 complete pairs; 0 excluded because complete matched observations were unavailable. | |||
add_rate() appends an event rate row calculated per a
chosen multiplier, with exact Poisson confidence intervals. This is
useful when your dataset contains event counts and person-time
denominators.
summary_table(mtcars, by = am, overall = TRUE) |>
add_rate(
event = carb,
time = cyl,
label = "Carburettor rate",
multiplier = 1000
) |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
|---|---|---|---|
| Carburettor rate | 454.5 (365.5–558.7) | 575.8 (407.4–790.3) | 393.9 (294.2–516.6) |
| 1 Rates per 1,000 person-time use complete event-time pairs and 95% exact Poisson confidence intervals. | |||
add_row() inserts a free-text row — useful for study
period notes, data source annotations, or any label that does not come
from a variable.
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_row(
label = "Study period",
overall = "2020–2024",
values = c("am = 1" = "2020–2024", "am = 0" = "2020–2024")
) |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
|---|---|---|---|
| mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) |
| wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) |
| cyl | |||
| 4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
| 6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
| 8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
| Study period | 2020–2024 | 2020–2024 | 2020–2024 |
| 1 Continuous data are mean (SD). Categorical data are n (%). | |||
Putting it all together — a complete, publication-ready descriptive table:
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs, level = "1", ci = TRUE) |>
add_total() |>
add_p() |>
to_gt()| Characteristic1 | Overall N = 321 |
1 N = 131 |
0 N = 191 |
p-value2 |
|---|---|---|---|---|
| mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) | 0.001ᵃ |
| wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) | <0.001ᵃ |
| cyl | 0.007ᵇ | |||
| 4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) | |
| 6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) | |
| 8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) | |
| vs (1) | 14 (43.8%); 28.2–60.7% | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% | |
| Total (N) | 32 | 13 | 19 | |
| 1 Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | ||||
| 2 ᵃ Welch t-test; ᵇ Fisher's exact test (Monte Carlo p-value) | ||||
customise_table() applies a visual theme and relabels
columns, rows, and factor levels. Pass the result directly; it returns a
flextable by default.
summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs) |>
add_total() |>
add_p() |>
customise_table(
theme = "journal",
title = "Table 1. Baseline characteristics by transmission type",
col_labels = c(
"Level" = "",
"am = 1" = "Manual",
"am = 0" = "Automatic"
),
row_labels = c(
"mpg" = "Miles per gallon",
"wt" = "Weight (1000 lbs)",
"cyl" = "Cylinders",
"vs (1)" = "V-shaped engine"
),
accent_color = "#123B7A"
)Table 1. Baseline characteristics by transmission type | ||||
|---|---|---|---|---|
Characteristic | Overall | Manual | Automatic | p-value |
mpg | 20.1 (6.0) | 24.4 (6.2) | 17.1 (3.8) | 0.001ᵃ |
wt | 3.2 (1.0) | 2.4 (0.6) | 3.8 (0.8) | <0.001ᵃ |
cyl | 0.007ᵇ | |||
4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) | |
6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) | |
8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) | |
vs (1) | 14 (43.8%); 28.2–60.7% | 7 (53.8%); 29.1–76.8% | 7 (36.8%); 19.1–59.0% | |
Total (N) | 32 | 13 | 19 | |
Continuous data are mean (SD). Categorical data are n (%). Confidence intervals: 95% intervals use the Wilson score method. | ||||
ᵃ Welch t-test; ᵇ Fisher's exact test (Monte Carlo p-value) | ||||
Available themes: "default", "journal",
"classic", "minimal",
"compact".
Customisation is deliberately separated from analysis. It changes how the completed table looks, never its estimates, denominators, confidence intervals, or tests.
| Task | Argument | Default and useful choices |
|---|---|---|
| Choose the renderer | engine |
"flextable" (default, Word/PowerPoint friendly) or
"gt" (HTML focused) |
| Apply a visual preset | theme |
"default", "journal",
"classic", "minimal",
"compact" |
| Add headings | title, subtitle |
One character value or NULL |
| Add explanatory text | source_note, footnotes |
One source note and/or a character vector of extra footnotes |
| Rename columns | col_labels |
Named vector: current column name = new label |
| Rename variable rows | row_labels |
Named vector: current row label = new label |
| Rename category levels | level_labels |
Named vector: current level = new level |
| Group columns visually | spanning_header |
One heading for result columns, or a named list mapping headings to columns |
| Align columns | align |
Named list containing left, center, and/or
right column names |
| Remove columns visually | hide_cols |
Character vector of completed column names |
| Emphasise columns | bold_cols, italic_cols |
Character vectors of completed column names |
| Control typography | font_size, font |
Numeric size and an installed font name |
| Control table width | width |
Percentage from 0 to 100 for gt output |
| Control individual widths | column_widths |
Named numeric widths in inches for flextable output |
| Add alternating rows | row_striping, stripe_color |
TRUE/FALSE and a colour such as
"#F4F4F2" |
| Set the accent | accent_color |
Hex colour used for rules and emphasis |
| Choose borders | borders |
"horizontal", "all", or
"minimal" |
| Change row spacing | density |
"standard", "compact", or
"spacious" |
| Retain/remove package notes | show_footnotes |
TRUE or FALSE |
| Emphasise variable labels | bold_labels |
TRUE or FALSE |
| Format p-values | pvalue_style |
"threshold", "fixed", or
"scientific" |
| Tune p-values | pvalue_digits, pvalue_threshold,
pvalue_prefix |
Digits, threshold, and optional p = prefix |
finished_table <- summary_table(
birthwt,
by = low,
include = c(age, lwt, race, smoke),
overall = "last",
show_dichotomous = "single_row",
value = c(smoke = "Yes")
) |>
add_p() |>
customise_table(
theme = "journal",
title = "Table 1. Maternal characteristics",
spanning_header = "Birth-weight outcome",
density = "compact",
borders = "horizontal",
font_size = 9,
pvalue_style = "threshold",
pvalue_digits = 3,
accent_color = "#4A4A4A",
show_footnotes = TRUE
)Mappings always use current = new. Inspect the completed
table first when you are unsure of a displayed column name.
summary_table(birthwt, by = low, include = c(race, smoke)) |>
customise_table(
col_labels = c(
"low = Normal birth weight" = "Normal birth weight",
"low = Low birth weight" = "Low birth weight"
),
row_labels = c("Maternal race" = "Race"),
level_labels = c("Yes" = "Smoker", "No" = "Non-smoker")
)Characteristic | Normal birth weight | Low birth weight |
|---|---|---|
Maternal race | ||
Black | 15 (11.5%) | 11 (18.6%) |
Other | 42 (32.3%) | 25 (42.4%) |
White | 73 (56.2%) | 23 (39.0%) |
Smoking during pregnancy | ||
No | 86 (66.2%) | 29 (49.2%) |
Yes | 44 (33.8%) | 30 (50.8%) |
Categorical data are n (%). | ||
Use this only when the meaning of every statistic is defined in the manuscript text, caption, or journal template.
summary_table(birthwt, include = c(age, race, smoke)) |>
customise_table(
theme = "minimal",
show_footnotes = FALSE,
bold_labels = TRUE,
density = "compact"
)Characteristic | Overall |
|---|---|
Maternal age (years) | 23.2 (5.3) |
Maternal race | |
White | 96 (50.8%) |
Black | 26 (13.8%) |
Other | 67 (35.4%) |
Smoking during pregnancy | |
No | 115 (60.8%) |
Yes | 74 (39.2%) |
You can also relabel factor levels within the table using
level_labels:
summary_table(mtcars, by = am, include = cyl, overall = TRUE) |>
customise_table(
level_labels = c(
"4" = "4-cylinder",
"6" = "6-cylinder",
"8" = "8-cylinder"
)
)Characteristic | Overall | 1 | 0 |
|---|---|---|---|
cyl | |||
4 | 11 (34.4%) | 8 (61.5%) | 3 (15.8%) |
6 | 7 (21.9%) | 3 (23.1%) | 4 (21.1%) |
8 | 14 (43.8%) | 2 (15.4%) | 12 (63.2%) |
Categorical data are n (%). | |||
Results already print as flextables. Call to_flextable()
explicitly when you want to set its font or autofit behaviour at
conversion time.
res <- summary_table(mtcars, by = am, include = c(mpg, wt, cyl), overall = TRUE) |>
add_proportion(var = vs) |>
add_total() |>
add_p()
ft <- to_flextable(res)In an R Markdown or Quarto document targeting Word output, simply
print ft in a chunk and it will appear as a formatted table
in the document.
The gtstats table builder lets you assemble a complete “Table 1” with very little code:
summary_table(data, by = group, overall = TRUE)
|> add_ci(vars = c(...))
|> add_p()
|> add_proportion(var = ...)
|> add_total()
|> customise_table(theme = "journal", ...)
Each add_*() function is independent — add only the rows
your table needs, in any order that makes sense for your report.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.