R/sprinkle_bg.R

Defines functions sprinkle_bg_index sprinkle_bg_index_assert sprinkle_bg.dust_list sprinkle_bg.default sprinkle_bg

Documented in sprinkle_bg sprinkle_bg.default sprinkle_bg.dust_list

#' @name sprinkle_bg
#' @title Sprinkle the Background Color of a Cell
#' 
#' @description Background colors may be used to highlight the contents 
#'   of cells, rows, or columns.  Most commonly, backgrounds are used to
#'   provide row discrimination; the \code{sprinkle_bg_pattern} function
#'   is better suited to that purpose.  
#'   
#' @param x An object of class \code{dust}
#' @param rows Either a numeric vector of rows in the tabular object to be 
#'   modified or an object of class \code{call}.  When a \code{call}, 
#'   generated by \code{quote(expression)}, the expression resolves to 
#'   a logical vector the same length as the number of rows in the table.
#'   Sprinkles are applied to where the expression resolves to \code{TRUE}.
#' @param cols Either a numeric vector of columns in the tabular object to
#'   be modified, or a character vector of column names. A mixture of 
#'   character and numeric indices is permissible.
#' @param bg \code{character(1)} A character string giving a color for the 
#'   background of the chosen cells.  
#' @param part A character string denoting which part of the table to modify.
#' @param fixed \code{logical(1)} indicating if the values in \code{rows} 
#'   and \code{cols} should be read as fixed coordinate pairs.  By default, 
#'   sprinkles are applied at the intersection of \code{rows} and \code{cols}, 
#'   meaning that the arguments do not have to share the same length.  
#'   When \code{fixed = TRUE}, they must share the same length.
#' @param recycle A \code{character} one that determines how sprinkles are 
#'   managed when the sprinkle input doesn't match the length of the region
#'   to be sprinkled.  By default, recycling is turned off.  Recycling 
#'   may be performed across rows first (left to right, top to bottom), 
#'   or down columns first (top to bottom, left to right).
#' @param ... Additional arguments to pass to other methods. Currently ignored.
#'   
#' @details Colors may be a dvips color name, or in the rgb(R, G, B), 
#' rgba(R, G, B, A), #RRGGBB, or #RRGGBBAA formats. 
#'   
#' This sprinkle is ignored in console and markdown outputs.  HTML output
#' will accept any of the color formats and recognize transparency.  LaTeX
#' output will accept any of the color formats but ignore transparency.
#' 
#' As long as \code{bg} is required to be a \code{character(1)}, the 
#' \code{recycle} argument is kind of useless. It is included to maintain
#' consistency with the \code{index_to_sprinkle} function. Future development
#' may permit a character vector of colors.
#' 
#' @section Functional Requirements:
#' \enumerate{
#'  \item Correctly reassigns the appropriate elements \code{bg} column
#'    in the table part.
#'  \item Casts an error if \code{x} is not a \code{dust} object.
#'  \item Casts an error if \code{bg} is not a \code{character(1)}
#'  \item Casts an error if \code{bg} is not a valid color format.
#'  \item Casts an error if \code{part} is not one of \code{"body"}, 
#'    \code{"head"}, \code{"foot"}, or \code{"interfoot"}
#'  \item Casts an error if \code{fixed} is not a \code{logical(1)}
#'  \item Casts an error if \code{recycle} is not one of \code{"none"},
#'    \code{"rows"}, or \code{"cols"}
#'  \item Casts an error if \code{recycle = "none"} and \code{bg} does not
#'    have length 1.
#' }
#' 
#' The functional behavior of the \code{fixed} and \code{recycle} arguments 
#' is not tested for this function. It is tested and validated in the
#' tests for \code{\link{index_to_sprinkle}}.
#' 
#' @seealso \code{\link{sprinkle}}, \code{\link{sprinkle_bg_pattern}}, 
#'   \code{\link{index_to_sprinkle}}
#'   
#' @author Benjamin Nutter
#' 
#' @export

sprinkle_bg <- function(x, rows = NULL, cols = NULL, bg = "", 
                        part = c("body", "head", "foot", "interfoot", "table"),
                        fixed = FALSE, 
                        recycle = c("none", "rows", "cols", "columns"), 
                        ...)
{
  UseMethod("sprinkle_bg")
}

#' @rdname sprinkle_bg
#' @export

sprinkle_bg.default <- function(x, rows = NULL, cols = NULL, bg = "", 
                                part = c("body", "head", "foot", "interfoot", "table"),
                                fixed = FALSE, 
                                recycle = c("none", "rows", "cols", "columns"), 
                                ...)
{
  coll <- checkmate::makeAssertCollection()
  
  checkmate::assert_class(x = x,
                          classes = "dust",
                          add = coll)
  
  indices <- index_to_sprinkle(x = x, 
                               rows = rows, 
                               cols = cols, 
                               fixed = fixed,
                               part = part,
                               recycle = recycle,
                               coll = coll)
  
  recycle <- recycle[1]
  
  sprinkle_bg_index_assert(bg = bg,
                           recycle = recycle,
                           coll = coll)
  
  checkmate::reportAssertions(coll)
  
  # At this point, part should have passed the assertions in 
  # index_to_sprinkle. The first element is expected to be valid.
  
  part <- part[1]
  
  sprinkle_bg_index(x = x, 
                    indices = indices, 
                    bg = bg, 
                    part = part)
  
}

#' @rdname sprinkle_bg
#' @export

sprinkle_bg.dust_list <- function(x, rows = NULL, cols = NULL, bg = "", 
                                  part = c("body", "head", "foot", "interfoot", "table"),
                                  fixed = FALSE, 
                                  recycle = c("none", "rows", "cols", "columns"), 
                                  ...)
{
  structure(
    lapply(X = x,
           FUN = sprinkle_bg.default,
           rows = rows,
           cols = cols,
           bg = bg,
           part = part,
           fixed = fixed,
           recycle = recycle,
           ...),
    class = "dust_list"
  )
}

#' @rdname sprinkle_bg
#' @export

sprinkle_background <- sprinkle_bg



# Unexported Utility ------------------------------------------------

# These functions are to be used inside of the general `sprinkle` call
# When used inside `sprinkle`, the indices are already determined, 
# the only the `bg` argument needs to be validated. 
# The assert function is kept separate so it may be called earlier
# without attempting to perform the assignment.

sprinkle_bg_index_assert <- function(bg = "", recycle = "none", coll)
{
  checkmate::assert_character(x = bg,
                              add = coll,
                              .var.name = "bg")
  
  if (recycle == "none" && length(bg) != 1)
  {
    coll$push("When `recycle` = 'none', `bg` must have length 1.")
  }
  
  if (!any(is_valid_color(bg)))
  {
    invalid_color <- bg[!is_valid_color(bg)]
    coll$push(sprintf("The following colors are not valid: %s",
                      paste0(invalid_color, collapse = ", ")))
  }
}

sprinkle_bg_index <- function(x, indices, bg, part)
{
  x[[part]][["bg"]][indices] <- bg
  
  x
}
nutterb/pixiedust documentation built on Oct. 17, 2023, 9:20 a.m.