diff --git a/NAMESPACE b/NAMESPACE index 201c817ee1..2621bdbeb3 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -54,6 +54,7 @@ export(fmt_bytes) export(fmt_currency) export(fmt_date) export(fmt_datetime) +export(fmt_ggplot) export(fmt_duration) export(fmt_engineering) export(fmt_fraction) diff --git a/R/format_data.R b/R/format_data.R index f5509e41a9..5a5d53cf8e 100644 --- a/R/format_data.R +++ b/R/format_data.R @@ -4610,6 +4610,66 @@ fmt_passthrough <- function( } +#' Format ggplot cells +#' +#' It's possible to include \pkg{ggplot2} plots within a list column of the +#' input table data. The common pattern toward obtaining these plots is through +#' mutation of a list column containing all the `data` required for a plot +#' (e.g., ` %>% dplyr::group_by() %>% tidyr::nest(.key = plot) %>% +#' dplyr::mutate(plot = purrr::map(plot, ))`). While \pkg{gt} will +#' automatically format columns containing \pkg{ggplot2} plots, using the +#' `fmt_ggplot()` function allows us to specify specific `rows` and set options +#' for the plots' `height` and `aspect_ratio`. +#' +#' Targeting of values is done through `columns` and additionally by `rows` (if +#' nothing is provided for `rows` then entire columns are selected). A number of +#' helper functions exist to make targeting more effective. Conditional +#' formatting is possible by providing a conditional expression to the `rows` +#' argument. See the Arguments section for more information on this. +#' +#' @inheritParams fmt_number +#' @inheritParams ggplot_image +#' @return an object of class `gt_tbl`. +#' @export +fmt_ggplot <- fmt_gg <- function(data, + columns, + rows = NULL, + height = 100, + aspect_ratio = 1.0) { + + # Capture expression in `rows` + rows <- rlang::enquo(rows) + + # Pass `data`, `columns`, `rows`, and the formatting + # functions (as a function list) to `fmt()` + fmt(data = data, + columns = columns, + rows = !!rows, + fns = list( + html = function(x) { + + map( + x, + ggplot_image, + height = height, + aspect_ratio = aspect_ratio + ) + + }, + latex = function(x) { + + stop("This formatter is not yet implemented for LaTeX output.", + call. = FALSE) + }, + default = function(x) { + + stop("This formatter is not yet implemented.", + call. = FALSE) + } + )) + +} + #' Set a column format with a formatter function #' #' @description diff --git a/R/utils_render_common.R b/R/utils_render_common.R index 466570984a..31e4d0db69 100644 --- a/R/utils_render_common.R +++ b/R/utils_render_common.R @@ -153,13 +153,18 @@ migrate_unformatted_to_output <- function(data, context) { if (inherits(data_tbl[[colname]], "list")) { + # Use `lapply()` so that all values could be treated independently body[[colname]][row_index] <- lapply( - data_tbl[[colname]][row_index], - FUN = function(x) { + data_df[[colname]][row_index], + function(x) { + + if (inherits(x, "gg") && context == "html") { - if (is.numeric(x)) { + x <- ggplot_image(x) + + } if (is.numeric(x)) { x <- format( x, @@ -176,6 +181,7 @@ migrate_unformatted_to_output <- function(data, context) { } ) + } else { # No `lapply()` used: all values will be treated cohesively diff --git a/man/fmt_ggplot.Rd b/man/fmt_ggplot.Rd new file mode 100644 index 0000000000..f267d1bc24 --- /dev/null +++ b/man/fmt_ggplot.Rd @@ -0,0 +1,52 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/format_data.R +\name{fmt_ggplot} +\alias{fmt_ggplot} +\title{Format ggplot cells} +\usage{ +fmt_ggplot(data, columns, rows = NULL, height = 100, + aspect_ratio = 1) +} +\arguments{ +\item{data}{A table object that is created using the \code{\link[=gt]{gt()}} function.} + +\item{columns}{The columns to format. Can either be a series of column names +provided in \code{\link[=vars]{vars()}}, a vector of column indices, or a helper function +focused on selections. The select helper functions are: \code{\link[=starts_with]{starts_with()}}, +\code{\link[=ends_with]{ends_with()}}, \code{\link[=contains]{contains()}}, \code{\link[=matches]{matches()}}, \code{\link[=one_of]{one_of()}}, and \code{\link[=everything]{everything()}}.} + +\item{rows}{Optional rows to format. Not providing any value results in all +rows in \code{columns} being formatted. Can either be a vector of row captions +provided \code{\link[=c]{c()}}, a vector of row indices, or a helper function focused on +selections. The select helper functions are: \code{\link[=starts_with]{starts_with()}}, +\code{\link[=ends_with]{ends_with()}}, \code{\link[=contains]{contains()}}, \code{\link[=matches]{matches()}}, \code{\link[=one_of]{one_of()}}, and \code{\link[=everything]{everything()}}. +We can also use expressions to filter down to the rows we need (e.g., +\code{[colname_1] > 100 & [colname_2] < 50}).} + +\item{height}{The absolute height (px) of the image in the table cell.} + +\item{aspect_ratio}{The plot's final aspect ratio. Where the height of the +plot is fixed using the \code{height} argument, the \code{aspect_ratio} +will either compress (\code{aspect_ratio} < \code{1.0}) or expand +(\code{aspect_ratio} > \code{1.0}) the plot horizontally. The default value +of \code{1.0} will neither compress nor expand the plot.} +} +\value{ +an object of class \code{gt_tbl}. +} +\description{ +It's possible to include \pkg{ggplot2} plots within a list column of the +input table data. The common pattern toward obtaining these plots is through +mutation of a list column containing all the \code{data} required for a plot +(e.g., \code{ \%>\% dplyr::group_by() \%>\% tidyr::nest(.key = plot) \%>\% dplyr::mutate(plot = purrr::map(plot, ))}). While \pkg{gt} will +automatically format columns containing \pkg{ggplot2} plots, using the +\code{fmt_ggplot()} function allows us to specify specific \code{rows} and set options +for the plots' \code{height} and \code{aspect_ratio}. +} +\details{ +Targeting of values is done through \code{columns} and additionally by \code{rows} (if +nothing is provided for \code{rows} then entire columns are selected). A number of +helper functions exist to make targeting more effective. Conditional +formatting is possible by providing a conditional expression to the \code{rows} +argument. See the Arguments section for more information on this. +}