Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Type: Package
Package: SummaryTables
Title: Publication-Ready Summary Tables for Jamovi
Version: 1.2.1
Version: 1.3.0
Authors@R:
person("Nour Edin", "Darwish", , "nouredindarwish@gmail.com", role = c("aut", "cre"),
comment = c(ORCID = "0009-0009-5527-4539"))
Expand Down Expand Up @@ -32,6 +32,7 @@ Imports:
cards (>= 0.7.1),
cardx (>= 0.3.1),
cli,
datawizard,
dplyr,
effectsize,
flextable,
Expand All @@ -50,7 +51,7 @@ Remotes:
insightsengineering/cards@v0.7.1,
insightsengineering/cardx@v0.3.1,
ddsjoberg/gtsummary@952b665
Config/roxygen2/version: 8.0.0
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## SummaryTables 1.3.0

* Added Standardized Coefficients for Linear Regression analyses (both Univariable and Multivariable).
* Added a rounding option for 16 decimal places across all analyses.
* Enhanced UI labels.
* General bug-fixes and improvements.

## SummaryTables 1.2.1

* Fixed an issue that caused an error when customizing the number of decimal places in the Continuous Table.
Expand Down
50 changes: 49 additions & 1 deletion R/regression.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ validateFactorPolynomials <- function(data, terms) {
#' @param terms modelTerms list from self$options$modelTerms
#' @return A formula object
buildFormula <- function(y, terms) {
as.formula(
stats::as.formula(
paste(
y,
"~",
Expand Down Expand Up @@ -128,6 +128,54 @@ buildMultiRegTable <- function(model, options, b64Map) {
}


# lmStd ---------------------------------------------------------------------

#' Fit standard linear regression model on standardized variables
#'
#' @param formula Model formula
#' @param data Data frame
#' @param ... Extra arguments passed to lm
#' @return An lm model object fitted on standardized complete cases
lmStd <- function(formula, data, ...) {
# Goal: produce the same standardized coefficients (betas) as
# parameters::standardize_parameters(method = "refit").
#
# How standardize_parameters(method = "refit") works internally:
# 1. Extracts the model frame via insight::get_data(model, source = "mf"),
# which is the data AFTER listwise deletion — rows with NA in ANY
# variable used by the model (numeric OR factor) are already gone.

# 2. Standardizes that complete-case data with datawizard::standardize()
# (factors are left untouched by default since force = FALSE).
# 3. Refits the model on the standardized complete-case data.
#
# Previously we used:
# datawizard::standardize(data, select = select_vars, remove_na = "selected")
# This had a bug: with force = FALSE (default), datawizard internally
# excludes factor columns from the "selected" set, so remove_na = "selected"
# only checked numeric columns for NAs. Rows with NA in a factor (but not
# in any numeric column) were KEPT, meaning mean/SD was computed from MORE
# rows than lm() actually uses (lm() does its own listwise deletion).
# This produced different standardized coefficients than
# parameters::standardize_parameters(method = "refit").
#
# We also cannot use remove_na = "all" on the full data frame, because
# "all" checks EVERY column — including ones not in the formula. NAs in
# unrelated columns would incorrectly drop rows.
#
# Fix: subset to formula columns first (data[select_vars]), then use
# remove_na = "all". This performs listwise deletion on exactly the
# variables the model uses, matching what lm() and
# parameters::standardize_parameters(method = "refit") do.
select_vars <- all.vars(formula)
data <- datawizard::standardize(
data[select_vars],
remove_na = "all"
)
stats::lm(formula, data = data, ...)
}


# buildUniRegTable ----------------------------------------------------------

#' Build a univariable tbl_uvregression table
Expand Down
4 changes: 2 additions & 2 deletions R/survival.R
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ buildSurvfitList <- function(data, elapsedB64, eventB64, strataB64, confInt) {
survLHS <- sprintf("survival::Surv(%s, %s)", elapsedB64, eventB64)

# Overall
overallF <- reformulate("1", response = survLHS)
overallF <- stats::reformulate("1", response = survLHS)
fits <- list(
rlang::inject(survival::survfit(
!!overallF,
Expand All @@ -89,7 +89,7 @@ buildSurvfitList <- function(data, elapsedB64, eventB64, strataB64, confInt) {

# One fit per stratifying variable (each analyzed independently)
for (s in strataB64) {
stratumF <- reformulate(s, response = survLHS)
stratumF <- stats::reformulate(s, response = survLHS)
fits <- c(
fits,
list(
Expand Down
3 changes: 2 additions & 1 deletion R/tblcontinuous.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ tblContinuousOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Cla
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..addPvalue <- jmvcore::OptionBool$new(
"addPvalue",
Expand Down
3 changes: 2 additions & 1 deletion R/tblcross.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ tblCrossOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..margin <- jmvcore::OptionList$new(
"margin",
Expand Down
3 changes: 2 additions & 1 deletion R/tbllikert.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ tblLikertOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..levelOrder <- jmvcore::OptionList$new(
"levelOrder",
Expand Down
3 changes: 2 additions & 1 deletion R/tblregcox.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ tblRegCoxOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..confInt <- jmvcore::OptionBool$new(
"confInt",
Expand Down
46 changes: 45 additions & 1 deletion R/tblreglinear.b.R
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,58 @@ tblRegLinearClass <- R6::R6Class(
# Formula and model ---------------------------------------------------
termsB64 <- lapply(terms, jmvcore::toB64)
formula <- buildFormula(depB64, termsB64)
model <- runSafe(lm(formula, data = data), collector)

if (self$options$standardize) {
# Goal: produce the same standardized coefficients (betas) as
# parameters::standardize_parameters(method = "refit").
#
# How standardize_parameters(method = "refit") works internally:
# 1. Extracts the model frame (data AFTER listwise deletion —
# rows with NA in ANY variable, numeric OR factor, are gone).
# 2. Standardizes that complete-case data with
# datawizard::standardize() (factors untouched, force = FALSE).
# 3. Refits the model on the standardized complete-case data.
#
# Previously we used:
# standardize(data, select = ..., remove_na = "selected")
# Bug: with force = FALSE (default), datawizard excludes factors
# from the internal "selected" set, so remove_na = "selected" only
# checked numeric columns for NAs. Rows with NA in a factor (but
# not in any numeric) were KEPT, meaning mean/SD was computed from
# MORE rows than lm() actually uses — producing wrong betas.
#
# We also cannot use remove_na = "all" on the full data frame,
# because "all" checks EVERY column — including ones not in the
# formula. NAs in unrelated columns would incorrectly drop rows.
#
# Fix: subset to formula columns first (data[select_vars]), then
# use remove_na = "all". This performs listwise deletion on exactly
# the variables the model uses, matching what lm() and
# parameters::standardize_parameters(method = "refit") do.
select_vars <- all.vars(formula)
data <- datawizard::standardize(
data[select_vars],
remove_na = "all"
)
}

model <- runSafe(stats::lm(formula, data = data), collector)

# Regression table ----------------------------------------------------
table <- runSafe(
buildMultiRegTable(model, self$options, b64Map),
collector
)

# Change header -------------------------------------------------------
coefHeader <- if (self$options$standardize) {
"**Standardized Coefficient**"
} else {
"**Coefficient**"
}
table <- table |>
gtsummary::modify_header(estimate = coefHeader)

# Pipeline ------------------------------------------------------------
table <- pipeAddGlobalP(
table,
Expand Down
14 changes: 13 additions & 1 deletion R/tblreglinear.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
manualRun = FALSE,
run = FALSE,
modelTerms = NULL,
standardize = FALSE,
digitsCoef = "auto",
confInt = TRUE,
confLevel = 95,
Expand Down Expand Up @@ -83,6 +84,10 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
private$..modelTerms <- jmvcore::OptionTerms$new(
"modelTerms",
modelTerms)
private$..standardize <- jmvcore::OptionBool$new(
"standardize",
standardize,
default=FALSE)
private$..digitsCoef <- jmvcore::OptionList$new(
"digitsCoef",
digitsCoef,
Expand All @@ -93,7 +98,8 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..confInt <- jmvcore::OptionBool$new(
"confInt",
Expand Down Expand Up @@ -275,6 +281,7 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
self$.addOption(private$..manualRun)
self$.addOption(private$..run)
self$.addOption(private$..modelTerms)
self$.addOption(private$..standardize)
self$.addOption(private$..digitsCoef)
self$.addOption(private$..confInt)
self$.addOption(private$..confLevel)
Expand Down Expand Up @@ -315,6 +322,7 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
manualRun = function() private$..manualRun$value,
run = function() private$..run$value,
modelTerms = function() private$..modelTerms$value,
standardize = function() private$..standardize$value,
digitsCoef = function() private$..digitsCoef$value,
confInt = function() private$..confInt$value,
confLevel = function() private$..confLevel$value,
Expand Down Expand Up @@ -354,6 +362,7 @@ tblRegLinearOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
..manualRun = NA,
..run = NA,
..modelTerms = NA,
..standardize = NA,
..digitsCoef = NA,
..confInt = NA,
..confLevel = NA,
Expand Down Expand Up @@ -445,6 +454,7 @@ tblRegLinearBase <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
#' @param manualRun .
#' @param run .
#' @param modelTerms .
#' @param standardize .
#' @param digitsCoef .
#' @param confInt .
#' @param confLevel .
Expand Down Expand Up @@ -498,6 +508,7 @@ tblRegLinear <- function(
manualRun = FALSE,
run = FALSE,
modelTerms,
standardize = FALSE,
digitsCoef = "auto",
confInt = TRUE,
confLevel = 95,
Expand Down Expand Up @@ -554,6 +565,7 @@ tblRegLinear <- function(
manualRun = manualRun,
run = run,
modelTerms = modelTerms,
standardize = standardize,
digitsCoef = digitsCoef,
confInt = confInt,
confLevel = confLevel,
Expand Down
3 changes: 2 additions & 1 deletion R/tblreglogistic.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ tblRegLogisticOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Cl
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..confInt <- jmvcore::OptionBool$new(
"confInt",
Expand Down
21 changes: 14 additions & 7 deletions R/tblsummary.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..statCatDefault <- jmvcore::OptionList$new(
"statCatDefault",
Expand Down Expand Up @@ -317,7 +318,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..percent <- jmvcore::OptionList$new(
"percent",
Expand Down Expand Up @@ -407,7 +409,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..diffDichotDefault <- jmvcore::OptionList$new(
"diffDichotDefault",
Expand Down Expand Up @@ -444,7 +447,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..diffDigitsCat <- jmvcore::OptionList$new(
"diffDigitsCat",
Expand All @@ -456,7 +460,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..addPvalue <- jmvcore::OptionBool$new(
"addPvalue",
Expand Down Expand Up @@ -623,7 +628,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..ciCatDefault <- jmvcore::OptionList$new(
"ciCatDefault",
Expand Down Expand Up @@ -670,7 +676,8 @@ tblSummaryOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..path <- jmvcore::OptionString$new(
"path",
Expand Down
3 changes: 2 additions & 1 deletion R/tblsurvfit.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ tblSurvfitOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..confLevel <- jmvcore::OptionNumber$new(
"confLevel",
Expand Down
3 changes: 2 additions & 1 deletion R/tbluniregcox.h.R
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ tblUniRegCoxOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Clas
"2",
"3",
"4",
"5"),
"5",
"16"),
default="auto")
private$..confInt <- jmvcore::OptionBool$new(
"confInt",
Expand Down
Loading