diff --git a/R/ctl_new_pillar.R b/R/ctl_new_pillar.R index 3cda3a9f1..0bca0d8d4 100644 --- a/R/ctl_new_pillar.R +++ b/R/ctl_new_pillar.R @@ -1,31 +1,21 @@ -#' Customize your tibble subclass +#' Customize the appearance of simple pillars in your tibble subclass +#' +#' @description +#' `r lifecycle::badge("experimental")` #' #' Gain full control over the appearance of the pillars of your tibble subclass #' in its body. -#' These methods are intended for implementers of subclasses of the `"tbl"` -#' class. +#' This method is intended for implementers of subclasses of the `"tbl"` class. #' Users will rarely need them. #' +#' @details #' `ctl_new_pillar()` is called to construct pillars for regular (one-dimensional) #' vectors. #' The default implementation returns an object constructed with [pillar()]. -#' Extend this method to tweak pillar components returned from the default +#' Extend this method to modify the pillar components returned from the default #' implementation. #' Override this method to completely change the appearance of the pillars. -#' -#' `ctl_new_pillar_list()` is called to construct a list of pillars. -#' It also works for compound pillars: columns that are data frames, matrices or -#' arrays. -#' This method is also called to initiate the construction of all pillars -#' in the tibble to be printed. -#' If called for a regular one-dimensional vector, it returns a list of length -#' one. -#' In any case, all pillars in the returned list of pillars represent only the -#' first column in case of compound columns. -#' This ensures that only those pillars that are shown are constructed. -#' To print all columns of a packed data frame, `ctl_new_pillar_list()` -#' eventually calls itself recursively. -#' Users will only rarely need to override this method if ever. +#' Components are created with [new_pillar_component()] or [pillar_component()]. #' #' All components must be of the same height. #' This restriction may be levied in the future. @@ -35,12 +25,14 @@ #' #' @inheritParams ellipsis::dots_empty #' @param controller The object of class `"tbl"` currently printed. -#' @param x A vector, can also be a data frame, array or matrix. -#' in `ctl_new_pillar_list()`. +#' @param x A simple (one-dimensional) vector. #' @param width The available width, can be a vector for multiple tiers. -#' If `NULL`, compute only the first pillar. #' @param title The title, derived from the name of the column in the data. #' +#' @seealso +#' See [ctl_new_pillar_list()] for creating pillar objects for compound columns: +#' packed data frames, matrices, or arrays. +#' #' @export #' @examplesIf rlang::is_installed("palmerpenguins") && requireNamespace("tibble") #' # Create pillar objects @@ -49,25 +41,12 @@ #' palmerpenguins::penguins$species[1:3], #' width = 60 #' ) +#' #' ctl_new_pillar( #' palmerpenguins::penguins, #' palmerpenguins::penguins$bill_length_mm[1:3], #' width = 60 #' ) -#' -#' # Packed data frame -#' ctl_new_pillar_list( -#' tibble::tibble(), -#' palmerpenguins::penguins, -#' width = 60 -#' ) -#' -#' # Packed matrix -#' ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = 60) -#' -#' # Packed array -#' ctl_new_pillar_list(tibble::tibble(), Titanic, width = 60) -#' #' @examples #' #' # Customize output @@ -116,45 +95,3 @@ max0 <- function(x) { 0L } } - -#' @param first_pillar Can be passed to this method if the first pillar -#' for a compound pillar (or the pillar itself for a simple pillar) -#' has been computed already. -#' @rdname ctl_new_pillar -#' @export -ctl_new_pillar_list <- function(controller, x, width, ..., title = NULL, first_pillar = NULL) { - "!!!!DEBUG ctl_new_pillar_list(`v(width)`, `v(title)`)" - - check_dots_empty() - - UseMethod("ctl_new_pillar_list") -} - -#' @export -ctl_new_pillar_list.tbl <- function(controller, x, width, ..., title = NULL, first_pillar = NULL) { - "!!!!DEBUG ctl_new_pillar_list.tbl(`v(width)`, `v(title)`)" - - if (is.data.frame(x)) { - new_data_frame_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) - } else if (is.matrix(x)) { - new_matrix_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) - } else if (is.array(x) && length(dim(x)) > 1) { - new_array_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) - } else { - if (is.null(first_pillar)) { - first_pillar <- ctl_new_pillar(controller, x, width, ..., title = prepare_title(title)) - } - new_single_pillar_list(first_pillar, width) - } -} - -prepare_title <- function(title) { - n_title <- length(title) - if (n_title == 0) { - title - } else if (grepl("^[[]", title[[n_title]])) { - paste0(paste(title[-n_title], collapse = "$"), title[[n_title]]) - } else { - paste(title, collapse = "$") - } -} diff --git a/R/ctl_new_pillar_list.R b/R/ctl_new_pillar_list.R index 18328262e..f94228d24 100644 --- a/R/ctl_new_pillar_list.R +++ b/R/ctl_new_pillar_list.R @@ -1,3 +1,111 @@ +#' Customize the appearance of compound pillars in your tibble subclass +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' Gain full control over the appearance of the pillars of your tibble subclass +#' in its body. +#' This method is intended for implementers of subclasses of the `"tbl"` class. +#' Users will rarely need them, and we also expect the default implementation +#' to be sufficient for the vast majority of cases. +#' +#' @details +#' `ctl_new_pillar_list()` is called to construct a list of pillars. +#' If `x` is a regular (one-dimensional) vector, the list contains one pillar +#' constructed by [ctl_new_pillar()]. +#' This method also works for compound columns: columns that are data frames, +#' matrices or arrays, with the following behavior: +#' +#' - If `width` is `NULL`, the method always returns a list of length one +#' containing one pillar object that represents the first sub-column in this +#' compound column. +#' - Otherwise, the returned list contains one pillar object for all sub-columns +#' that can be fit in the available horizontal space. +#' These pillar objects are obtained by calling `ctl_new_pillar_list()` +#' with `width = NULL` on each sub-column until the available width is +#' exhausted. +#' +#' This method is called to initiate the construction of all pillars +#' in the tibble to be printed. +#' To ensure that all packed columns that fit the available space are printed, +#' `ctl_new_pillar_list()` may be called twice on the same input: +#' once with `width = NULL`, and +#' once with `width` corresponding to the then known available space +#' and with `first_pillar` set to the pillar object constructed in the +#' first call. +#' +#' @inheritParams ctl_new_pillar +#' @param x A vector, can also be a data frame, matrix, or array. +#' @param width The available width, can be a vector for multiple tiers. +#' If `NULL`, only the first pillar is instantiated. +#' @param first_pillar Can be passed to this method if the first pillar +#' for a compound pillar (or the pillar itself for a simple pillar) +#' has been constructed already. +#' @export +#' @examplesIf rlang::is_installed("palmerpenguins") && requireNamespace("tibble") +#' # Simple column +#' ctl_new_pillar_list( +#' tibble::tibble(), +#' palmerpenguins::penguins$weight[1:3], +#' width = 10 +#' ) +#' +#' # Packed data frame: unknown width +#' ctl_new_pillar_list( +#' tibble::tibble(), +#' palmerpenguins::penguins[1:3, ], +#' width = NULL +#' ) +#' +#' # Packed data frame: known width +#' ctl_new_pillar_list( +#' tibble::tibble(), +#' palmerpenguins::penguins, +#' width = 60 +#' ) +#' +#' # Deeply packed data frame with known width: +#' # showing only the first sub-column even if the width is sufficient +#' ctl_new_pillar_list( +#' tibble::tibble(), +#' tibble::tibble(x = tibble::tibble(b = 1, c = 2), y = 3), +#' width = 60 +#' ) +#' +#' # Packed matrix: unknown width +#' ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = NULL) +#' +#' # Packed matrix: known width +#' ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = 60) +#' +#' # Packed array +#' ctl_new_pillar_list(tibble::tibble(), Titanic, width = 60) +ctl_new_pillar_list <- function(controller, x, width, ..., title = NULL, first_pillar = NULL) { + "!!!!DEBUG ctl_new_pillar_list(`v(width)`, `v(title)`)" + + check_dots_empty() + + UseMethod("ctl_new_pillar_list") +} + +#' @export +ctl_new_pillar_list.tbl <- function(controller, x, width, ..., title = NULL, first_pillar = NULL) { + "!!!!DEBUG ctl_new_pillar_list.tbl(`v(width)`, `v(title)`)" + + if (is.data.frame(x)) { + new_data_frame_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) + } else if (is.matrix(x)) { + new_matrix_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) + } else if (is.array(x) && length(dim(x)) > 1) { + new_array_pillar_list(x, controller, width, title = title, first_pillar = first_pillar) + } else { + if (is.null(first_pillar)) { + first_pillar <- ctl_new_pillar(controller, x, width, ..., title = prepare_title(title)) + } + new_single_pillar_list(first_pillar, width) + } +} + new_data_frame_pillar_list <- function(x, controller, width, title, first_pillar = NULL) { "!!!!!DEBUG new_data_frame_pillar_list(`v(width)`, `v(title)`)" @@ -209,3 +317,14 @@ new_pillar_list <- function(pillar_list, extra, remaining_width, simple = FALSE) simple = simple ) } + +prepare_title <- function(title) { + n_title <- length(title) + if (n_title == 0) { + title + } else if (grepl("^[[]", title[[n_title]])) { + paste0(paste(title[-n_title], collapse = "$"), title[[n_title]]) + } else { + paste(title, collapse = "$") + } +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 6a0473c93..ff820ba0c 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -11,6 +11,7 @@ reference: - tbl_format_body - tbl_format_footer - ctl_new_pillar + - ctl_new_pillar_list - tbl_sum - glimpse - format_glimpse diff --git a/man/ctl_new_pillar.Rd b/man/ctl_new_pillar.Rd index d2781502f..7458df7db 100644 --- a/man/ctl_new_pillar.Rd +++ b/man/ctl_new_pillar.Rd @@ -2,65 +2,37 @@ % Please edit documentation in R/ctl_new_pillar.R \name{ctl_new_pillar} \alias{ctl_new_pillar} -\alias{ctl_new_pillar_list} -\title{Customize your tibble subclass} +\title{Customize the appearance of simple pillars in your tibble subclass} \usage{ ctl_new_pillar(controller, x, width, ..., title = NULL) - -ctl_new_pillar_list( - controller, - x, - width, - ..., - title = NULL, - first_pillar = NULL -) } \arguments{ \item{controller}{The object of class \code{"tbl"} currently printed.} -\item{x}{A vector, can also be a data frame, array or matrix. -in \code{ctl_new_pillar_list()}.} +\item{x}{A simple (one-dimensional) vector.} -\item{width}{The available width, can be a vector for multiple tiers. -If \code{NULL}, compute only the first pillar.} +\item{width}{The available width, can be a vector for multiple tiers.} \item{...}{These dots are for future extensions and must be empty.} \item{title}{The title, derived from the name of the column in the data.} - -\item{first_pillar}{Can be passed to this method if the first pillar -for a compound pillar (or the pillar itself for a simple pillar) -has been computed already.} } \description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + Gain full control over the appearance of the pillars of your tibble subclass in its body. -These methods are intended for implementers of subclasses of the \code{"tbl"} -class. +This method is intended for implementers of subclasses of the \code{"tbl"} class. Users will rarely need them. } \details{ \code{ctl_new_pillar()} is called to construct pillars for regular (one-dimensional) vectors. The default implementation returns an object constructed with \code{\link[=pillar]{pillar()}}. -Extend this method to tweak pillar components returned from the default +Extend this method to modify the pillar components returned from the default implementation. Override this method to completely change the appearance of the pillars. - -\code{ctl_new_pillar_list()} is called to construct a list of pillars. -It also works for compound pillars: columns that are data frames, matrices or -arrays. -This method is also called to initiate the construction of all pillars -in the tibble to be printed. -If called for a regular one-dimensional vector, it returns a list of length -one. -In any case, all pillars in the returned list of pillars represent only the -first column in case of compound columns. -This ensures that only those pillars that are shown are constructed. -To print all columns of a packed data frame, \code{ctl_new_pillar_list()} -eventually calls itself recursively. -Users will only rarely need to override this method if ever. +Components are created with \code{\link[=new_pillar_component]{new_pillar_component()}} or \code{\link[=pillar_component]{pillar_component()}}. All components must be of the same height. This restriction may be levied in the future. @@ -76,24 +48,12 @@ ctl_new_pillar( palmerpenguins::penguins$species[1:3], width = 60 ) + ctl_new_pillar( palmerpenguins::penguins, palmerpenguins::penguins$bill_length_mm[1:3], width = 60 ) - -# Packed data frame -ctl_new_pillar_list( - tibble::tibble(), - palmerpenguins::penguins, - width = 60 -) - -# Packed matrix -ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = 60) - -# Packed array -ctl_new_pillar_list(tibble::tibble(), Titanic, width = 60) \dontshow{\}) # examplesIf} # Customize output @@ -121,3 +81,7 @@ vctrs::new_data_frame( class = c("line_tbl", "tbl") ) } +\seealso{ +See \code{\link[=ctl_new_pillar_list]{ctl_new_pillar_list()}} for creating pillar objects for compound columns: +packed data frames, matrices, or arrays. +} diff --git a/man/ctl_new_pillar_list.Rd b/man/ctl_new_pillar_list.Rd new file mode 100644 index 000000000..e7464f088 --- /dev/null +++ b/man/ctl_new_pillar_list.Rd @@ -0,0 +1,107 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ctl_new_pillar_list.R +\name{ctl_new_pillar_list} +\alias{ctl_new_pillar_list} +\title{Customize the appearance of compound pillars in your tibble subclass} +\usage{ +ctl_new_pillar_list( + controller, + x, + width, + ..., + title = NULL, + first_pillar = NULL +) +} +\arguments{ +\item{controller}{The object of class \code{"tbl"} currently printed.} + +\item{x}{A vector, can also be a data frame, matrix, or array.} + +\item{width}{The available width, can be a vector for multiple tiers. +If \code{NULL}, only the first pillar is instantiated.} + +\item{...}{These dots are for future extensions and must be empty.} + +\item{title}{The title, derived from the name of the column in the data.} + +\item{first_pillar}{Can be passed to this method if the first pillar +for a compound pillar (or the pillar itself for a simple pillar) +has been constructed already.} +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + +Gain full control over the appearance of the pillars of your tibble subclass +in its body. +This method is intended for implementers of subclasses of the \code{"tbl"} class. +Users will rarely need them, and we also expect the default implementation +to be sufficient for the vast majority of cases. +} +\details{ +\code{ctl_new_pillar_list()} is called to construct a list of pillars. +If \code{x} is a regular (one-dimensional) vector, the list contains one pillar +constructed by \code{\link[=ctl_new_pillar]{ctl_new_pillar()}}. +This method also works for compound columns: columns that are data frames, +matrices or arrays, with the following behavior: +\itemize{ +\item If \code{width} is \code{NULL}, the method always returns a list of length one +containing one pillar object that represents the first sub-column in this +compound column. +\item Otherwise, the returned list contains one pillar object for all sub-columns +that can be fit in the available horizontal space. +These pillar objects are obtained by calling \code{ctl_new_pillar_list()} +with \code{width = NULL} on each sub-column until the available width is +exhausted. +} + +This method is called to initiate the construction of all pillars +in the tibble to be printed. +To ensure that all packed columns that fit the available space are printed, +\code{ctl_new_pillar_list()} may be called twice on the same input: +once with \code{width = NULL}, and +once with \code{width} corresponding to the then known available space +and with \code{first_pillar} set to the pillar object constructed in the +first call. +} +\examples{ +\dontshow{if (rlang::is_installed("palmerpenguins") && requireNamespace("tibble")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +# Simple column +ctl_new_pillar_list( + tibble::tibble(), + palmerpenguins::penguins$weight[1:3], + width = 10 +) + +# Packed data frame: unknown width +ctl_new_pillar_list( + tibble::tibble(), + palmerpenguins::penguins[1:3, ], + width = NULL +) + +# Packed data frame: known width +ctl_new_pillar_list( + tibble::tibble(), + palmerpenguins::penguins, + width = 60 +) + +# Deeply packed data frame with known width: +# showing only the first sub-column even if the width is sufficient +ctl_new_pillar_list( + tibble::tibble(), + tibble::tibble(x = tibble::tibble(b = 1, c = 2), y = 3), + width = 60 +) + +# Packed matrix: unknown width +ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = NULL) + +# Packed matrix: known width +ctl_new_pillar_list(tibble::tibble(), matrix(1:6, ncol = 2), width = 60) + +# Packed array +ctl_new_pillar_list(tibble::tibble(), Titanic, width = 60) +\dontshow{\}) # examplesIf} +}