From 90d17742b57b2db918c6b8c47b5fe98e3cd57296 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:48:42 -0500 Subject: [PATCH 01/10] Define the delimiter width --- R/tab_create_modify.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index 83601a2bc6..09dfca1007 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -1323,6 +1323,8 @@ str_split_across <- function( reverse = FALSE ) { + delim_width <- nchar(delim) + if (is.null(n)) { x_split <- unlist(strsplit(x, split = delim, fixed = TRUE)) From 6b736024967835b0eb55ebb816780e1ad999923c Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:49:18 -0500 Subject: [PATCH 02/10] Use delimiter width to better excise delim chars --- R/tab_create_modify.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index 09dfca1007..a1a4bd05e3 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -1355,7 +1355,6 @@ str_split_across <- function( x_split <- x for (i in seq_len(n)) { - if (split == "last") { x_split_i <- x_split[1] @@ -1372,7 +1371,7 @@ str_split_across <- function( x_split_n <- nchar(x_split_i) x_split_1 <- substr(x_split_i, start = 1, stop = split_delim - 1) - x_split_2 <- substr(x_split_i, start = split_delim + 1, x_split_n) + x_split_2 <- substr(x_split_i, start = split_delim + delim_width, x_split_n) x_split <- c(x_split_1, x_split_2, x_split) @@ -1392,7 +1391,7 @@ str_split_across <- function( x_split_n <- nchar(x_split_i) x_split_1 <- substr(x_split_i, start = 1, stop = split_delim - 1) - x_split_2 <- substr(x_split_i, start = split_delim + 1, x_split_n) + x_split_2 <- substr(x_split_i, start = split_delim + delim_width, x_split_n) x_split <- c(x_split, x_split_1, x_split_2) } From 8c58c362b1a7543483a327bfe717e47104e65ba6 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:49:46 -0500 Subject: [PATCH 03/10] Modify conditional stmt that checks char length of delim --- R/tab_create_modify.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index a1a4bd05e3..a5cf02d925 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -1118,8 +1118,8 @@ tab_spanner_delim <- function( cli::cli_abort("`delim` must be a single value.") } - if (nchar(delim) != 1) { - cli::cli_abort("The value supplied for `delim` must be a single character.") + if (nchar(delim) < 1) { + cli::cli_abort("The value supplied for `delim` must be at least a single character.") } # Get all of the columns in the dataset From 3f89105bfaed6aaa9e8140ab1dc580ebcdcc9514 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:49:53 -0500 Subject: [PATCH 04/10] Update tab_create_modify.R --- R/tab_create_modify.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index a5cf02d925..2a8a412ebe 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -800,8 +800,8 @@ resolve_spanned_column_names <- function( #' #' The `tab_spanner_delim()` function can take specially-crafted column names #' and generate one or more spanners (and revise column labels at the same -#' time). This is done by splitting the column name by a specified delimiter -#' (this is the `delim`) and placing the fragments from top to bottom (i.e., +#' time). This is done by splitting the column name by the specified delimiter +#' text (`delim`) and placing the fragments from top to bottom (i.e., #' higher-level spanners to the column labels) or vice versa. Furthermore, #' neighboring text fragments on different spanner levels that have the same #' text will be coalesced together. For instance, having the three side-by-side From 1a106490387792675f9b7d2dcce971a9b52a5769 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:49:57 -0500 Subject: [PATCH 05/10] Update tab_create_modify.R --- R/tab_create_modify.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index 2a8a412ebe..bae0743c91 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -811,16 +811,16 @@ resolve_spanned_column_names <- function( #' `cols_spanner_delim()` to slice and dice delimited column names in different #' ways: #' -#' - the delimiter: choose which delimiter to use for the fragmentation of +#' - delimiter text: choose the delimiter text to use for the fragmentation of #' column names into spanners with the `delim` argument #' - direction and amount of splitting: we can choose to split *n* times #' according to a `limit` argument, and, we get to specify from which side of -#' the column name the splitting should occur +#' the column name the splitting should commence #' - reversal of fragments: we can reverse the order the fragments we get from -#' the splitting procedure -#' - column constraints: define which columns in a **gt** table that should -#' participate in spanner creation using vectors or **tidyselect**-style -#' expressions +#' the splitting procedure with the `reverse` argument +#' - column constraints: it's possible to constrain which columns in a **gt** +#' table should participate in spanner creation using vectors or +#' **tidyselect**-style expressions #' #' @inheritParams tab_spanner #' From a7731810f74e897066cba9b8e2085b8326004709 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:50:01 -0500 Subject: [PATCH 06/10] Update tab_create_modify.R --- R/tab_create_modify.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/tab_create_modify.R b/R/tab_create_modify.R index bae0743c91..ecdd916d6d 100644 --- a/R/tab_create_modify.R +++ b/R/tab_create_modify.R @@ -828,8 +828,8 @@ resolve_spanned_column_names <- function( #' #' `scalar` // **required** #' -#' The delimiter to use to split an input column name. This should be a single -#' character (e.g., `"_"`, `"."`, etc.). +#' The delimiter text to use to split one of more column names (i.e., those +#' that are targeted via the `columns` argument). #' #' @param columns *Columns to target* #' From a023993b54b6710f3e6c8628eba4aee3728c43a1 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:50:17 -0500 Subject: [PATCH 07/10] Update cell_borders.Rd --- man/cell_borders.Rd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/man/cell_borders.Rd b/man/cell_borders.Rd index 271806c65a..1e933a36d5 100644 --- a/man/cell_borders.Rd +++ b/man/cell_borders.Rd @@ -20,16 +20,16 @@ can use the \code{"all"} option.} \verb{scalar|NULL} // \emph{default:} \code{"#000000"} The border \code{color} can be defined with a color name or with a hexadecimal -color code. The default \code{color} value is \code{"#000000"} (black). Borders for any -defined \code{sides} can be removed by supplying \code{NULL} here.} +color code. The default \code{color} value is \code{"#000000"} (black). Borders for +any defined \code{sides} can be removed by supplying \code{NULL} here.} \item{style}{\emph{Border line style} \verb{scalar|NULL} // \emph{default:} \code{"solid"} The border \code{style} can be one of either \code{"solid"} (the default), -\code{"dashed"}, \code{"dotted"}, \code{"hidden"}, or \code{"double"}. Borders for any -defined \code{sides} can be removed by supplying \code{NULL} here.} +\code{"dashed"}, \code{"dotted"}, \code{"hidden"}, or \code{"double"}. Borders for any defined +\code{sides} can be removed by supplying \code{NULL} here.} \item{weight}{\emph{Border weight} From 62b4eb92fa4bba5dc0fb406c27b6951df69bb993 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:50:20 -0500 Subject: [PATCH 08/10] Update tab_spanner_delim.Rd --- man/tab_spanner_delim.Rd | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/man/tab_spanner_delim.Rd b/man/tab_spanner_delim.Rd index d56c3ffbb5..0eb28198a1 100644 --- a/man/tab_spanner_delim.Rd +++ b/man/tab_spanner_delim.Rd @@ -25,8 +25,8 @@ This is the \strong{gt} table object that is commonly created through use of the \verb{scalar} // \strong{required} -The delimiter to use to split an input column name. This should be a single -character (e.g., \code{"_"}, \code{"."}, etc.).} +The delimiter text to use to split one of more column names (i.e., those +that are targeted via the \code{columns} argument).} \item{columns}{\emph{Columns to target} @@ -74,8 +74,8 @@ An object of class \code{gt_tbl}. \description{ The \code{tab_spanner_delim()} function can take specially-crafted column names and generate one or more spanners (and revise column labels at the same -time). This is done by splitting the column name by a specified delimiter -(this is the \code{delim}) and placing the fragments from top to bottom (i.e., +time). This is done by splitting the column name by the specified delimiter +text (\code{delim}) and placing the fragments from top to bottom (i.e., higher-level spanners to the column labels) or vice versa. Furthermore, neighboring text fragments on different spanner levels that have the same text will be coalesced together. For instance, having the three side-by-side @@ -85,16 +85,16 @@ the labels \code{"1"}, \code{"2"}, and \code{"3"}. There are many options in \code{cols_spanner_delim()} to slice and dice delimited column names in different ways: \itemize{ -\item the delimiter: choose which delimiter to use for the fragmentation of +\item delimiter text: choose the delimiter text to use for the fragmentation of column names into spanners with the \code{delim} argument \item direction and amount of splitting: we can choose to split \emph{n} times according to a \code{limit} argument, and, we get to specify from which side of -the column name the splitting should occur +the column name the splitting should commence \item reversal of fragments: we can reverse the order the fragments we get from -the splitting procedure -\item column constraints: define which columns in a \strong{gt} table that should -participate in spanner creation using vectors or \strong{tidyselect}-style -expressions +the splitting procedure with the \code{reverse} argument +\item column constraints: it's possible to constrain which columns in a \strong{gt} +table should participate in spanner creation using vectors or +\strong{tidyselect}-style expressions } } \section{Details on column splitting}{ From 669b71696d60e3c4d86d6d42b8fe633e22ac87a9 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:50:24 -0500 Subject: [PATCH 09/10] Update test-tab_spanner_delim.R --- tests/testthat/test-tab_spanner_delim.R | 99 +++++++++++++++++++++---- 1 file changed, 86 insertions(+), 13 deletions(-) diff --git a/tests/testthat/test-tab_spanner_delim.R b/tests/testthat/test-tab_spanner_delim.R index 7db20d01b9..01d045ae46 100644 --- a/tests/testthat/test-tab_spanner_delim.R +++ b/tests/testthat/test-tab_spanner_delim.R @@ -243,20 +243,12 @@ test_that("The `tab_spanner_delim()` function works correctly", { ) # Expect an error if an invalid delimiter specification is used; here - # we use strings that aren't a single character (and some cases, vectors - # with lengths not equal to one) - expect_error( - gt(iris_short) %>% - tab_spanner_delim(delim = "__") - ) + # we use strings that aren't at least a single character (and, in some cases, + # vectors with lengths not equal to one) expect_error( gt(iris_short) %>% tab_spanner_delim(delim = "") ) - expect_error( - gt(iris_short) %>% - tab_spanner_delim(delim = " ") - ) expect_error( gt(iris_short) %>% tab_spanner_delim(delim = c(".", ".")) @@ -767,7 +759,7 @@ test_that("`tab_spanner_delim()` works on higher-order spanning", { gt(tbl_5) %>% tab_spanner_delim(delim = ".") - # Take snapshots of `gt_tbl_5a` + # Take snapshot of `gt_tbl_5a` gt_tbl_5a %>% render_as_html() %>% expect_snapshot() gt_tbl_5b <- @@ -777,7 +769,7 @@ test_that("`tab_spanner_delim()` works on higher-order spanning", { columns = c(all.W.A, all.X.B) ) - # Take snapshots of `gt_tbl_5b` + # Take snapshot of `gt_tbl_5b` gt_tbl_5b %>% render_as_html() %>% expect_snapshot() gt_tbl_5c <- @@ -787,9 +779,90 @@ test_that("`tab_spanner_delim()` works on higher-order spanning", { columns = c(all.W.A, all.Z.B) ) - # Take snapshots of `gt_tbl_5c` + # Take snapshot of `gt_tbl_5c` gt_tbl_5c %>% render_as_html() %>% expect_snapshot() + # Generate a table with delimiters that are composed of several characters + # and are asymmetric with regard to the ordering of characters + tbl_5m <- + dplyr::tibble( + all__1W__1A = 1, + all__1X__1B = 2, + all__1Y__1A = 3, + all__1Z__1B = 4 + ) + + gt_tbl_5m_a <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "last") + + # Take snapshot of `gt_tbl_5m_a` + gt_tbl_5m_a %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_b <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "first") + + # Take snapshot of `gt_tbl_5m_b` + gt_tbl_5m_b %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_c <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "first", limit = 1) + + # Take snapshot of `gt_tbl_5m_c` + gt_tbl_5m_c %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_d <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "first", limit = 2) + + # Take snapshot of `gt_tbl_5m_d` + gt_tbl_5m_d %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_e <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "last", limit = 1) + + # Take snapshot of `gt_tbl_5m_e` + gt_tbl_5m_e %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_f <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "last", limit = 2) + + # Take snapshot of `gt_tbl_5m_f` + gt_tbl_5m_f %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_g <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "last", limit = 2, reverse = TRUE) + + # Take snapshot of `gt_tbl_5m_g` + gt_tbl_5m_g %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_h <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "first", limit = 2, reverse = TRUE) + + # Take snapshot of `gt_tbl_5m_h` + gt_tbl_5m_h %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_i <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "last", limit = 1, reverse = TRUE) + + # Take snapshot of `gt_tbl_5m_i` + gt_tbl_5m_i %>% render_as_html() %>% expect_snapshot() + + gt_tbl_5m_j <- + gt(tbl_5m) %>% + tab_spanner_delim(delim = "__1", split = "first", limit = 1, reverse = TRUE) + + # Take snapshot of `gt_tbl_5m_j` + gt_tbl_5m_j %>% render_as_html() %>% expect_snapshot() + + # # Combinations of `tab_spanner_delim()` and `tab_spanner()` to # generate otherwise tricky spanner constructions From 379ec8c7f7b5fa1dbec0324a43a9000ce5c1d510 Mon Sep 17 00:00:00 2001 From: Richard Iannone Date: Thu, 21 Dec 2023 14:50:27 -0500 Subject: [PATCH 10/10] Update tab_spanner_delim.md --- tests/testthat/_snaps/tab_spanner_delim.md | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/testthat/_snaps/tab_spanner_delim.md b/tests/testthat/_snaps/tab_spanner_delim.md index b0e0be91fe..e8f37dd564 100644 --- a/tests/testthat/_snaps/tab_spanner_delim.md +++ b/tests/testthat/_snaps/tab_spanner_delim.md @@ -47,6 +47,76 @@ Output [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n \n all\n
\n W\n all.X.Ball.Y.A\n Z\n
AB
1234
" +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n
\n W\n \n X\n \n Y\n \n Z\n
ABAB
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n
\n W\n \n X\n \n Y\n \n Z\n
ABAB
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n
W__1AX__1BY__1AZ__1B
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n
\n W\n \n X\n \n Y\n \n Z\n
ABAB
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all__1W\n \n all__1X\n \n all__1Y\n \n all__1Z\n
ABAB
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n all\n
\n W\n \n X\n \n Y\n \n Z\n
ABAB
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n A\n \n B\n \n A\n \n B\n
\n W\n \n X\n \n Y\n \n Z\n
allallallall
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n A\n \n B\n \n A\n \n B\n
\n W\n \n X\n \n Y\n \n Z\n
allallallall
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n A\n \n B\n \n A\n \n B\n
all__1Wall__1Xall__1Yall__1Z
1234
" + +--- + + Code + . + Output + [1] "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n \n \n \n
\n W__1A\n \n X__1B\n \n Y__1A\n \n Z__1B\n
allallallall
1234
" + --- Code