class: inverse, center, title-slide, middle # Reporting Research Study Results with {gtsummary} ### Daniel D. Sjoberg #### April 27, 2022 <p align="center"><img src="Images/White-Transparent.png" width=30%></p> .medium[ <svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FFFFFF;" xmlns="http://www.w3.org/2000/svg"> <path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg> @statistishdan <svg viewBox="0 0 496 512" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FFFFFF;" xmlns="http://www.w3.org/2000/svg"> <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg> @ddsjoberg ] --- class: inverse, center, middle # Motivation --- # The reproducibility crisis .pull-left[ .large[ - Quality of medical research is often low - **Low quality code** in medical research part of the problem - Low quality code is more likely to **contain errors** - Reproducibility is often **cumbersome** and **time-consuming** ] ] .pull-right[ <p align="center"><img src="Images/reproducibility-graphic-online1.jpeg" width=90%></p> ] .footnote[Image source: https://www.nature.com/news/1-500-scientists-lift-the-lid-on-reproducibility-1.19970] --- # {gtsummary} overview .pull-left[ * Create **tabular summaries** with sensible defaults but highly customizable * Types of summaries: - "Table 1"-types - Cross-tabulation - Regression models - Survival data - Survey data - Custom tables * Report statistics from {gtsummary} tables **inline** in R Markdown * Stack and/or merge any table type * Use **themes** to standardize across tables * Choose from different **print engines** ] .pull-right[ <img src="Images/gtsummary_logo.png" width=80%> ] --- # {gtsummary} example dataset * The `trial` dataset is included with {gtsummary} * Simulated dataset of baseline characteristics for 200 patients who receive Drug A or Drug B * Variables were assigned labels using the `labelled` package ```r library(gtsummary) library(tidyverse) head(trial) ``` ``` ## # A tibble: 6 × 8 ## trt age marker stage grade response death ttdeath ## <chr> <dbl> <dbl> <fct> <fct> <int> <int> <dbl> ## 1 Drug A 23 0.16 T1 II 0 0 24 ## 2 Drug B 9 1.11 T2 I 1 0 24 ## 3 Drug A 31 0.277 T1 II 0 0 24 ## 4 Drug A NA 2.07 T3 III 1 1 17.6 ## 5 Drug A 51 2.77 T4 III 1 1 16.4 ## 6 Drug B 39 0.613 T4 I 0 1 15.6 ``` --- # {gtsummary} example dataset .pull-left[ This presentation will use a subset of the variables. ```r sm_trial <- trial %>% select(trt, age, grade, response) ``` ] .pull-right[ <p align="center"><img src="Images/sm_trial_info.png" width=90%></p> ] --- class: inverse, center, middle # tbl_summary() --- # Basic tbl_summary() .pull-left[ ```r tbl_summary_1 <- sm_trial %>% select(-trt) %>% tbl_summary() ``` .medium[ - Four types of summaries: `continuous`, `continuous2`, `categorical`, and `dichotomous` - Statistics are `median (IQR)` for continuous, `n (%)` for categorical/dichotomous - Variables coded `0/1`, `TRUE/FALSE`, `Yes/No` treated as dichotomous - Lists `NA` values under "Unknown" - Label attributes are printed automatically ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_1.png" width=55%></p> ] --- # Customize tbl_summary() output .pull-left[ ```r tbl_summary_2 <- sm_trial %>% tbl_summary( by = trt, type = age ~ "continuous2", statistic = list(age ~ c("{mean} ({sd})", "{min}, {max}"), response ~ "{n} / {N} ({p}%)"), label = grade ~ "Pathologic tumor grade", digits = age ~ 1 ) ``` .small[ - `by`: specifies a column variable for cross-tabulation - `type`: specifies the summary type - `statistic`: customize the reported statistics - `label`: change or customize variable labels - `digits`: specify the number of decimal places for rounding ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_2.png" width=90%></p> ] --- # {gtsummary} + formulas <p align="center"><img src="https://raw.githubusercontent.com/ddsjoberg/gtsummary-weill-cornell-presentation/5887c81b58f4ed0c76f6ae458243e9c2a2fbbcd2/Images/Dan-SummaryTables-5.png" width=95%></p> --- # Add-on functions in {gtsummary} .xlarge[ `tbl_summary()` objects can also be updated using related functions. - `add_*()` add additional column of statistics or information, e.g. p-values, q-values, overall statistics, treatment differences, N obs., and more - `modify_*()` modify table headers, spanning headers, footnotes, and more - `bold_*()/italicize_*()` style labels, variable levels, significant p-values ] --- # Update tbl\_summary() with add\_\*() .pull-left[ ```r tbl_summary_3a <- sm_trial %>% tbl_summary( by = trt ) %>% add_p() %>% add_q(method = "fdr") ``` .medium[ * `add_p()`: adds a column of p-values * `add_q()`: adds a column of p-values adjusted for multiple comparisons through a call to `p.adjust()` ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_3a.png" width=100%></p> ] --- # Update tbl\_summary() with add\_\*() .pull-left[ ```r tbl_summary_3ab <- trial %>% select(trt, marker, response) %>% tbl_summary( by = trt, statistic = list(marker ~ "{mean} ({sd})", response ~ "{p}%"), missing = "no" ) %>% add_difference() ``` ] .pull-right[ .medium[ * `add_difference()`: mean and rate differences between two groups. Can also be adjusted differences ] ] <p align="center"><img src="Images/tbl_summary_3ab.png" width=65%></p> --- # Update tbl\_summary() with add\_\*() .pull-left[ ```r tbl_summary_3b <- sm_trial %>% tbl_summary( by = trt, missing = "no" ) %>% add_overall() %>% add_n() %>% add_stat_label( label = all_categorical() ~ "No. (%)" ) ``` .medium[ * `add_overall()`: adds a column of overall statistics * `add_n()`: adds a column with the sample size * `add_stat_label()`: adds a description of the reported statistic ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_3b.png" width=100%></p> ] --- # Update tbl\_summary() with add\_\*() .pull-left[ ```r tbl_summary_3b <- sm_trial %>% select(age, marker, trt) tbl_summary( by = trt, missing = "no" ) %>% add_stat(...) ``` .large[ - Customize statistics presented with `add_stat()` - Added statistics can be placed on the label or the level rows - Added statistics may be a single column or multiple ] ] .pull-right[ <p align="center"><img src="Images/add_stat_ex2.png" width=100%></p> ] --- # Update with bold\_\*()/italicize\_\*() .pull-left[ ```r tbl_summary_4 <- sm_trial %>% tbl_summary( by = trt ) %>% add_p() %>% bold_labels() %>% italicize_levels() %>% bold_p(t = 0.8) ``` .medium[ * `bold_labels()`: bold the variable labels * `italicize_levels()`: italicize the variable levels * `bold_p()`: bold p-values according a specified threshold ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_4.png" width=100%></p> ] --- # Update tbl\_summary() with modify\_\*() .pull-left[ .tiny[ ```r tbl_summary_5 <- sm_trial %>% select(age, response, trt) %>% tbl_summary( by = trt, missing = "no" ) %>% modify_header( update = list( stat_1 ~ "**A**", stat_2 ~ "**B**" )) %>% modify_spanning_header( update = all_stat_cols() ~ "**Drug**") %>% modify_footnote( update = all_stat_cols() ~ "median (IQR) for continuous; n (%) for categorical" ) ``` ] ] .pull-right[ <p align="center"><img src="Images/tbl_summary_5.png" width=90%></p> ] * Use `show_header_names()` to see the internal header names available for use in `modify_header()` --- # Add-on functions in {gtsummary} .xlarge[ And many more! See the documentation at http://www.danieldsjoberg.com/gtsummary/reference/index.html And a detailed `tbl_summary()` vignette at http://www.danieldsjoberg.com/gtsummary/articles/tbl_summary.html ] --- # Cross-tabulation with tbl_cross() .large[`tbl_cross()` is a wrapper for `tbl_summary()` for **n x m** tables] .pull-left[ <br> ```r tbl_cross_1 <- sm_trial %>% tbl_cross( row = trt, col = grade, percent = "row", margin = "row" ) %>% add_p(source_note = TRUE) ``` ] .pull-right[ <p align="center"><img src="Images/tbl_cross_1.png" width=90%></p> ] --- # Continuous Summaries with tbl_continuous() .large[`tbl_continuous()` summarizes a continuous variable by 1, 2, or more categorical variables] .pull-left[ <br> ```r tbl_continuous_1 <- sm_trial %>% tbl_continuous( variable = age, by = trt, include = grade ) ``` ] .pull-right[ <p align="center"><img src="Images/tbl_continuous_1.png" width=90%></p> ] --- # Survey data with tbl_svysummary() .pull-left[ <br> ```r tbl_svysummary <- survey::svydesign( ids = ~1, data = as.data.frame(Titanic), weights = ~Freq ) %>% tbl_svysummary(by = Survived) %>% add_p() %>% modify_spanning_header( all_stat_cols() ~ "**Survived**") ``` ] .pull-right[ <p align="center"><img src="Images/tbl_svysummary.png" width=70%></p> ] --- # Survival outcomes with tbl_survfit() ```r library(survival) fit <- survfit(Surv(ttdeath, death) ~ trt, trial) tbl_survfit_1 <- tbl_survfit( fit, times = c(12, 24), label_header = "**{time} Month**" ) %>% add_p() ``` <p align="center"><img src="Images/tbl_survfit_1.png" width=60%></p> --- class: inverse, center, middle # tbl_regression() --- # Traditional model summary() .pull-left[ ```r m1 <- glm( response ~ age + stage, data = trial, family = binomial(link = "logit") ) summary(m1) ``` .medium[ Looks **messy** and it's not easy for others to understand. ] ] .pull-right[ <p align="center"><img src="Images/messy-model-output.png" width=100%></p> ] --- # Basic tbl_regression() .pull-left[ ```r m1_tbl_1 <- tbl_regression( m1 ) ``` .medium[ - Displays **p-values** for covariates - Shows **reference levels** for categorical variables ] ] .pull-right[ <p align="center"><img src="Images/m1_tbl_1.png" width=90%></p> ] --- # Customize tbl_regression() output .pull-left[ ```r m1_tbl_2 <- tbl_regression( m1, exponentiate = TRUE ) %>% add_global_p() %>% add_glance_table( include = c(nobs, logLik, AIC, BIC)) ``` .medium[ - Display **odds ratio** estimates and **confidence intervals** - Add global p-values - Add various model statistics ] ] .pull-right[ <p align="center"><img src="Images/m1_tbl_2.png" width=62%></p> ] --- # Supported models in tbl_regression() .xlarge[ `stats::lm()`, `stats::glm()`, `stats::aov()`, `ordinal::clm()`, `ordinal::clmm()`, `survival::coxph()`, `survival::survreg()`, `survival::clogit()`, `lme4::lmer()`, `lme4::glmer()`, `lme4::glmer.nb()`, `brms::brm()`, `geepack::geeglm()`, `gam::gam()`, `glmmTMB::glmmTMB()`, `mgcv::gam()`, `nnet::multinom()`, `survey::svyglm()`, `survey::svycoxph()`, `survey::svyolr()`, `MASS::polr()`, `MASS::glm.nb()`, `mice::mira`, `lavaan::lavaan()`, `stats::nls()`, `lfe::felm()`, `rstanarm::stan_glm()`, `VGAM::vglm()`, `cmprsk::crr()`, `tidycmprsk::crr()`, `plm::plm()` ] .large[**Custom tidiers** can be written and passed to `tbl_regression()` using the `tidy_fun=` argument.] --- # Univariate models with tbl_uvregression() .pull-left[ ```r tbl_uvreg <- sm_trial %>% tbl_uvregression( method = glm, y = response, method.args = list(family = binomial), exponentiate = TRUE ) ``` .medium[ - Specify model `method`, `method.args`, and the `response` variable - Arguments and helper functions like `exponentiate`, `bold_*()`, `add_global_p()` can also be used with `tbl_uvregression()` ] ] .pull-right[ <p align="center"><img src="Images/tbl_uvreg.png" width=90%></p> ] --- class: inverse, center, middle # inline_text() --- # {gtsummary} reporting with inline_text() .large[ - Tables are important, but we often need to report results in-line in a report. - Any statistic reported in a {gtsummary} table can be extracted and reported in-line in an R Markdown document with the `inline_text()` function. - The pattern of what is reported can be modified with the `pattern = ` argument. - Default is `pattern = "{estimate} ({conf.level*100}% CI {conf.low}, {conf.high}; {p.value})"`. ] --- # {gtsummary} reporting with inline_text() <p align="center"><img src="Images/tbl_uvreg.png" width=30%></p> **In Code:** The odds ratio for age is '` r inline_text(tbl_uvreg, variable = age)`' **In Report:** The odds ratio for age is 1.02 (95% CI 1.00, 1.04; p=0.10) --- class: inverse, center, middle # tbl_merge()/tbl_stack() --- # tbl_merge() for side-by-side tables .pull-left[ A **univariable** table: ```r library(survival) tbl_uvsurv <- trial %>% select(age, grade, death, ttdeath) %>% tbl_uvregression( method = coxph, y = Surv(ttdeath, death), exponentiate = TRUE ) %>% add_global_p() ``` ] .pull-right[ A **multivariable** table: ```r library(survival) tbl_mvsurv <- coxph( Surv(ttdeath, death) ~ age + grade, data = trial ) %>% tbl_regression( exponentiate = TRUE ) %>% add_global_p() ``` ] --- # tbl_merge() for side-by-side tables .pull-left[ A **univariable** table: <p align="center"><img src="Images/tbl_uvsurv.png" width=90%></p> ] .pull-right[ A **multivariable** table: <p align="center"><img src="Images/tbl_mvsurv.png" width=85%></p> ] --- # tbl_merge() for side-by-side tables ```r tbl_surv_merge <- tbl_merge( list(tbl_uvsurv, tbl_mvsurv), tab_spanner = c("**Univariable**", "**Multivariable**") ) ``` <p align="center"><img src="Images/tbl_surv_merge.png" width=48%></p> --- # tbl_stack() to combine vertically .pull-left[ An **unadjusted** model: ```r t3 <- coxph(Surv(ttdeath, death) ~ trt, data = trial) %>% tbl_regression( show_single_row = trt, label = trt ~ "Drug B vs A", exponentiate = TRUE ) ``` ] .pull-right[ An **adjusted** model: ```r t4 <- coxph(Surv(ttdeath, death) ~ trt + grade + stage + marker, data = trial) %>% tbl_regression( show_single_row = trt, label = trt ~ "Drug B vs A", exponentiate = TRUE, include = "trt" ) ``` ] --- # tbl_stack() to combine vertically .pull-left[ An **unadjusted** model: <p align="center"><img src="Images/t3.png" width=90%></p> ] .pull-right[ An **adjusted** model: <p align="center"><img src="Images/t4.png" width=90%></p> ] --- # tbl_stack() to combine vertically ```r tbl_surv_stack <- tbl_stack( list(t3, t4), group_header = c("Unadjusted", "Adjusted") ) ``` <p align="center"><img src="Images/tbl_surv_stack.png" width=38%></p> --- # tbl_strata() for stratified tables ```r tbl_strata <- sm_trial %>% mutate(grade = paste("Grade", grade)) %>% tbl_strata( strata = grade, ~tbl_summary(.x, by = trt, missing = "no") %>% modify_header(all_stat_cols() ~ "**{level}**") ) ``` <p align="center"><img src="Images/tbl_strata.png" width=85%></p> --- # Define custom function `tbl_cmh()` <p align="center"><img src="Images/tbl_cmh.png" width=68%></p> --- # Define custom functiont `tbl_cmh()` <p align="center"><img src="Images/tbl_cmh_markup.png" width=68%></p> --- # {gtreg} for regulatory submissions * The {gtreg} package uses {gtsummary} to construct tables for regulatory agencies. * https://shannonpileggi.github.io/gtreg/ <p align="center"><img src="Images/tbl_ae.png" width=68%></p> --- class: inverse, center, middle # {gtsummary} themes --- # {gtsummary} theme basics .large[ - A **theme** is a set of customization preferences that can be easily set and reused. - Themes control **default settings for existing functions** - Themes control more **fine-grained customization** not available via arguments or helper functions - Easily use one of the **available themes**, or **create your own** ] --- # {gtsummary} default theme .pull-left[ ```r reset_gtsummary_theme() no_theme <- tbl_regression(m1, exponentiate = TRUE) %>% modify_caption("Default Theme") ``` ] .pull-right[ <p align="center"><img src="Images/no_theme.png" width=80%></p> ] --- # {gtsummary} theme_gtsummary_journal() .pull-left[ ```r reset_gtsummary_theme() theme_gtsummary_journal(journal = "jama") jama_theme <- tbl_regression(m1, exponentiate = TRUE) %>% modify_caption("Journal Theme (JAMA)") ``` ] .pull-right[ <p align="center"><img src="Images/jama_theme.png" width=80%></p> ] .medium[ Contributions welcome! ] --- # {gtsummary} theme_gtsummary_language() .pull-left[ ```r reset_gtsummary_theme() theme_gtsummary_language(language = "zh-tw") lang_theme <- tbl_regression(m1, exponentiate = TRUE) %>% modify_caption("Language Theme (Chinese)") ``` ] .pull-right[ <p align="center"><img src="Images/lang_theme.png" width=66%></p> ] .medium[ Language options: "de" (German), "en" (English), "es" (Spanish), "fr" (French), "gu" (Gujarati), "hi" (Hindi), "is" (Icelandic),"ja" (Japanese), "kr" (Korean), "mr" (Marathi), "pt" (Portuguese), "se" (Swedish), "zh-cn" (Chinese Simplified), "zh-tw" (Chinese Traditional) ] --- # {gtsummary} theme_gtsummary_compact() .pull-left[ ```r reset_gtsummary_theme() theme_gtsummary_compact() compact_theme <- tbl_regression(m1, exponentiate = TRUE) %>% modify_caption("Compact Theme") ``` ] .pull-right[ <p align="center"><img src="Images/compact_theme.png" width=80%></p> ] .medium[ Reduces padding and font size ] --- # {gtsummary} set_gtsummary_theme() .large[ * `set_gtsummary_theme()` to use a custom theme. * See the {gtsummary} + themes vignette for examples http://www.danieldsjoberg.com/gtsummary/articles/themes.html ] --- class: inverse, center, middle # {gtsummary} print engines --- # {gtsummary} print engines <p align="center"><img src="Images/gtsummary_rmarkdown.png" width=70%></p> --- # {gtsummary} print engines Use any print engine to customize table .pull-left[ ```r library(gt, warn.conflicts = FALSE) print_engine <- trial %>% select(age, grade) %>% tbl_summary() %>% as_gt() %>% cols_width(label ~ px(300)) %>% cols_align(columns = stat_0, align = "left") ``` ] .pull-right[ <p align="center"><img src="Images/print_engine.png" width=70%></p> ] --- class: inverse, center, middle # In Closing --- # {gtsummary} website .large[http://www.danieldsjoberg.com/gtsummary/] <p align="center"><img src="Images/gtsummary_website.png" width=80%></p> --- # {gtsummary} installation .pull-left[ Install production version from CRAN: ```r install.packages("gtsummary") ``` ] .pull-right[ Install development version from GitHub: ```r remotes::install_github("ddsjoberg/gtsummary") ``` ] <p align="center"><img src="Images/cran-downloads.png" width=80%></p> --- # {gtsummary} sandbox in {bstfun} .large[http://www.danieldsjoberg.com/bstfun/] .pull-left[ <p align="center"><img src="Images/bstfun_website.jpg" width=80%></p> ] .pull-right[ <p align="center"><img src="Images/add_sparkline_ex1.png" width=80%></p> <p align="center"><img src="Images/add_inline_forest_plot_ex1.png" width=90%></p> ] --- # Thank you <img src = "https://github.com/ddsjoberg/gtsummary/raw/master/data-raw/misc_files/tbl_summary_demo1.gif" alt = "animated" width = "100%"> #### gtsummary questions? .medium[ <svg viewBox="0 0 384 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M290.7 311L95 269.7 86.8 309l195.7 41zm51-87L188.2 95.7l-25.5 30.8 153.5 128.3zm-31.2 39.7L129.2 179l-16.7 36.5L293.7 300zM262 32l-32 24 119.3 160.3 32-24zm20.5 328h-200v39.7h200zm39.7 80H42.7V320h-40v160h359.5V320h-40z"></path></svg> Ask on [stackoverflow.com](stackoverflow.com) and *use the gtsummary tag*. Hundreds of Qs already answered! <svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg> @statistishdan, <svg viewBox="0 0 496 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg> @ddsjoberg ] --- # gtsummary object ```r tbl <- tbl_summary(trial, by = trt, include = c(age, trt)) %>% add_p() tbl$table_body ``` ``` ## # A tibble: 2 × 12 ## variable test_name var_type var_label row_type label stat_1 stat_2 ## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> ## 1 age wilcox.test continuous Age label Age 46 (37, 59) 48 (39… ## 2 age wilcox.test continuous Age missing Unknown 7 4 ## # … with 4 more variables: test_result <list>, statistic <dbl>, p.value <dbl>, ## # alternative <chr> ``` --- # gtsummary object ```r names(tbl$table_styling) ``` ``` ## [1] "header" "footnote" "footnote_abbrev" "text_format" ## [5] "fmt_missing" "fmt_fun" "cols_merge" ``` ```r tbl$table_styling ``` ``` ## $header ## # A tibble: 12 × 11 ## column hide align interpret_label label interpret_spann… spanning_header ## <chr> <lgl> <chr> <chr> <chr> <chr> <chr> ## 1 variable TRUE cent… gt::md vari… gt::md <NA> ## 2 test_name TRUE cent… gt::md test… gt::md <NA> ## 3 var_type TRUE cent… gt::md var_… gt::md <NA> ## 4 var_label TRUE cent… gt::md var_… gt::md <NA> ## 5 row_type TRUE cent… gt::md row_… gt::md <NA> ## 6 label FALSE left gt::md **Ch… gt::md <NA> ## 7 stat_1 FALSE cent… gt::md **Dr… gt::md <NA> ## 8 stat_2 FALSE cent… gt::md **Dr… gt::md <NA> ## 9 test_resu… TRUE cent… gt::md test… gt::md <NA> ## 10 statistic TRUE cent… gt::md stat… gt::md <NA> ## 11 p.value FALSE cent… gt::md **p-… gt::md <NA> ## 12 alternati… TRUE cent… gt::md alte… gt::md <NA> ## # … with 4 more variables: modify_stat_N <int>, modify_stat_n <int>, ## # modify_stat_p <dbl>, modify_stat_level <chr> ## ## $footnote ## # A tibble: 3 × 4 ## column rows text_interpret footnote ## <chr> <list> <chr> <chr> ## 1 stat_1 <quosure> gt::md Median (IQR) ## 2 stat_2 <quosure> gt::md Median (IQR) ## 3 p.value <quosure> gt::md Wilcoxon rank sum test ## ## $footnote_abbrev ## # A tibble: 0 × 4 ## # … with 4 variables: column <chr>, rows <list>, text_interpret <chr>, ## # footnote <chr> ## ## $text_format ## # A tibble: 1 × 4 ## column rows format_type undo_text_format ## <chr> <list> <chr> <lgl> ## 1 label <language> indent FALSE ## ## $fmt_missing ## # A tibble: 0 × 3 ## # … with 3 variables: column <chr>, rows <list>, symbol <chr> ## ## $fmt_fun ## # A tibble: 1 × 3 ## column rows fmt_fun ## <chr> <list> <list> ## 1 p.value <quosure> <fn> ## ## $cols_merge ## # A tibble: 0 × 3 ## # … with 3 variables: column <chr>, rows <list>, pattern <chr> ``` --- # gtsummary object .pull-left[ ``` modify_table_styling( x, columns, rows = NULL, label = NULL, spanning_header = NULL, hide = NULL, footnote = NULL, footnote_abbrev = NULL, align = NULL, missing_symbol = NULL, fmt_fun = NULL, text_format = NULL, undo_text_format = FALSE, text_interpret = c("md", "html"), cols_merge_pattern = NULL ) ``` ] .large[ .pull-right[ `modify_header()` <br> `modify_footnote()` <br> `modify_spanning_header()` <br> `modify_caption()` <br> `modify_column_hide()` <br> `modify_column_unhide()` <br> `modify_fmt_fun()` <br> <br> `modify_table_body()` ] ]