diff --git a/R/modify_abbreviation.R b/R/modify_abbreviation.R index 518212625..edde312b6 100644 --- a/R/modify_abbreviation.R +++ b/R/modify_abbreviation.R @@ -34,7 +34,7 @@ modify_abbreviation <- function(x, abbreviation, text_interpret = c("md", "html" # add updates to `x$table_styling$abbreviation` ------------------------------ x <- x |> - .modify_abbreviation(abbreviation = abbreviation, text_interpret = paste0("gt::", text_interpret)) + .modify_abbreviation(abbreviation = abbreviation, text_interpret = text_interpret) # update call list and return table ------------------------------------------ x$call_list <- updated_call_list @@ -80,7 +80,7 @@ remove_abbreviation <- function(x, abbreviation) { dplyr::tibble( column = column, abbreviation = abbreviation, - text_interpret = text_interpret + text_interpret = paste0("gt::", text_interpret) ) ) x diff --git a/R/modify_table_styling.R b/R/modify_table_styling.R index 3ae9ac824..0baecd31d 100644 --- a/R/modify_table_styling.R +++ b/R/modify_table_styling.R @@ -1,10 +1,19 @@ #' Modify Table Styling #' +#' @description +#' This function is for developers. +#' If you are not a developer, it's recommended that you use the following +#' functions to make modifications to your table. [`modify_header()`], +#' [`modify_spanning_header()`], `[modify_column_hide()]`, [`modify_column_unhide()`], +#' [`modify_footnote_header()`], [`modify_footnote_body()`], [`modify_abbreviation()`], +#' [`modify_column_alignment()`], [`modify_fmt_fun()`], `[modify_column_indent()]`, +#' [`modify_column_merge()`]. +#' +#' #' This is a function meant for advanced users to gain #' more control over the characteristics of the resulting #' gtsummary table by directly modifying `.$table_styling`. -#' *This function is primarily used in the development of other gtsummary -#' functions, and very little checking of the passed arguments is performed.* +#' *This function has very little checking of the passed arguments.* #' #' Review the #' \href{https://www.danieldsjoberg.com/gtsummary/articles/gtsummary_definition.html}{gtsummary definition} @@ -101,7 +110,7 @@ modify_table_styling <- function(x, text_format = NULL, undo_text_format = NULL, indent = NULL, - text_interpret = c("md", "html"), + text_interpret = "md", cols_merge_pattern = NULL) { set_cli_abort_call() updated_call_list <- c(x$call_list, list(modify_table_styling = match.call())) @@ -175,8 +184,6 @@ modify_table_styling <- function(x, ) } - text_interpret <- paste0("gt::", arg_match(text_interpret)) - if (!is_empty(text_format)) { text_format <- arg_match(text_format, values = c("bold", "italic"), multiple = TRUE) } @@ -202,7 +209,7 @@ modify_table_styling <- function(x, x$table_styling$header <- x$table_styling$header %>% dplyr::rows_update( - dplyr::tibble(column = columns, interpret_label = text_interpret, label = label), + dplyr::tibble(column = columns, interpret_label = paste0("gt::", text_interpret), label = label), by = "column" ) } @@ -212,7 +219,7 @@ modify_table_styling <- function(x, x$table_styling$header <- x$table_styling$header %>% dplyr::rows_update( - dplyr::tibble(column = columns, interpret_spanning_header = text_interpret, spanning_header = spanning_header), + dplyr::tibble(column = columns, interpret_spanning_header = paste0("gt::", text_interpret), spanning_header = spanning_header), by = "column" ) } @@ -241,28 +248,25 @@ modify_table_styling <- function(x, if (!is_empty(footnote)) { # header footnotes if (tryCatch(is.null(eval_tidy(rows)), error = \(x) FALSE)) { - x$table_styling$footnote_header <- x$table_styling$footnote_header |> - dplyr::bind_rows( - dplyr::tibble( - column = columns, - footnote = footnote, - text_interpret = text_interpret, - replace = TRUE, - remove = is.na(footnote) - ) + x <- + .modify_footnote_header( + x = x, + lst_footnotes = + rep_named(columns, as.list(footnote)), + text_interpret = text_interpret, + replace = TRUE, + remove = is.na(footnote) ) } else { - x$table_styling$footnote_body <- x$table_styling$footnote_body |> - dplyr::bind_rows( - dplyr::tibble( - column = columns, - rows = list(rows), - footnote = footnote, - text_interpret = text_interpret, - replace = TRUE, - remove = is.na(footnote) - ) + x <- + .modify_footnote_body( + x = x, + lst_footnotes = rep_named(columns, as.list(footnote)), + rows = !!rows, + text_interpret = text_interpret, + replace = TRUE, + remove = is.na(footnote) ) } } diff --git a/R/utils-as.R b/R/utils-as.R index 932a3a7a6..87a4b695e 100644 --- a/R/utils-as.R +++ b/R/utils-as.R @@ -135,14 +135,7 @@ remove = ifelse(is.na(.data$footnote), TRUE, .data$remove), ) |> # within a column, if a later entry contains `replace=TRUE` or `remove=TRUE`, then mark the row for removal - dplyr::filter( - .by = "column", - !ifelse( - dplyr::row_number() == dplyr::n(), - FALSE, - as.logical(rev(cummax(rev(max(.data$replace, .data$remove))))) - ) - ) |> + .filter_row_with_subsequent_replace_or_removal() |> #finally, remove the row if it's marked for removal or if the column is not printed in final table dplyr::filter(!remove, .data$column %in% x$table_styling$header$column[!x$table_styling$header$hide]) @@ -159,15 +152,8 @@ ) ) |> tidyr::unnest(cols = "row_numbers") |> - # within a column, if a later entry contains `replace=TRUE` or `remove=TRUE`, then mark the row for removal - dplyr::filter( - .by = c("column", "row_numbers"), - !ifelse( - dplyr::row_number() == dplyr::n(), - FALSE, - as.logical(rev(cummax(rev(max(.data$replace, .data$remove))))) - ) - ) |> + # within a column/row, if a later entry contains `replace=TRUE` or `remove=TRUE`, then mark the row for removal + .filter_row_with_subsequent_replace_or_removal() |> #finally, remove the row if it's marked for removal or if the column is not printed in final table dplyr::filter(!remove, .data$column %in% x$table_styling$header$column[!x$table_styling$header$hide]) |> dplyr::select(all_of(c("column", "row_numbers", "text_interpret", "footnote"))) |> @@ -228,6 +214,32 @@ x } + +# this function processes the footnotes and removes footnotes that have +# later been replaced or removed from the table +.filter_row_with_subsequent_replace_or_removal <- function(x) { + if (nrow(x) == 0L) return(x) + + # within a column/row, if a later entry contains `replace=TRUE` or `remove=TRUE`, then mark the row for removal + dplyr::filter( + .data = x, + .by = any_of(c("column", "row_numbers")), + !unlist( + pmap( + list(.data$replace, .data$remove, dplyr::row_number()), + function(row_replace, row_remove, row_number) { + # if this is the last row in the group, there will be now removal indications below + if (row_number == dplyr::n()) return(FALSE) + # if a subsequent call to replace or remove a footnote appear below, + # then the current row can be deleted. + any(.data$replace[seq(row_number + 1L, dplyr::n())]) || + any(.data$remove[seq(row_number + 1L, dplyr::n())]) + } + ) + ) + ) +} + # this function orders the footnotes by where they first appear in the table, # and assigns them an sequential ID .number_footnotes <- function(x, type, start_with = 0L) { diff --git a/man/modify_table_styling.Rd b/man/modify_table_styling.Rd index 76d5c233a..8f69cdb4e 100644 --- a/man/modify_table_styling.Rd +++ b/man/modify_table_styling.Rd @@ -19,7 +19,7 @@ modify_table_styling( text_format = NULL, undo_text_format = NULL, indent = NULL, - text_interpret = c("md", "html"), + text_interpret = "md", cols_merge_pattern = NULL ) } @@ -78,13 +78,19 @@ use \code{"{conf.low}, {conf.high}"}. The first column listed in the pattern string must match the single column name passed in \verb{columns=}.} } \description{ +This function is for developers. +If you are not a developer, it's recommended that you use the following +functions to make modifications to your table. \code{\link[=modify_header]{modify_header()}}, +\code{\link[=modify_spanning_header]{modify_spanning_header()}}, \verb{[modify_column_hide()]}, \code{\link[=modify_column_unhide]{modify_column_unhide()}}, +\code{\link[=modify_footnote_header]{modify_footnote_header()}}, \code{\link[=modify_footnote_body]{modify_footnote_body()}}, \code{\link[=modify_abbreviation]{modify_abbreviation()}}, +\code{\link[=modify_column_alignment]{modify_column_alignment()}}, \code{\link[=modify_fmt_fun]{modify_fmt_fun()}}, \verb{[modify_column_indent()]}, +\code{\link[=modify_column_merge]{modify_column_merge()}}. + This is a function meant for advanced users to gain more control over the characteristics of the resulting gtsummary table by directly modifying \code{.$table_styling}. -\emph{This function is primarily used in the development of other gtsummary -functions, and very little checking of the passed arguments is performed.} -} -\details{ +\emph{This function has very little checking of the passed arguments.} + Review the \href{https://www.danieldsjoberg.com/gtsummary/articles/gtsummary_definition.html}{gtsummary definition} vignette for information on \code{.$table_styling} objects. diff --git a/tests/testthat/_snaps/as_kable_extra.md b/tests/testthat/_snaps/as_kable_extra.md index 1460b1914..9a9210891 100644 --- a/tests/testthat/_snaps/as_kable_extra.md +++ b/tests/testthat/_snaps/as_kable_extra.md @@ -97,7 +97,7 @@ [13] "