From 6bd491d4ce77d55931a9a31efa8478238f68d9bd Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Mon, 3 Feb 2025 13:43:02 -0800 Subject: [PATCH 1/6] hook up round_type support --- R/format_rcell.R | 4 +- R/tt_toString.R | 38 ++++++++------- inst/WORDLIST | 70 +++++++++++++++------------- man/format_rcell.Rd | 1 + man/gfc.Rd | 10 ++-- man/matrix_form-VTableTree-method.Rd | 7 ++- man/tostring.Rd | 7 ++- tests/testthat/test-exporters.R | 33 +++++++++++++ tests/testthat/test-formatting.R | 13 ++++++ 9 files changed, 126 insertions(+), 57 deletions(-) diff --git a/R/format_rcell.R b/R/format_rcell.R index 46eb8df9a..6531eae43 100644 --- a/R/format_rcell.R +++ b/R/format_rcell.R @@ -32,6 +32,7 @@ format_rcell <- function(x, format, na_str = obj_na_str(x) %||% "NA", pr_row_format = NULL, pr_row_na_str = NULL, + round_type = c("iec", "sas"), shell = FALSE) { # Check for format and parent row format format <- if (missing(format)) obj_format(x) else format @@ -50,6 +51,7 @@ format_rcell <- function(x, format, format_value(rawvalues(x), format = format, output = output, - na_str = na_str + na_str = na_str, + round_type = round_type ) } diff --git a/R/tt_toString.R b/R/tt_toString.R index dbca92e7e..0d34fce48 100644 --- a/R/tt_toString.R +++ b/R/tt_toString.R @@ -49,20 +49,23 @@ setMethod("toString", "VTableTree", function(x, tf_wrap = FALSE, max_width = NULL, fontspec = font_spec(), - ttype_ok = FALSE) { + ttype_ok = FALSE, + round_type = c("iec", "sas")) { toString( matrix_form(x, indent_rownames = TRUE, indent_size = indent_size, fontspec = fontspec, - col_gap = col_gap + col_gap = col_gap, + round_type = round_type ), widths = widths, col_gap = col_gap, hsep = hsep, tf_wrap = tf_wrap, max_width = max_width, fontspec = fontspec, - ttype_ok = ttype_ok + ttype_ok = ttype_ok, + round_type = round_type ) }) @@ -146,6 +149,7 @@ table_shell_str <- function(tt, widths = NULL, col_gap = 3, hsep = default_hsep( #' it is useful to map the `rtable` to an in-between state with the formatted cells in a matrix form. #' #' @inheritParams gen_args +#' @inheritParams formatters::format_value #' @param indent_rownames (`flag`)\cr if `TRUE`, the column with the row names in the `strings` matrix of the output #' has indented row names (strings pre-fixed). #' @param expand_newlines (`flag`)\cr whether the matrix form generated should expand rows whose values contain @@ -203,7 +207,8 @@ setMethod( expand_newlines = TRUE, indent_size = 2, fontspec = NULL, - col_gap = 3L) { + col_gap = 3L, + round_type = c("iec", "sas")) { stopifnot(is(obj, "VTableTree")) check_ccount_vis_ok(obj) header_content <- .tbl_header_mat(obj) # first col are for row.names @@ -213,7 +218,7 @@ setMethod( body_content_strings <- if (NROW(sr) == 0) { character() } else { - cbind(as.character(sr$label), get_formatted_cells(obj)) + cbind(as.character(sr$label), get_formatted_cells(obj, round_type = round_type)) } formats_strings <- if (NROW(sr) == 0) { @@ -664,17 +669,17 @@ get_formatted_fnotes <- function(tt) { #' #' @export #' @rdname gfc -setGeneric("get_formatted_cells", function(obj, shell = FALSE) standardGeneric("get_formatted_cells")) +setGeneric("get_formatted_cells", function(obj, shell = FALSE, round_type = c("iec", "sas")) standardGeneric("get_formatted_cells")) #' @rdname gfc setMethod( "get_formatted_cells", "TableTree", - function(obj, shell = FALSE) { - lr <- get_formatted_cells(tt_labelrow(obj), shell = shell) + function(obj, shell = FALSE, round_type = c("iec", "sas")) { + lr <- get_formatted_cells(tt_labelrow(obj), shell = shell, round_type = round_type) - ct <- get_formatted_cells(content_table(obj), shell = shell) + ct <- get_formatted_cells(content_table(obj), shell = shell, round_type = round_type) - els <- lapply(tree_children(obj), get_formatted_cells, shell = shell) + els <- lapply(tree_children(obj), get_formatted_cells, shell = shell, round_type = round_type) ## TODO fix ncol problem for rrow() if (ncol(ct) == 0 && ncol(lr) != ncol(ct)) { @@ -688,9 +693,9 @@ setMethod( #' @rdname gfc setMethod( "get_formatted_cells", "ElementaryTable", - function(obj, shell = FALSE) { - lr <- get_formatted_cells(tt_labelrow(obj), shell = shell) - els <- lapply(tree_children(obj), get_formatted_cells, shell = shell) + function(obj, shell = FALSE, round_type = c("iec", "sas")) { + lr <- get_formatted_cells(tt_labelrow(obj), shell = shell, round_type = round_type) + els <- lapply(tree_children(obj), get_formatted_cells, shell = shell, round_type = round_type) do.call(rbind, c(list(lr), els)) } ) @@ -698,7 +703,7 @@ setMethod( #' @rdname gfc setMethod( "get_formatted_cells", "TableRow", - function(obj, shell = FALSE) { + function(obj, shell = FALSE, round_type = c("iec", "sas")) { # Parent row format and na_str pr_row_format <- if (is.null(obj_format(obj))) "xx" else obj_format(obj) pr_row_na_str <- obj_na_str(obj) %||% "NA" @@ -710,7 +715,8 @@ setMethod( out <- format_rcell(val, pr_row_format = pr_row_format, pr_row_na_str = pr_row_na_str, - shell = shelli + shell = shelli, + round_type = round_type ) if (!is.function(out) && is.character(out)) { out <- paste(out, collapse = ", ") @@ -726,7 +732,7 @@ setMethod( #' @rdname gfc setMethod( "get_formatted_cells", "LabelRow", - function(obj, shell = FALSE) { + function(obj, shell = FALSE, round_type = c("iec", "sas")) { nc <- ncol(obj) # TODO note rrow() or rrow("label") has the wrong ncol vstr <- if (shell) "-" else "" if (labelrow_visible(obj)) { diff --git a/inst/WORDLIST b/inst/WORDLIST index b327acbd8..c09bdb6b1 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,42 +1,13 @@ +amongst ARD ARDs -Bové -CRAN's +Bov Carreras +charset Cheatsheet Chohan -FFFL -Godwin -Heng -Hoffmann -Kelkhoff -Layouting -Lewandowski -Maximo -Modelling -NSE -ORCID -Paszty -Pharma -Phuse -Pre -Qi -RStudio -Resync -Rua -STUDYID -Sabanés -Saibah -Stoilova -Subtable -Subtables -Tadeusz -Unstratified -ValueWrapper -Yung -amongst -charset combinatorial +CRAN's customizations de decrementing @@ -45,40 +16,70 @@ dplyr emph facetted facetting +FFFL formatter forseeable funder getter getters +Godwin +Heng +Hoffmann +IEC +iec ing initializer iteratively +Kelkhoff labelled +Layouting layouting +Lewandowski mandatorily +Maximo +Modelling monospace multivariable +NSE +ORCID orderable +Paszty pathing +peforms +Pharma +Phuse postfix postprocessing +Pre pre priori programmatically +Qi reindexed repo repped responder +Resync reusability roadmap +RStudio +Rua +Sabans +Saibah +sas sortable spl +Stoilova +STUDYID subsplits +Subtable subtable subtable's +Subtables subtables summarization tableone +Tadeusz todo traversable truetype @@ -86,8 +87,11 @@ unaggregated unicode univariable unpruned +Unstratified unstratified useR +ValueWrapper visibilty visiblities xtable +Yung diff --git a/man/format_rcell.Rd b/man/format_rcell.Rd index fa2fb10fe..cb330197e 100644 --- a/man/format_rcell.Rd +++ b/man/format_rcell.Rd @@ -11,6 +11,7 @@ format_rcell( na_str = obj_na_str(x) \%||\% "NA", pr_row_format = NULL, pr_row_na_str = NULL, + round_type = c("iec", "sas"), shell = FALSE ) } diff --git a/man/gfc.Rd b/man/gfc.Rd index f5e2d33da..1cb426a03 100644 --- a/man/gfc.Rd +++ b/man/gfc.Rd @@ -13,15 +13,15 @@ \alias{get_cell_aligns,LabelRow-method} \title{Get formatted cells} \usage{ -get_formatted_cells(obj, shell = FALSE) +get_formatted_cells(obj, shell = FALSE, round_type = c("iec", "sas")) -\S4method{get_formatted_cells}{TableTree}(obj, shell = FALSE) +\S4method{get_formatted_cells}{TableTree}(obj, shell = FALSE, round_type = c("iec", "sas")) -\S4method{get_formatted_cells}{ElementaryTable}(obj, shell = FALSE) +\S4method{get_formatted_cells}{ElementaryTable}(obj, shell = FALSE, round_type = c("iec", "sas")) -\S4method{get_formatted_cells}{TableRow}(obj, shell = FALSE) +\S4method{get_formatted_cells}{TableRow}(obj, shell = FALSE, round_type = c("iec", "sas")) -\S4method{get_formatted_cells}{LabelRow}(obj, shell = FALSE) +\S4method{get_formatted_cells}{LabelRow}(obj, shell = FALSE, round_type = c("iec", "sas")) get_cell_aligns(obj) diff --git a/man/matrix_form-VTableTree-method.Rd b/man/matrix_form-VTableTree-method.Rd index 9e3776a39..27a488bb8 100644 --- a/man/matrix_form-VTableTree-method.Rd +++ b/man/matrix_form-VTableTree-method.Rd @@ -10,7 +10,8 @@ expand_newlines = TRUE, indent_size = 2, fontspec = NULL, - col_gap = 3L + col_gap = 3L, + round_type = c("iec", "sas") ) } \arguments{ @@ -31,6 +32,10 @@ rendering this \code{MatrixPrintForm} object, or NULL (the default).} by \code{fontspec}) that should be placed between columns when the table is rendered directly to text (e.g., by \code{toString} or \code{export_as_txt}). Defaults to \code{3}.} + +\item{round_type}{(\code{"iec"} or \code{"sas"})\cr the type of rounding to perform. iec, +the default, peforms rounding compliant with IEC 60559 (see details), while +sas performs nearest-value rounding consistent with rounding within SAS.} } \value{ A list with the following elements: diff --git a/man/tostring.Rd b/man/tostring.Rd index 0906e9882..9d9e517f4 100644 --- a/man/tostring.Rd +++ b/man/tostring.Rd @@ -14,7 +14,8 @@ tf_wrap = FALSE, max_width = NULL, fontspec = font_spec(), - ttype_ok = FALSE + ttype_ok = FALSE, + round_type = c("iec", "sas") ) } \arguments{ @@ -45,6 +46,10 @@ calculating string widths and heights, as returned by \code{\link[formatters:fon \item{ttype_ok}{(\code{logical(1)})\cr should truetype (non-monospace) fonts be allowed via \code{fontspec}. Defaults to \code{FALSE}. This parameter is primarily for internal testing and generally should not be set by end users.} + +\item{round_type}{(\code{"iec"} or \code{"sas"})\cr the type of rounding to perform. iec, +the default, peforms rounding compliant with IEC 60559 (see details), while +sas performs nearest-value rounding consistent with rounding within SAS.} } \value{ A string representation of \code{x} as it appears when printed. diff --git a/tests/testthat/test-exporters.R b/tests/testthat/test-exporters.R index 4e33d6b51..c61186952 100644 --- a/tests/testthat/test-exporters.R +++ b/tests/testthat/test-exporters.R @@ -120,6 +120,39 @@ test_that("export_as_txt works with wrapping", { expect_identical(pagepos3[1], pagepos2b[1]) }) + +test_that("export_as_txt works with sas rounding", { + ## this also tests pagination and all supported formats with 2 decimals of precision + vals <- list( + 0.845, + c(1.845, 0.845), + c(10.845, 8.845, 12.845) + ) + forms <- lapply(list_valid_format_labels(), + function(x) grep("xx[.]xx([^x%]|$)", x, value = TRUE)) + vals <- rep(vals, times = lengths(forms)) + names(vals) <- paste0("row", seq_along(vals)) + forms <- setNames(unlist(forms), nm = names(vals)) + superdumbafun <- function(x) { + in_rows(.list = vals, .formats = forms) + } + superdumbfun2 <- function(x) { + txtvals <- mapply(format_value, x = vals, format = forms, round_type = "sas") + in_rows(.list = txtvals) + } + lyt <- basic_table() |> + analyze("AGE", afun = superdumbafun) + tbl <- build_table(lyt, DM) + txt <- export_as_txt(tbl, round_type = "sas") + lyt2 <- basic_table() |> + analyze("AGE", afun = superdumbfun2) + tbl2 <- build_table(lyt2, DM) + expect_identical(export_as_txt(tbl, round_type = "sas"), + export_as_txt(tbl2)) + expect_identical(toString(tbl, round_type = "sas"), + export_as_txt(tbl, round_type = "sas")) +}) + test_that("tsv roundtripping for path_enriched_df", { tbl2 <- tt_to_export() diff --git a/tests/testthat/test-formatting.R b/tests/testthat/test-formatting.R index 01b8effc9..11d3edf72 100644 --- a/tests/testthat/test-formatting.R +++ b/tests/testthat/test-formatting.R @@ -198,3 +198,16 @@ test_that("format and na_str inheritance", { # Check if it preserves the shell format expect_identical(result, expected) }) + + +test_that("sas-style formatting works", { + dumbafun <- function(x) rcell(0.845, format = "xx.xx") + lyt <- basic_table() |> + analyze("AGE", dumbafun) + + tbl <- build_table(lyt, DM) + str1 <- toString(tbl) + str2 <- toString(tbl, round_type = "sas") + expect_true(grepl("0.84", str1, fixed = TRUE)) + expect_true(grepl("0.85", str2, fixed = TRUE)) +}) From e979ab0b07508f9285df688ae4d1ceff1181a7a1 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 21:49:59 +0000 Subject: [PATCH 2/6] [skip style] [skip vbump] Restyle files --- tests/testthat/test-exporters.R | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-exporters.R b/tests/testthat/test-exporters.R index c61186952..600e6e26f 100644 --- a/tests/testthat/test-exporters.R +++ b/tests/testthat/test-exporters.R @@ -128,8 +128,10 @@ test_that("export_as_txt works with sas rounding", { c(1.845, 0.845), c(10.845, 8.845, 12.845) ) - forms <- lapply(list_valid_format_labels(), - function(x) grep("xx[.]xx([^x%]|$)", x, value = TRUE)) + forms <- lapply( + list_valid_format_labels(), + function(x) grep("xx[.]xx([^x%]|$)", x, value = TRUE) + ) vals <- rep(vals, times = lengths(forms)) names(vals) <- paste0("row", seq_along(vals)) forms <- setNames(unlist(forms), nm = names(vals)) @@ -147,10 +149,14 @@ test_that("export_as_txt works with sas rounding", { lyt2 <- basic_table() |> analyze("AGE", afun = superdumbfun2) tbl2 <- build_table(lyt2, DM) - expect_identical(export_as_txt(tbl, round_type = "sas"), - export_as_txt(tbl2)) - expect_identical(toString(tbl, round_type = "sas"), - export_as_txt(tbl, round_type = "sas")) + expect_identical( + export_as_txt(tbl, round_type = "sas"), + export_as_txt(tbl2) + ) + expect_identical( + toString(tbl, round_type = "sas"), + export_as_txt(tbl, round_type = "sas") + ) }) test_that("tsv roundtripping for path_enriched_df", { From db7b2ebb7055ee934f054edc6030471a7b1372ad Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Mon, 3 Feb 2025 15:27:43 -0800 Subject: [PATCH 3/6] missing round_type param doc --- R/format_rcell.R | 1 + R/tt_toString.R | 1 + man/format_rcell.Rd | 4 ++++ man/gfc.Rd | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/R/format_rcell.R b/R/format_rcell.R index 6531eae43..28c257af3 100644 --- a/R/format_rcell.R +++ b/R/format_rcell.R @@ -3,6 +3,7 @@ #' This is a wrapper for [formatters::format_value()] for use with `CellValue` objects #' #' @inheritParams lyt_args +#' @inheritParams formatters::format_value #' @param x (`CellValue` or `ANY`)\cr an object of class `CellValue`, or a raw value. #' @param format (`string` or `function`)\cr the format label or formatter function to #' apply to `x`. diff --git a/R/tt_toString.R b/R/tt_toString.R index 0d34fce48..842b7ff2f 100644 --- a/R/tt_toString.R +++ b/R/tt_toString.R @@ -646,6 +646,7 @@ get_formatted_fnotes <- function(tt) { #' Get formatted cells #' #' @inheritParams gen_args +#' @inheritParams formatters::format_value #' @param shell (`flag`)\cr whether the formats themselves should be returned instead of the values with formats #' applied. Defaults to `FALSE`. #' diff --git a/man/format_rcell.Rd b/man/format_rcell.Rd index cb330197e..64fc6232c 100644 --- a/man/format_rcell.Rd +++ b/man/format_rcell.Rd @@ -29,6 +29,10 @@ apply to \code{x}.} \item{pr_row_na_str}{(\code{list})\cr list of default \code{"NA"} strings coming from the general row.} +\item{round_type}{(\code{"iec"} or \code{"sas"})\cr the type of rounding to perform. iec, +the default, peforms rounding compliant with IEC 60559 (see details), while +sas performs nearest-value rounding consistent with rounding within SAS.} + \item{shell}{(\code{flag})\cr whether the formats themselves should be returned instead of the values with formats applied. Defaults to \code{FALSE}.} } diff --git a/man/gfc.Rd b/man/gfc.Rd index 1cb426a03..19c01c115 100644 --- a/man/gfc.Rd +++ b/man/gfc.Rd @@ -38,6 +38,10 @@ get_cell_aligns(obj) \item{shell}{(\code{flag})\cr whether the formats themselves should be returned instead of the values with formats applied. Defaults to \code{FALSE}.} + +\item{round_type}{(\code{"iec"} or \code{"sas"})\cr the type of rounding to perform. iec, +the default, peforms rounding compliant with IEC 60559 (see details), while +sas performs nearest-value rounding consistent with rounding within SAS.} } \value{ The formatted print-strings for all (body) cells in \code{obj}. From 687a2da3998edc3a082ebd9694e8c9ddddc845ee Mon Sep 17 00:00:00 2001 From: Gabe Becker Date: Mon, 3 Feb 2025 16:00:12 -0800 Subject: [PATCH 4/6] fix silly lintr complaint --- R/tt_toString.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/tt_toString.R b/R/tt_toString.R index 842b7ff2f..7d8d4ce70 100644 --- a/R/tt_toString.R +++ b/R/tt_toString.R @@ -670,7 +670,8 @@ get_formatted_fnotes <- function(tt) { #' #' @export #' @rdname gfc -setGeneric("get_formatted_cells", function(obj, shell = FALSE, round_type = c("iec", "sas")) standardGeneric("get_formatted_cells")) +setGeneric("get_formatted_cells", + function(obj, shell = FALSE, round_type = c("iec", "sas")) standardGeneric("get_formatted_cells")) #' @rdname gfc setMethod( From 0af07f6272ac2aa23cfbcfaed76bd54f4722db10 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 00:02:21 +0000 Subject: [PATCH 5/6] [skip style] [skip vbump] Restyle files --- R/tt_toString.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/R/tt_toString.R b/R/tt_toString.R index 7d8d4ce70..2c434805d 100644 --- a/R/tt_toString.R +++ b/R/tt_toString.R @@ -670,8 +670,10 @@ get_formatted_fnotes <- function(tt) { #' #' @export #' @rdname gfc -setGeneric("get_formatted_cells", - function(obj, shell = FALSE, round_type = c("iec", "sas")) standardGeneric("get_formatted_cells")) +setGeneric( + "get_formatted_cells", + function(obj, shell = FALSE, round_type = c("iec", "sas")) standardGeneric("get_formatted_cells") +) #' @rdname gfc setMethod( From 591d05805db5570e7a32dd2cd2cd41612bd9eda8 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 00:05:45 +0000 Subject: [PATCH 6/6] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/formatters_methods.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/formatters_methods.Rd b/man/formatters_methods.Rd index 6a7767a00..fb7b6f7c2 100644 --- a/man/formatters_methods.Rd +++ b/man/formatters_methods.Rd @@ -163,7 +163,7 @@ sibpos = NA_integer_, nsibs = NA_integer_, max_width = NULL, - fontspec = font_spec(), + fontspec, col_gap = 3 ) @@ -180,7 +180,7 @@ sibpos = NA_integer_, nsibs = NA_integer_, max_width = NULL, - fontspec = font_spec(), + fontspec, col_gap = 3 ) }