Overview
table_or() automates the creation of publication-ready odds ratio tables from logistic regression models. This vignette shows how to:
Generate programmatic tibble output for downstream analysis and reporting
Create formatted HTML tables with {gt} for manuscripts and reports
Customise confidence levels, anonymisation and styling
Export tables for publication
When to use this function
Use table_or() when you need to:
Present logistic regression results in a standardised, publication-ready format
Create tables that comply with reporting guidelines, (e.g., STROBE guidelines for observational studies)
Combine or compare results across multiple models
Ensure consistent interpretation guidance for readers (via footnotes)
Balance transparency with data privacy (via anonymisation options)
Quick example - minimal workflow
# create a small example dataset
rows <- 400
df <- data.frame(
outcome = rbinom(n = rows, size = 1, prob = 0.25) |>
factor(labels = c("Healthy", "Disease")),
age = rnorm(n = rows, mean = 50, sd = 12),
sex = sample(x = 0:1, size = rows, replace = TRUE) |>
factor(labels = c("Female", "Male")),
smoke = sample(x = 0:2, size = rows, replace = TRUE) |>
factor(labels = c("Never", "Former", "Current"))
)
# fit a logistic regression model
m <- glm(
formula = outcome ~ age + sex + smoke,
family = "binomial",
data = df
)Programmatic output (tibble)
Use the tibble output for downstream manipulation, reporting or combining results across models.
table_or(m, output = "tibble")
#> # A tibble: 6 × 14
#> label level rows outcome outcome_rate class estimate std.error statistic
#> <fct> <fct> <int> <int> <dbl> <chr> <dbl> <dbl> <dbl>
#> 1 age age 400 97 0.242 numeric 0.990 0.00996 -1.04
#> 2 sex Female 206 53 0.257 factor NA NA NA
#> 3 sex Male 194 44 0.227 factor 0.856 0.235 -0.663
#> 4 smoke Never 137 34 0.248 factor NA NA NA
#> 5 smoke Former 135 34 0.252 factor 1.03 0.281 0.0997
#> 6 smoke Current 128 29 0.227 factor 0.902 0.290 -0.356
#> # ℹ 5 more variables: p.value <dbl>, conf.low <dbl>, conf.high <dbl>,
#> # significance <chr>, comparator <dbl>Key columns returned:
label: Variable name or predictor group (e.g., “age”, “sex”, “smoke”)
level: Specific level or term shown for the row (numeric variable name or factor level label)
rows: Number of observations used to estimate the row (rows in the model / data subset for that term)
outcome: Count of outcome events (cases) observed for that row / level
outcome_rate: Proportion of observations with the outcome (outcome / rows)
class: Data type of the predictor shown in this row (e.g., “numeric”, “factor”)
estimate: Model coefficient on the link (log-odds) scale; NA for comparator / reference rows
std.error: Standard error of the coefficient estimate
statistic: Test statistic for the coefficient (e.g., z or t value from the model)
p.value: Two-sided p-value for the coefficient test
conf.low: Lower bound of the confidence interval for the odds ratio (exponentiated coefficient)
conf.high: Upper bound of the confidence interval for the odds ratio (exponentiated coefficient)
signfiicance: Human-readable summary of statistical evidence (e.g., “Not significant”, “Significant” or “Comaparator”)
comparator: Indicates reference / comparator rows (e.g., “1” for the first level of factors)
Estimates are shown as coefficients on the log-odds scale (estimate / std.error / statistic / p.value) with confidence intervals presented for exponentiated results (conf.low / conf.high).
Interpreting the results
OR > 1: increased odds of the outcome
OR < 1: decreased odds of the outcome
OR = 1: No association
Confidence interval crosses 1.0: not statistically significant
Formatted HTML table (gt)
Create a publication-ready table using gt formatting.
table_or(m, output = "gt")| outcome | ||||||||||||
| Odds Ratio summary table with 95% Confidence Interval | ||||||||||||
Characteristic1
|
Odds Ratio (OR)2
|
95% Confidence Interval (CI)3
|
OR Plot | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Level | N | n | Rate | Class | OR | SE | p | Lower | Upper | Significance | ||
| age | age | 400 | 97 | 24.25% | numeric | 0.9897 | 0.009961 | 3.00 × 10−1 | 0.9705 | 1.009 | Not significant | |
| sex | Female | 206 | 53 | 25.73% | factor | — | — | — | — | — | Comparator | |
| Male | 194 | 44 | 22.68% | factor | 0.8558 | 0.2350 | 5.07 × 10−1 | 0.5385 | 1.355 | Not significant | ||
| smoke | Never | 137 | 34 | 24.82% | factor | — | — | — | — | — | Comparator | |
| Former | 135 | 34 | 25.19% | factor | 1.028 | 0.2808 | 9.21 × 10−1 | 0.5923 | 1.786 | Not significant | ||
| Current | 128 | 29 | 22.66% | factor | 0.9018 | 0.2903 | 7.22 × 10−1 | 0.5085 | 1.592 | Not significant | ||
|
1
Characteristics are the explanatory variables in the logistic regression analysis. For categorical variables the first characteristic is designated as a reference against which the others are compared. For numeric variables the results indicate a change per single unit increase.
Level - the name or the description of the explanatory variable. N - the number of observations examined. n - the number of observations resulting in the outcome of interest. Rate - the proportion of observations resulting in the outcome of interest (n / N). Class - description of the data type. |
||||||||||||
|
2
Odds Ratios estimate the relative odds of an outcome with reference to the Characteristic. For categorical data the first level is the reference against which the odds of other levels are compared. Numerical characteristics indicate the change in OR for each additional increase of one unit in the variable.
OR - The Odds Ratio point estimate - values below 1 indicate an inverse relationship whereas values above 1 indicate a positive relationship. Values shown to 4 significant figures. SE - Standard Error of the point estimate. Values shown to 4 significant figures. p - The p-value estimate based on the residual Chi-squared statistic. |
||||||||||||
|
3
Confidence Interval - the range of values likely to contain the OR in 95% of cases if this study were to be repeated multiple times. If the CI touches or crosses the value 1 then it is unlikely the Characteristic is significantly associated with the outcome.
Lower & Upper - The range of values comprising the CI, shown to 4 significant figures. Significance - The statistical significance indicated by the CI, Significant where the CI does not touch or cross the value 1. |
||||||||||||
What the gt output includes
The HTML table includes:
Formatted odds ratios with confidence intervals
Mini forest plot visualising effect sizes
Comprehensive footnotes that help readers interpret results
Understanding the footnotes
The footnotes clarify:
Interpretation of OR values: explaining that values below 1 indicate inverse relationships and above 1 indicate positive relationships
Variable type handling: showing how categorical variables (reference vs comparison levels) and numeric variables (per-unit change) are presented differently
Significance rule: making clear that confidence intervals crossing 1.0 are presented differently
Precision: specifying that values are shown to 4 significant figures
Metric definitions: ensureing readers understand OR, SE, p-value and CI without external references
Common customisations
Change confidence level
Report 90% confidence intervals for sensitivity analysis or different reporting standards:
table_or(m, output = "tibble", conf_level = 0.90)
#> # A tibble: 6 × 14
#> label level rows outcome outcome_rate class estimate std.error statistic
#> <fct> <fct> <int> <int> <dbl> <chr> <dbl> <dbl> <dbl>
#> 1 age age 400 97 0.242 numeric 0.990 0.00996 -1.04
#> 2 sex Female 206 53 0.257 factor NA NA NA
#> 3 sex Male 194 44 0.227 factor 0.856 0.235 -0.663
#> 4 smoke Never 137 34 0.248 factor NA NA NA
#> 5 smoke Former 135 34 0.252 factor 1.03 0.281 0.0997
#> 6 smoke Current 128 29 0.227 factor 0.902 0.290 -0.356
#> # ℹ 5 more variables: p.value <dbl>, conf.low <dbl>, conf.high <dbl>,
#> # significance <chr>, comparator <dbl>Anonymise counts for sensitive data
Improve data privacy by rounding counts to the nearest five and suppressing counts below ten. This is useful when working with sensitive dataset under strict information governance requirements:
table_or(m, output = "tibble", anonymise_counts = TRUE)
#> # A tibble: 6 × 14
#> label level rows outcome outcome_rate class estimate std.error statistic
#> <fct> <fct> <chr> <chr> <dbl> <chr> <dbl> <dbl> <dbl>
#> 1 age age 400 95 0.242 numeric 0.990 0.00996 -1.04
#> 2 sex Female 205 55 0.257 factor NA NA NA
#> 3 sex Male 195 45 0.227 factor 0.856 0.235 -0.663
#> 4 smoke Never 135 35 0.248 factor NA NA NA
#> 5 smoke Former 135 35 0.252 factor 1.03 0.281 0.0997
#> 6 smoke Current 130 30 0.227 factor 0.902 0.290 -0.356
#> # ℹ 5 more variables: p.value <dbl>, conf.low <dbl>, conf.high <dbl>,
#> # significance <chr>, comparator <dbl>Combine results from multiple models
Compare models by binding tibble outputs:
# fit a second model
m2 <- glm(
formula = outcome ~ age + sex,
family = "binomial",
data = df
)
# combine results
combined_results <-
dplyr::bind_rows(
dplyr::bind_cols(model = "Model 1", table_or(m)),
dplyr::bind_cols(model = "Model 2", table_or(m2))
)
head(combined_results)
#> # A tibble: 6 × 15
#> model label level rows outcome outcome_rate class estimate std.error
#> <chr> <fct> <fct> <int> <int> <dbl> <chr> <dbl> <dbl>
#> 1 Model 1 age age 400 97 0.242 numeric 0.990 0.00996
#> 2 Model 1 sex Female 206 53 0.257 factor NA NA
#> 3 Model 1 sex Male 194 44 0.227 factor 0.856 0.235
#> 4 Model 1 smoke Never 137 34 0.248 factor NA NA
#> 5 Model 1 smoke Former 135 34 0.252 factor 1.03 0.281
#> 6 Model 1 smoke Current 128 29 0.227 factor 0.902 0.290
#> # ℹ 6 more variables: statistic <dbl>, p.value <dbl>, conf.low <dbl>,
#> # conf.high <dbl>, significance <chr>, comparator <dbl>Exporting tables
Export to HTML file
Export to Word document
Export to CSV (tibble)
Tips for publication
Choose your output format wisely: use “tibble” for flexibility and downstream analysis; use “gt” for direct inclusion in manuscripts or reports
Select relevant columns: not all columns are needed for publication; consider your audience and journal requirements
Check the confidence interval rule: always verify that your signifiance conslusions match the CI crossing rule (CI does not cross 1.0 = significant)
Report the confidence level: specify whether you’re using 95% (default), 90% or another confidence level
Use anonymisation for sensitive data: when sharing tables with restricted data, use
anonymise_counts = TRUE
Conclusion
The table_or() function automates the creation of publication-ready odds ratio tables from logistic regression models, eliminating manual calculation and formatting while ensuring consistent presentation of results with appropriate statistical annotations.
See also
vignette("plot_or")- detailed plotting options and themesvignette("check_or")- diagnostics and case studiesgt::gt()- formatted table creation
