|
41 | 41 | #' equal the number of columns. For instance, `align = "lccrl"` would |
42 | 42 | #' left-align the first column, center the second and third, right-align |
43 | 43 | #' column four and left-align the fifth column. |
44 | | -#' @param by Name of column in `x` that indicates grouping for tables. |
45 | | -#' Only applies when `format = "html"`. `by` is passed down to |
46 | | -#' `gt::gt(groupname_col = by)`. |
| 44 | +#' @param by Name of column(s) in `x` that indicates grouping for tables. |
| 45 | +#' When `format = "html"`, `by` is passed down to `gt::gt(groupname_col = by)`. |
| 46 | +#' For markdown and text format, `x` is internally split into a list of data |
| 47 | +#' frames. |
47 | 48 | #' @param width Refers to the width of columns (with numeric values). Can be |
48 | 49 | #' either `NULL`, a number or a named numeric vector. If `NULL`, the width for |
49 | 50 | #' each column is adjusted to the minimum required width. If a number, columns |
|
99 | 100 | #' # split longer tables |
100 | 101 | #' export_table(head(iris), table_width = 30) |
101 | 102 | #' |
| 103 | +#' # group (split) tables by variables |
| 104 | +#' export_table(head(mtcars, 8), by = "cyl") |
| 105 | +#' |
102 | 106 | #' \donttest{ |
103 | 107 | #' # colored footers |
104 | 108 | #' data(iris) |
@@ -194,6 +198,8 @@ export_table <- function(x, |
194 | 198 | indent_groups <- attributes(x)$indent_groups |
195 | 199 | indent_rows <- attributes(x)$indent_rows |
196 | 200 |
|
| 201 | + # split data frames? |
| 202 | + x <- .split_tables(x, by, format) |
197 | 203 |
|
198 | 204 | # table from single data frame -------------------------------------------- |
199 | 205 |
|
@@ -360,6 +366,64 @@ print.insight_table <- function(x, ...) { |
360 | 366 |
|
361 | 367 | # small helper ---------------------- |
362 | 368 |
|
| 369 | +# split data frame for text format - unlike HTML, where we need to bind |
| 370 | +# lists of data frames to a single data frame and have a "group_by" variable, |
| 371 | +# we need a list of data frames for text or markdown output (instead of a |
| 372 | +# single data frame) |
| 373 | +.split_tables <- function(x, by, format) { |
| 374 | + if (!is.null(by) && is.data.frame(x) && !identical(format, "html")) { |
| 375 | + # convert formula into string |
| 376 | + if (inherits(by, "formula")) { |
| 377 | + by <- all.vars(by) |
| 378 | + } |
| 379 | + # numeric indices are possible - just extract column names at that positions |
| 380 | + if (is.numeric(by)) { |
| 381 | + if (any(by < 1 || by > ncol(x))) { |
| 382 | + format_error("Indices in `by` cannot be lower than 1 or higher than the number of columns in the data frame.") |
| 383 | + } |
| 384 | + by <- colnames(x)[by] |
| 385 | + } |
| 386 | + # check if all by columns are in the data |
| 387 | + if (!all(by %in% colnames(x))) { |
| 388 | + suggestion <- .misspelled_string(colnames(x), by) |
| 389 | + msg <- "Not all variables in `by` were found in the data frame." |
| 390 | + if (is.null(suggestion$msg) || !length(suggestion$msg) || !nzchar(suggestion$msg)) { |
| 391 | + msg <- paste(msg, "Please use one of the following names:", .to_string(colnames(x))) |
| 392 | + } else { |
| 393 | + msg <- paste(msg, suggestion$msg) |
| 394 | + } |
| 395 | + format_error(msg) |
| 396 | + } |
| 397 | + # convert `by` columns into factor. we do this so split works with correct |
| 398 | + # order of values in "by" columns. If `by` columns are character vector, |
| 399 | + # `split()` sorts alpahbetically, which we don't want |
| 400 | + x[by] <- lapply(x[by], function(i) { |
| 401 | + factor(i, levels = unique(i)) |
| 402 | + }) |
| 403 | + |
| 404 | + # create titles based on group names and levels |
| 405 | + groups <- expand.grid(lapply(x[by], unique)) |
| 406 | + groups[] <- lapply(groups, as.character) |
| 407 | + |
| 408 | + group_titles <- lapply(seq_len(nrow(groups)), function(i) { |
| 409 | + paste0(colnames(groups), "=", as.character(groups[i, ]), collapse = ", ") |
| 410 | + }) |
| 411 | + |
| 412 | + # split data frames |
| 413 | + x <- split(x, x[by]) |
| 414 | + |
| 415 | + # remove by-columns and set title |
| 416 | + x <- lapply(seq_along(x), function(i) { |
| 417 | + x[[i]][by] <- NULL |
| 418 | + attr(x[[i]], "table_title") <- c(paste("Group:", group_titles[[i]]), "blue") |
| 419 | + x[[i]] |
| 420 | + }) |
| 421 | + } |
| 422 | + |
| 423 | + x |
| 424 | +} |
| 425 | + |
| 426 | + |
363 | 427 | # check whether "table_caption" or its alias "table_title" is used as attribute |
364 | 428 | .check_caption_attr_name <- function(x) { |
365 | 429 | attr_name <- "table_caption" |
|
0 commit comments