Skip to content

Commit bb94d6c

Browse files
authored
by in export_table() also works for non-html format (#1068)
* `by` in `export_table()` also works for non-html format * fix * fix * add tests * add example
1 parent be76f0a commit bb94d6c

6 files changed

Lines changed: 432 additions & 7 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: insight
33
Title: Easy Access to Model Information for Various Model Objects
4-
Version: 1.2.0.8
4+
Version: 1.2.0.9
55
Authors@R:
66
c(person(given = "Daniel",
77
family = "Lüdecke",

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
to `get_parameters()`, which is in turn passed to `as.data.frame()`, to
2727
extract parameters more efficiently.
2828

29+
* The `by` argument in `export_table()` now also splits tables when format is
30+
not `"html"`.
31+
2932
# insight 1.2.0
3033

3134
## Breaking Changes

R/export_table.R

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@
4141
#' equal the number of columns. For instance, `align = "lccrl"` would
4242
#' left-align the first column, center the second and third, right-align
4343
#' 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.
4748
#' @param width Refers to the width of columns (with numeric values). Can be
4849
#' either `NULL`, a number or a named numeric vector. If `NULL`, the width for
4950
#' each column is adjusted to the minimum required width. If a number, columns
@@ -99,6 +100,9 @@
99100
#' # split longer tables
100101
#' export_table(head(iris), table_width = 30)
101102
#'
103+
#' # group (split) tables by variables
104+
#' export_table(head(mtcars, 8), by = "cyl")
105+
#'
102106
#' \donttest{
103107
#' # colored footers
104108
#' data(iris)
@@ -194,6 +198,8 @@ export_table <- function(x,
194198
indent_groups <- attributes(x)$indent_groups
195199
indent_rows <- attributes(x)$indent_rows
196200

201+
# split data frames?
202+
x <- .split_tables(x, by, format)
197203

198204
# table from single data frame --------------------------------------------
199205

@@ -360,6 +366,64 @@ print.insight_table <- function(x, ...) {
360366

361367
# small helper ----------------------
362368

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+
363427
# check whether "table_caption" or its alias "table_title" is used as attribute
364428
.check_caption_attr_name <- function(x) {
365429
attr_name <- "table_caption"

man/export_table.Rd

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/export_table.md

Lines changed: 334 additions & 0 deletions
Large diffs are not rendered by default.

tests/testthat/test-export_table.R

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,23 @@ test_that("export_table, new column names", {
283283
regex = "is a named vector"
284284
)
285285
})
286+
287+
288+
test_that("export_table, by in text format", {
289+
data(mtcars)
290+
data(iris)
291+
292+
expect_snapshot(export_table(mtcars, by = c("cyl", "gear")))
293+
expect_snapshot(export_table(iris, by = "Species"))
294+
expect_snapshot(export_table(mtcars, by = ~ cyl + gear))
295+
296+
# errors
297+
expect_error(
298+
export_table(iris, by = "Specis"),
299+
regex = "Not all variables"
300+
)
301+
expect_error(
302+
export_table(iris, by = 6),
303+
regex = "cannot be lower"
304+
)
305+
})

0 commit comments

Comments
 (0)