From 71ce0d6a7210eac268567d9cdd507fb6e93bcccb Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Sun, 26 Jul 2026 16:40:47 -0400 Subject: [PATCH 1/8] Add function for chi square. --- R/data_chisq.R | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 R/data_chisq.R diff --git a/R/data_chisq.R b/R/data_chisq.R new file mode 100644 index 000000000..636f87bea --- /dev/null +++ b/R/data_chisq.R @@ -0,0 +1,15 @@ +#' Calculate chi square test for tabulate +#' +#' @param dwtable A dwtable object. +#' @param show_table Should the table be shown with the chi sqare +#' @param ... Other options +#' +#' @export +data_chisq <- function(dwtable, show_table = TRUE, ...) { + tablelist <- as.table(dwtable) + chisqlist <- lapply(tablelist, stats::chisq.test) + if (length(chisqlist) == 1) { + return(chisqlist[[1]]) + } + chisqlist +} From 434d2516f1e93a4b8119862f6f18bf0a6686cd0e Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Fri, 23 Oct 2026 04:39:07 -0400 Subject: [PATCH 2/8] Change approach to chisq --- R/data_chisq.R | 15 --------------- R/data_tabulate.R | 8 ++++++-- R/data_xtabulate.R | 21 ++++++++++++++++++++- man/data_tabulate.Rd | 3 +++ 4 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 R/data_chisq.R diff --git a/R/data_chisq.R b/R/data_chisq.R deleted file mode 100644 index 636f87bea..000000000 --- a/R/data_chisq.R +++ /dev/null @@ -1,15 +0,0 @@ -#' Calculate chi square test for tabulate -#' -#' @param dwtable A dwtable object. -#' @param show_table Should the table be shown with the chi sqare -#' @param ... Other options -#' -#' @export -data_chisq <- function(dwtable, show_table = TRUE, ...) { - tablelist <- as.table(dwtable) - chisqlist <- lapply(tablelist, stats::chisq.test) - if (length(chisqlist) == 1) { - return(chisqlist[[1]]) - } - chisqlist -} diff --git a/R/data_tabulate.R b/R/data_tabulate.R index 7245e7df1..06d487577 100644 --- a/R/data_tabulate.R +++ b/R/data_tabulate.R @@ -44,6 +44,7 @@ #' any combination of `N` (frequencies including `NA`), `"raw"` (percentage #' including `NA` values), `"valid"` (percentage excluding `NA` values) and #' `"cumulative"` (percentage excluding `NA` values). +#' @param chisq include chi square for two dimensional tables #' @param ... not used. #' @inheritParams extract_column_names #' @@ -163,6 +164,7 @@ data_tabulate.default <- function( name = NULL, verbose = TRUE, metrics = c("N", "raw", "valid", "cumulative"), + chisq = FALSE, ... ) { # save label attribute, before it gets lost... @@ -211,7 +213,8 @@ data_tabulate.default <- function( remove_na = remove_na, proportions = proportions, obj_name = obj_name, - group_variable = group_variable + group_variable = group_variable, + chisq = chisq )) } # frequency table @@ -318,7 +321,7 @@ data_tabulate.default <- function( if (!"N" %in% metrics) { out <- data_select(out, exclude = "N") } - + cs2 <<- chisq # save information attr(out, "type") <- .variable_type(x) attr(out, "varname") <- name @@ -334,6 +337,7 @@ data_tabulate.default <- function( attr(out, "by") <- NULL } else { attr(out, "by") <- by_name + attr(out, "chi_square") <- chisq } class(out) <- c("datawizard_table", "data.frame") diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index cf1a56cc1..f806889ba 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -7,8 +7,11 @@ remove_na = FALSE, proportions = NULL, obj_name = NULL, - group_variable = NULL + group_variable = NULL, + chisq = NULL ) { + chi_square <- chisq.test(x, by) + if (!is.null(proportions)) { proportions <- match.arg(proportions, c("row", "column", "full")) } @@ -97,6 +100,19 @@ if (!is.null(by_name)) { attr(out, "by") <- by_name } + attr(out, "chi_square") <- chi_square + if (chisq) { + attr(out, "chisq_caption") <- paste0( + chi_square$method, + "\n ", + round(chi_square$statistic, 3), + ", ", + "df = ", + chi_square[["parameter"]][["df"]], + ", p = ", + round(chi_square$p.value, 3) + ) + } attr(out, "grouped_df") <- !is.null(group_variable) attr(out, "prop_table") <- .prop_table(out) @@ -312,6 +328,9 @@ print_html.datawizard_crosstab <- function(x, big_mark = NULL, ...) { caption <- paste0("Grouped by ", x[["Group"]][1]) x$Group <- NULL } + if (!is.null(attr(x, "chisq_caption"))) { + caption <- paste0(caption, attr(x, "chisq_caption")) + } # this function is used by all four supported format, markdown, text, html # and tt (tinytable). For tt, we sometimes have format "html" and backend = "tt", diff --git a/man/data_tabulate.Rd b/man/data_tabulate.Rd index 93112add9..bd25d7325 100644 --- a/man/data_tabulate.Rd +++ b/man/data_tabulate.Rd @@ -20,6 +20,7 @@ data_tabulate(x, ...) name = NULL, verbose = TRUE, metrics = c("N", "raw", "valid", "cumulative"), + chisq = FALSE, ... ) @@ -81,6 +82,8 @@ any combination of \code{N} (frequencies including \code{NA}), \code{"raw"} (per including \code{NA} values), \code{"valid"} (percentage excluding \code{NA} values) and \code{"cumulative"} (percentage excluding \code{NA} values).} +\item{chisq}{include chi square for two dimensional tables} + \item{select}{Variables that will be included when performing the required tasks. Can be either \itemize{ From 90f56d271040ae15a285195d2f0904cb185411b3 Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Sat, 24 Oct 2026 11:15:07 -0400 Subject: [PATCH 3/8] Start work on tests, some still not working, --- R/data_tabulate.R | 4 +++- R/data_xtabulate.R | 19 ++++++++++++++++--- man/data_tabulate.Rd | 1 + tests/testthat/test-data_tabulate.R | 20 +++++++++++++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/R/data_tabulate.R b/R/data_tabulate.R index 06d487577..61e4a2dbc 100644 --- a/R/data_tabulate.R +++ b/R/data_tabulate.R @@ -321,7 +321,7 @@ data_tabulate.default <- function( if (!"N" %in% metrics) { out <- data_select(out, exclude = "N") } - cs2 <<- chisq + # save information attr(out, "type") <- .variable_type(x) attr(out, "varname") <- name @@ -361,6 +361,7 @@ data_tabulate.data.frame <- function( proportions = NULL, collapse = FALSE, verbose = TRUE, + chisq = FALSE, ... ) { if (!is.null(by)) { @@ -395,6 +396,7 @@ data_tabulate.data.frame <- function( remove_na = remove_na, name = i, verbose = verbose, + chisq = chisq, ... ) }) diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index f806889ba..2b1546b0c 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -10,7 +10,12 @@ group_variable = NULL, chisq = NULL ) { - chi_square <- chisq.test(x, by) + chi_square <- suppressWarnings(chisq.test(x, by)) + chi_square2 <- tryCatch( + chisq.test(x, by), + warning = function(w) chisqwarning <<- w + ) + chi_square_warning <- chisqwarning$message if (!is.null(proportions)) { proportions <- match.arg(proportions, c("row", "column", "full")) @@ -105,15 +110,16 @@ attr(out, "chisq_caption") <- paste0( chi_square$method, "\n ", - round(chi_square$statistic, 3), + "X-squared = ", + round(chi_square[["statistic"]], 3), ", ", "df = ", chi_square[["parameter"]][["df"]], ", p = ", round(chi_square$p.value, 3) ) + attr(out, "chi_square_warning") <- chi_square_warning } - attr(out, "grouped_df") <- !is.null(group_variable) attr(out, "prop_table") <- .prop_table(out) @@ -331,6 +337,13 @@ print_html.datawizard_crosstab <- function(x, big_mark = NULL, ...) { if (!is.null(attr(x, "chisq_caption"))) { caption <- paste0(caption, attr(x, "chisq_caption")) } + if (!is.null(attr(x, "chi_square_warning"))) { + paste0( + caption, + "\n", + insight::format_warning(attr(x, "chi_square_warning")) + ) + } # this function is used by all four supported format, markdown, text, html # and tt (tinytable). For tt, we sometimes have format "html" and backend = "tt", diff --git a/man/data_tabulate.Rd b/man/data_tabulate.Rd index bd25d7325..0d883a603 100644 --- a/man/data_tabulate.Rd +++ b/man/data_tabulate.Rd @@ -37,6 +37,7 @@ data_tabulate(x, ...) proportions = NULL, collapse = FALSE, verbose = TRUE, + chisq = FALSE, ... ) diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index c8b55e756..8818d43d7 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -318,7 +318,12 @@ test_that("data_tabulate data.frame with wrong value for 'metrics'", { test_that("data_tabulate data.frame by", { data(efc, package = "datawizard") - x <- data_tabulate(efc, "c172code", by = "e16sex") + # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) + by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) + x <- factor(efc$c172code) + # by <- factor(efc$e16sex) + chisq <- suppressWarnings(chisq.test(x, by)) + x <- data_tabulate(efc, "c172code", by = "e16sex", chisq = FALSE) expect_s3_class(x, c("datawizard_crosstab", "list")) expect_length(x, 1L) expect_identical( @@ -335,6 +340,7 @@ test_that("data_tabulate data.frame by", { total_n = 100L, varname = "c172code", by = "e16sex", + chi_square = chisq, grouped_df = FALSE ) ) @@ -342,6 +348,11 @@ test_that("data_tabulate data.frame by", { test_that("data_tabulate default by", { data(efc, package = "datawizard") + # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) + by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) + x <- factor(efc$c172code) + # by <- factor(efc$e16sex) + chisq <- suppressWarnings(chisq.test(x, by)) x <- data_tabulate(efc$c172code, by = efc$e16sex) expect_s3_class(x, c("datawizard_crosstab", "data.frame")) expect_length(x, 4L) @@ -359,6 +370,7 @@ test_that("data_tabulate default by", { total_n = 100L, varname = "efc$c172code", by = "efc$e16sex", + chi_square = chisq, grouped_df = FALSE ) ) @@ -367,6 +379,11 @@ test_that("data_tabulate default by", { test_that("data_tabulate grouped data.frame by", { skip_if_not_installed("poorman") data(efc, package = "datawizard") + # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) + x <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) + by <- factor(efc$c172code) + # by <- factor(efc$e16sex) + chisq <- suppressWarnings(chisq.test(x, by)) x <- data_tabulate(poorman::group_by(efc, e16sex), "c172code", by = "e42dep") expect_identical( attributes(x[[1]]), @@ -385,6 +402,7 @@ test_that("data_tabulate grouped data.frame by", { total_n = 46L, varname = "c172code", by = "e42dep", + chi_square = chisq, grouped_df = TRUE ) ) From f6f8266620f3825c92264fd2307cf6d6b1576b2c Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Sun, 25 Oct 2026 13:50:59 -0400 Subject: [PATCH 4/8] Update documentation and fix some issues in tests. Also only run chisq.test() when lengths of x and by are both greater than 1. --- R/data_tabulate.R | 4 ++- R/data_xtabulate.R | 13 ++++---- man/data_tabulate.Rd | 3 +- tests/testthat/test-data_tabulate.R | 47 ++++++++++++++++++++--------- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/R/data_tabulate.R b/R/data_tabulate.R index 61e4a2dbc..4f4e5e41d 100644 --- a/R/data_tabulate.R +++ b/R/data_tabulate.R @@ -44,7 +44,8 @@ #' any combination of `N` (frequencies including `NA`), `"raw"` (percentage #' including `NA` values), `"valid"` (percentage excluding `NA` values) and #' `"cumulative"` (percentage excluding `NA` values). -#' @param chisq include chi square for two dimensional tables +#' @param chisq include chi square for two dimensional tables. This is always +#' calculated with the `chisq.test()` `simulate.p.value = TRUE`. #' @param ... not used. #' @inheritParams extract_column_names #' @@ -428,6 +429,7 @@ data_tabulate.grouped_df <- function( remove_na = FALSE, collapse = FALSE, verbose = TRUE, + chisq = FALSE, ... ) { grps <- attr(x, "groups", exact = TRUE) diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index 2b1546b0c..bd9783c01 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -10,13 +10,12 @@ group_variable = NULL, chisq = NULL ) { - chi_square <- suppressWarnings(chisq.test(x, by)) - chi_square2 <- tryCatch( - chisq.test(x, by), - warning = function(w) chisqwarning <<- w - ) - chi_square_warning <- chisqwarning$message - + if (length(unique(x)) > 1 & length(unique(by)) > 1) { + chi_square <- chisq.test(x, by, simulate.p.value = TRUE) + } else { + chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + in order to calculate chi square." + } if (!is.null(proportions)) { proportions <- match.arg(proportions, c("row", "column", "full")) } diff --git a/man/data_tabulate.Rd b/man/data_tabulate.Rd index 0d883a603..7540ccb9b 100644 --- a/man/data_tabulate.Rd +++ b/man/data_tabulate.Rd @@ -83,7 +83,8 @@ any combination of \code{N} (frequencies including \code{NA}), \code{"raw"} (per including \code{NA} values), \code{"valid"} (percentage excluding \code{NA} values) and \code{"cumulative"} (percentage excluding \code{NA} values).} -\item{chisq}{include chi square for two dimensional tables} +\item{chisq}{include chi square for two dimensional tables. This is always +calculated with the \code{chisq.test()} \code{simulate.p.value = TRUE}.} \item{select}{Variables that will be included when performing the required tasks. Can be either diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index 8818d43d7..df914f072 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -318,11 +318,16 @@ test_that("data_tabulate data.frame with wrong value for 'metrics'", { test_that("data_tabulate data.frame by", { data(efc, package = "datawizard") - # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) x <- factor(efc$c172code) - # by <- factor(efc$e16sex) - chisq <- suppressWarnings(chisq.test(x, by)) + set.seed(456) + if (length(unique(x)) > 1 & length(unique(by)) > 1) { + chi_square <- chisq.test(x, by, simulate.p.value = TRUE) + } else { + chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + in order to calculate chi square." + } + set.seed(456) x <- data_tabulate(efc, "c172code", by = "e16sex", chisq = FALSE) expect_s3_class(x, c("datawizard_crosstab", "list")) expect_length(x, 1L) @@ -340,7 +345,7 @@ test_that("data_tabulate data.frame by", { total_n = 100L, varname = "c172code", by = "e16sex", - chi_square = chisq, + chi_square = chi_square, grouped_df = FALSE ) ) @@ -348,11 +353,16 @@ test_that("data_tabulate data.frame by", { test_that("data_tabulate default by", { data(efc, package = "datawizard") - # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) x <- factor(efc$c172code) - # by <- factor(efc$e16sex) - chisq <- suppressWarnings(chisq.test(x, by)) + set.seed(456) + if (length(unique(x)) > 1 & length(unique(by)) > 1) { + chi_square <- chisq.test(x, by, simulate.p.value = TRUE) + } else { + chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + in order to calculate chi square." + } + set.seed(456) x <- data_tabulate(efc$c172code, by = efc$e16sex) expect_s3_class(x, c("datawizard_crosstab", "data.frame")) expect_length(x, 4L) @@ -370,7 +380,7 @@ test_that("data_tabulate default by", { total_n = 100L, varname = "efc$c172code", by = "efc$e16sex", - chi_square = chisq, + chi_square = chi_square, grouped_df = FALSE ) ) @@ -379,11 +389,20 @@ test_that("data_tabulate default by", { test_that("data_tabulate grouped data.frame by", { skip_if_not_installed("poorman") data(efc, package = "datawizard") - # x <- factor(efc$c172code, labels = attr(efc$c172code, "labels") |> names()) - x <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) - by <- factor(efc$c172code) - # by <- factor(efc$e16sex) - chisq <- suppressWarnings(chisq.test(x, by)) + efc_group1 <- subset(efc, efc$e16sex == 1) + x <- factor( + efc_group1$c172code + ) + by <- factor(efc_group1$e42dep) + Group <- factor(efc_group1$e16sex) + set.seed(456) + if (length(unique(x)) > 1 & length(unique(by)) > 1) { + chi_square <- chisq.test(x, by, simulate.p.value = TRUE) + } else { + chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + in order to calculate chi square." + } + set.seed(456) x <- data_tabulate(poorman::group_by(efc, e16sex), "c172code", by = "e42dep") expect_identical( attributes(x[[1]]), @@ -402,7 +421,7 @@ test_that("data_tabulate grouped data.frame by", { total_n = 46L, varname = "c172code", by = "e42dep", - chi_square = chisq, + chi_square = chi_square, grouped_df = TRUE ) ) From 8cc9e27c54947e542e50830f21f1e1c764423a3a Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Sun, 25 Oct 2026 15:04:17 -0400 Subject: [PATCH 5/8] Fix test cruff --- R/data_xtabulate.R | 11 +++++++---- tests/testthat/test-data_tabulate.R | 19 ++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index bd9783c01..eeb8ca86f 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -8,14 +8,18 @@ proportions = NULL, obj_name = NULL, group_variable = NULL, - chisq = NULL + chisq = FALSE ) { - if (length(unique(x)) > 1 & length(unique(by)) > 1) { + if (is.null(group_variable) & is.null(attr(x, "groups"))) { + chi_square <- chisq.test(x, by, simulate.p.value = TRUE) + } else if (length(levels(x)) > 1 & length(levels(by)) > 1) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) } else { - chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + chi_square <- + "Both 'by' and 'x' must have at least 2 unique levels\n in order to calculate chi square." } + if (!is.null(proportions)) { proportions <- match.arg(proportions, c("row", "column", "full")) } @@ -117,7 +121,6 @@ ", p = ", round(chi_square$p.value, 3) ) - attr(out, "chi_square_warning") <- chi_square_warning } attr(out, "grouped_df") <- !is.null(group_variable) attr(out, "prop_table") <- .prop_table(out) diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index df914f072..270adc8de 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -321,11 +321,12 @@ test_that("data_tabulate data.frame by", { by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) x <- factor(efc$c172code) set.seed(456) - if (length(unique(x)) > 1 & length(unique(by)) > 1) { + if (length(levels(x)) > 1 & length(levels(by)) > 1) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) } else { - chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n - in order to calculate chi square." + chi_square <- + "Both 'by' and 'x' must have at least 2 unique values + in order to calculate chi square." } set.seed(456) x <- data_tabulate(efc, "c172code", by = "e16sex", chisq = FALSE) @@ -359,8 +360,11 @@ test_that("data_tabulate default by", { if (length(unique(x)) > 1 & length(unique(by)) > 1) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) } else { - chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + chi_square <- list( + "Both 'by' and 'x' must have at least 2 unique values\n in order to calculate chi square." + ) + class(chi_square) <- "htest" } set.seed(456) x <- data_tabulate(efc$c172code, by = efc$e16sex) @@ -396,12 +400,9 @@ test_that("data_tabulate grouped data.frame by", { by <- factor(efc_group1$e42dep) Group <- factor(efc_group1$e16sex) set.seed(456) - if (length(unique(x)) > 1 & length(unique(by)) > 1) { - chi_square <- chisq.test(x, by, simulate.p.value = TRUE) - } else { - chi_square <- "Both 'by' and 'x' must have at least 2 unique values\n + chi_square <- + "Both 'by' and 'x' must have at least 2 unique levels\n in order to calculate chi square." - } set.seed(456) x <- data_tabulate(poorman::group_by(efc, e16sex), "c172code", by = "e42dep") expect_identical( From 262e33a6912b69f783894869d47b004bbdd43a3e Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Sun, 25 Oct 2026 16:29:25 -0400 Subject: [PATCH 6/8] Run linter. --- R/data_xtabulate.R | 4 ++-- tests/testthat/test-data_tabulate.R | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index eeb8ca86f..16150d869 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -10,9 +10,9 @@ group_variable = NULL, chisq = FALSE ) { - if (is.null(group_variable) & is.null(attr(x, "groups"))) { + if (is.null(group_variable) && is.null(attr(x, "groups"))) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) - } else if (length(levels(x)) > 1 & length(levels(by)) > 1) { + } else if (nlevels(x) > 1 && nlevels(x) > 1) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) } else { chi_square <- diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index 270adc8de..73895e620 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -321,7 +321,7 @@ test_that("data_tabulate data.frame by", { by <- factor(efc$e16sex, labels = attr(efc$e16sex, "labels") |> names()) x <- factor(efc$c172code) set.seed(456) - if (length(levels(x)) > 1 & length(levels(by)) > 1) { + if (nlevels(x) > 1 && nlevels(x) > 1) { chi_square <- chisq.test(x, by, simulate.p.value = TRUE) } else { chi_square <- @@ -1121,7 +1121,7 @@ test_that("data_tabulate, as.data.frame, cross tables", { ) expect_length(out$table, 1L) expect_named(out$table[[1]], c("cyl", "0", "1", "NA")) - expect_identical(nrow(out$table[[1]]), 4L) + expect_shape(out$table[[1]], nrow = 4L) # cross tables x <- data_tabulate(mtcars, c("cyl", "vs"), by = "am") out <- as.data.frame(x) @@ -1133,7 +1133,7 @@ test_that("data_tabulate, as.data.frame, cross tables", { ) expect_length(out$table, 2L) expect_named(out$table[[1]], c("cyl", "0", "1", "NA")) - expect_identical(nrow(out$table[[1]]), 4L) + expect_shape(out$table[[1]], nrow = 4L) }) @@ -1149,7 +1149,7 @@ test_that("data_tabulate, as.data.frame, cross tables with total N", { ) expect_length(out$table, 1L) expect_named(out$table[[1]], c("cyl", "0", "1", "", "Total")) - expect_identical(nrow(out$table[[1]]), 5L) + expect_shape(out$table[[1]], nrow = 5L) expect_identical(out$table[[1]]$cyl, c("4", "6", "8", NA, "Total")) # cross tables, with total x <- data_tabulate(mtcars, c("cyl", "vs"), by = "am") @@ -1162,7 +1162,7 @@ test_that("data_tabulate, as.data.frame, cross tables with total N", { ) expect_length(out$table, 2L) expect_named(out$table[[1]], c("cyl", "0", "1", "", "Total")) - expect_identical(nrow(out$table[[1]]), 5L) + expect_shape(out$table[[1]], nrow = 5L) expect_identical(out$table[[1]]$cyl, c("4", "6", "8", NA, "Total")) }) From 216ab77fd96cefe65ec39a6d233b0899228392b2 Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Mon, 26 Oct 2026 10:38:12 -0400 Subject: [PATCH 7/8] Add some tests --- DESCRIPTION | 2 +- R/data_xtabulate.R | 28 ++++++++------ tests/testthat/_snaps/data_tabulate.md | 20 ++++++++++ tests/testthat/test-data_tabulate.R | 52 ++++++++++++++++++++------ 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 03da8ef69..28b992f95 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -85,4 +85,4 @@ Roxygen: list(markdown = TRUE) Config/testthat/edition: 3 Config/testthat/parallel: true Config/Needs/website: easystats/easystatstemplate -Config/roxygen2/version: 8.1.0 +Config/roxygen2/version: 8.1.1 diff --git a/R/data_xtabulate.R b/R/data_xtabulate.R index 16150d869..93fc4d1d7 100644 --- a/R/data_xtabulate.R +++ b/R/data_xtabulate.R @@ -110,17 +110,23 @@ } attr(out, "chi_square") <- chi_square if (chisq) { - attr(out, "chisq_caption") <- paste0( - chi_square$method, - "\n ", - "X-squared = ", - round(chi_square[["statistic"]], 3), - ", ", - "df = ", - chi_square[["parameter"]][["df"]], - ", p = ", - round(chi_square$p.value, 3) - ) + if (is.list(chi_square)) { + attr(out, "chisq_caption") <- paste0( + chi_square$method, + "\n ", + "X-squared = ", + round(chi_square[["statistic"]], 3), + ", ", + "df = ", + chi_square[["parameter"]][["df"]], + ", p = ", + round(chi_square$p.value, 3) + ) + } else { + if (is.character(chi_square)) { + attr(out, "chisq_caption") <- chi_square + } + } } attr(out, "grouped_df") <- !is.null(group_variable) attr(out, "prop_table") <- .prop_table(out) diff --git a/tests/testthat/_snaps/data_tabulate.md b/tests/testthat/_snaps/data_tabulate.md index 153420ab5..4b1428baa 100644 --- a/tests/testthat/_snaps/data_tabulate.md +++ b/tests/testthat/_snaps/data_tabulate.md @@ -861,6 +861,26 @@ |e42dep | 4| 32 (50.8%)| 28 (44.4%)| 3 (4.8%) | 63| |e42dep | (NA)| 1 (33.3%)| 2 (66.7%)| 0 (0.0%) | 3| +--- + + Code + display(data_tabulate(efc, "c172code", by = "e16sex", proportions = "column", + remove_na = TRUE, weights = "weights", chisq = TRUE)) + Output + + + Table: Pearson's Chi-squared test with simulated p-value + (based on 2000 replicates) + X-squared = 4.217, df = NA, p = 0.117 + + |c172code | male| female| Total| + |:--------|----------:|----------:|-----:| + |1 | 5 (12.5%)| 3 (6.5%)| 8| + |2 | 32 (80.0%)| 32 (69.6%)| 64| + |3 | 3 (7.5%)| 11 (23.9%)| 14| + | | | | | + |Total | 40| 46| 86| + # data_tabulate, correct 0% for proportions Code diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index 73895e620..401c15aff 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -364,7 +364,6 @@ test_that("data_tabulate default by", { "Both 'by' and 'x' must have at least 2 unique values\n in order to calculate chi square." ) - class(chi_square) <- "htest" } set.seed(456) x <- data_tabulate(efc$c172code, by = efc$e16sex) @@ -390,6 +389,14 @@ test_that("data_tabulate default by", { ) }) +test_that("data_tabulate default by with chisq", { + expect_no_error(data_tabulate( + x = efc$e16sex, + by = efc$c172code, + chisq = TRUE + )) +}) + test_that("data_tabulate grouped data.frame by", { skip_if_not_installed("poorman") data(efc, package = "datawizard") @@ -427,6 +434,19 @@ test_that("data_tabulate grouped data.frame by", { ) ) }) + + +test_that("data_tabulate grouped data.frame by with chi square", { + skip_if_not_installed("poorman") + data(efc, package = "datawizard") + expect_no_warning(data_tabulate( + poorman::group_by(efc, e16sex), + "c172code", + by = "e42dep", + chisq = TRUE + )) +}) + test_that("data_tabulate unsupported class", { data(mtcars) expect_warning( @@ -435,7 +455,6 @@ test_that("data_tabulate unsupported class", { ) }) - test_that("data_tabulate print", { set.seed(123) x <- sample.int(3, 1e6, TRUE) @@ -995,14 +1014,16 @@ test_that("data_tabulate, cross tables, markdown", { remove_na = TRUE, weights = efc$weights ))) # nolint - expect_snapshot(print_md(data_tabulate( - efc, - "c172code", - by = "e16sex", - proportions = "column", - remove_na = TRUE, - weights = "weights" - ))) # nolint + expect_snapshot( + print_md(data_tabulate( + efc, + "c172code", + by = "e16sex", + proportions = "column", + remove_na = TRUE, + weights = "weights" + )) + ) # nolint expect_snapshot(print_md(data_tabulate( efc, c("c172code", "e42dep"), @@ -1023,9 +1044,18 @@ test_that("data_tabulate, cross tables, markdown", { by = "e16sex", proportions = "row" ))) # nolint + set.seed(123) + expect_snapshot(display(data_tabulate( + efc, + "c172code", + by = "e16sex", + proportions = "column", + remove_na = TRUE, + weights = "weights", + chisq = TRUE + ))) # nolint }) - # validate against table ------------------------- test_that("data_tabulate, validate against table", { From 05b6031091b9a7de72e5723cb89e4351813b94d7 Mon Sep 17 00:00:00 2001 From: Elin Waring Date: Mon, 26 Oct 2026 14:52:49 -0400 Subject: [PATCH 8/8] Add another snapshot test (default) --- tests/testthat/_snaps/data_tabulate.md | 25 +++++++++++++++++++++++++ tests/testthat/test-data_tabulate.R | 9 +++++++++ 2 files changed, 34 insertions(+) diff --git a/tests/testthat/_snaps/data_tabulate.md b/tests/testthat/_snaps/data_tabulate.md index 4b1428baa..1f223fb2d 100644 --- a/tests/testthat/_snaps/data_tabulate.md +++ b/tests/testthat/_snaps/data_tabulate.md @@ -270,6 +270,31 @@ 5 | 2002107 | 20.02 | 20.02 | 100.00 | 0 | 0.00 | | +# data_tabulate default by with chisq + + Code + data_tabulate(x = efc$e16sex, by = efc$c172code, chisq = TRUE) + Output + Pearson's Chi-squared test with simulated p-value + (based on 2000 replicates) + X-squared = 3.88, df = NA, p = 0.163 + + efc$e16sex | low level of education | intermediate level of education + -----------+------------------------+-------------------------------- + 1 | 5 | 32 + 2 | 3 | 34 + | 0 | 0 + -----------+------------------------+-------------------------------- + Total | 8 | 66 + + efc$e16sex | high level of education | | Total + -----------+-------------------------+------+------ + 1 | 4 | 5 | 46 + 2 | 12 | 5 | 54 + | 0 | 0 | 0 + -----------+-------------------------+------+------ + Total | 16 | 10 | 100 + # data_tabulate print multiple, collapse Code diff --git a/tests/testthat/test-data_tabulate.R b/tests/testthat/test-data_tabulate.R index 401c15aff..422678736 100644 --- a/tests/testthat/test-data_tabulate.R +++ b/tests/testthat/test-data_tabulate.R @@ -496,6 +496,15 @@ test_that("data_tabulate big numbers", { expect_snapshot(print(data_tabulate(x), big_mark = "")) }) +test_that("data_tabulate default by with chisq", { + data(efc, package = "datawizard") + set.seed(123) + expect_snapshot(data_tabulate( + x = efc$e16sex, + by = efc$c172code, + chisq = TRUE + )) +}) test_that("data_tabulate print multiple, collapse", { data(efc, package = "datawizard")