diff --git a/NAMESPACE b/NAMESPACE index 115ded97..3e933bde 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,11 @@ # Generated by roxygen2: do not edit by hand +S3method(as_continuous_pal,"function") +S3method(as_continuous_pal,default) +S3method(as_continuous_pal,pal_discrete) +S3method(as_discrete_pal,"function") +S3method(as_discrete_pal,default) +S3method(as_discrete_pal,pal_continuous) S3method(fullseq,Date) S3method(fullseq,POSIXt) S3method(fullseq,difftime) @@ -38,6 +44,8 @@ export(alpha) export(area_pal) export(as.trans) export(as.transform) +export(as_continuous_pal) +export(as_discrete_pal) export(asinh_trans) export(asn_trans) export(atanh_trans) @@ -92,6 +100,11 @@ export(identity_pal) export(identity_trans) export(is.trans) export(is.transform) +export(is_colour_pal) +export(is_continuous_pal) +export(is_discrete_pal) +export(is_numeric_pal) +export(is_pal) export(label_bytes) export(label_comma) export(label_currency) @@ -124,6 +137,8 @@ export(minor_breaks_n) export(minor_breaks_width) export(modulus_trans) export(muted) +export(new_continuous_palette) +export(new_discrete_palette) export(new_transform) export(number) export(number_bytes) @@ -155,6 +170,9 @@ export(pal_rescale) export(pal_seq_gradient) export(pal_shape) export(pal_viridis) +export(palette_na_safe) +export(palette_nlevels) +export(palette_type) export(parse_format) export(percent) export(percent_format) diff --git a/R/pal-.R b/R/pal-.R index e210e9c6..dd2bd50f 100644 --- a/R/pal-.R +++ b/R/pal-.R @@ -1,5 +1,65 @@ # Constructors ------------------------------------------------------------ +#' Constructors for palettes +#' +#' These constructor functions attach metadata to palette functions. This +#' metadata can be used in testing or coercion. +#' +#' @param fun A function to serve as a palette. For continuous palettes, these +#' typically take vectors of numeric values between (0, 1) and return a +#' vector of equal length. For discrete palettes, these typically take a +#' scalar integer and return a vector of that length. +#' @param type A string giving the type of return values. Some example strings +#' include `"colour"`, `"numeric"`, `"linetype"` or `"shape"`. +#' @param na_safe A boolean indicating whether `NA` values are translated to +#' palette values (`TRUE`) or are kept as `NA` (`FALSE`). Applies to +#' continuous palettes. +#' @param nlevels An integer giving the number of distinct palette values +#' that can be returned by the discrete palette. +#' @param x An object to test or coerce. +#' @param pal A palette to retrieve properties from. +#' +#' @return +#' For `new_continuous_palette()`, `new_discret_palette()`, `as_discrete_pal()` +#' and `as_continuous_pal()`: a function of class `pal_continuous` or `pal_discrete`. +#' For `is_pal()`, `is_continuous_pal()`, `is_discret_pal()`, `is_colour_pal()`, +#' or `is_numeric_pal()`: a logical value of length 1. +#' For `palette_nlevels()` a single integer. For `palette_na_safe()` a boolean. +#' For `palette_type()` a string. +#' @export +#' +#' @examples +#' # Creating a new discrete palette +#' new_discrete_palette( +#' fun = grDevices::terrain.colors, +#' type = "colour", nlevels = 255 +#' ) +#' +#' # Creating a new continuous palette +#' new_continuous_palette( +#' fun = function(x) rescale(x, to = c(1, 0)), +#' type = "numeric", na_safe = FALSE +#' ) +#' +#' # Testing palette properties +#' is_continuous_pal(pal_seq_gradient()) +#' is_discrete_pal(pal_viridis()) +#' is_numeric_pal(pal_area()) +#' is_colour_pal(pal_manual(c("red", "green"))) +#' is_pal(transform_log10()) +#' +#' # Extracting properties +#' palette_nlevels(pal_viridis()) +#' palette_na_safe(colour_ramp(c("red", "green"), na.color = "grey50")) +#' palette_type(pal_shape()) +#' +#' # Switching discrete to continuous +#' pal <- as_continuous_pal(pal_viridis()) +#' show_col(pal(c(0, 0.1, 0.2, 0.4, 1))) +#' +#' # Switching continuous to discrete +#' pal <- as_discrete_pal(pal_div_gradient()) +#' show_col(pal(9)) new_continuous_palette <- function(fun, type, na_safe = NA) { if (!is.function(fun)) { cli::cli_abort("{.arg fun} must be a function.") @@ -10,6 +70,8 @@ new_continuous_palette <- function(fun, type, na_safe = NA) { fun } +#' @rdname new_continuous_palette +#' @export new_discrete_palette <- function(fun, type, nlevels = NA) { if (!is.function(fun)) { cli::cli_abort("{.arg fun} must be a function.") @@ -20,28 +82,46 @@ new_discrete_palette <- function(fun, type, nlevels = NA) { fun } - # Testing ----------------------------------------------------------------- +#' @rdname new_continuous_palette +#' @export is_pal <- function(x) inherits(x, c("pal_discrete", "pal_continuous")) + +#' @rdname new_continuous_palette +#' @export is_continuous_pal <- function(x) inherits(x, "pal_continuous") + +#' @rdname new_continuous_palette +#' @export is_discrete_pal <- function(x) inherits(x, "pal_discrete") +#' @rdname new_continuous_palette +#' @export is_colour_pal <- function(x) { is_pal(x) && any(palette_type(x) %in% c("color", "colour")) } + +#' @rdname new_continuous_palette +#' @export is_numeric_pal <- function(x) { is_pal(x) && any(palette_type(x) %in% c("numeric", "double", "integer")) } # Getters ----------------------------------------------------------------- +#' @rdname new_continuous_palette +#' @export palette_nlevels <- function(pal) { as.integer(attr(pal, "nlevels")[1] %||% NA_integer_) } +#' @rdname new_continuous_palette +#' @export palette_na_safe <- function(pal) { as.logical(attr(pal, "na_safe")[1] %||% FALSE) } +#' @rdname new_continuous_palette +#' @export palette_type <- function(pal) { as.character(attr(pal, "type")[1] %||% NA_character_) } @@ -50,18 +130,23 @@ palette_type <- function(pal) { ## As discrete palette ---------------------------------------------------- +#' @rdname new_continuous_palette +#' @export as_discrete_pal <- function(x, ...) { UseMethod("as_discrete_pal") } +#' @export as_discrete_pal.default <- function(x, ...) { cli::cli_abort("Cannot convert {.arg x} to a discrete palette.") } +#' @export as_discrete_pal.function <- function(x, ...) { x } +#' @export as_discrete_pal.pal_continuous <- function(x, ...) { force(x) new_discrete_palette( @@ -72,18 +157,23 @@ as_discrete_pal.pal_continuous <- function(x, ...) { ## As continuous palette -------------------------------------------------- +#' @rdname new_continuous_palette +#' @export as_continuous_pal <- function(x, ...) { UseMethod("as_continuous_pal") } +#' @export as_continuous_pal.default <- function(x, ...) { cli::cli_abort("Cannot convert {.arg x} to a continuous palette.") } +#' @export as_continuous_pal.function <- function(x, ...) { x } +#' @export as_continuous_pal.pal_discrete <- function(x, ...) { nlevels <- palette_nlevels(x) if (!is_scalar_integerish(nlevels, finite = TRUE)) { diff --git a/R/pal-manual.R b/R/pal-manual.R index 6a02b528..6c3c6ca1 100644 --- a/R/pal-manual.R +++ b/R/pal-manual.R @@ -1,6 +1,7 @@ #' Manual palette (discrete) #' #' @param values vector of values to be used as a palette. +#' @inheritParams new_continuous_palette #' @export pal_manual <- function(values, type = NULL) { force(values) diff --git a/man/new_continuous_palette.Rd b/man/new_continuous_palette.Rd new file mode 100644 index 00000000..f9593940 --- /dev/null +++ b/man/new_continuous_palette.Rd @@ -0,0 +1,84 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/pal-.R +\name{new_continuous_palette} +\alias{new_continuous_palette} +\alias{new_discrete_palette} +\alias{is_pal} +\alias{is_continuous_pal} +\alias{is_discrete_pal} +\alias{is_colour_pal} +\alias{is_numeric_pal} +\alias{palette_nlevels} +\alias{palette_na_safe} +\alias{palette_type} +\alias{as_discrete_pal} +\alias{as_continuous_pal} +\title{Constructors for palettes} +\usage{ +new_continuous_palette(fun, type, na_safe = NA) + +new_discrete_palette(fun, type, nlevels = NA) + +is_pal(x) + +is_continuous_pal(x) + +is_discrete_pal(x) + +is_colour_pal(x) + +is_numeric_pal(x) + +palette_nlevels(pal) + +palette_na_safe(pal) + +palette_type(pal) + +as_discrete_pal(x, ...) + +as_continuous_pal(x, ...) +} +\arguments{ +\item{fun}{A function to serve as a palette. For continuous palettes, these +typically take vectors of numeric values between (0, 1) and return a +vector of equal length. For discrete palettes, these typically take a +scalar integer and return a vector of that length.} + +\item{type}{A string giving the type of return values. Some example strings +include \code{"colour"}, \code{"numeric"}, \code{"linetype"} or \code{"shape"}.} + +\item{na_safe}{A boolean indicating whether \code{NA} values are translated to +palette values (\code{TRUE}) or are kept as \code{NA} (\code{FALSE}). Applies to +continuous palettes.} + +\item{nlevels}{An integer giving the number of distinct palette values +that can be returned by the discrete palette.} + +\item{x}{An object to test or coerce.} + +\item{pal}{A palette to retrieve properties from.} +} +\value{ +For \code{new_continuous_palette()}, \code{new_discret_palette()}, \code{as_discrete_pal()} +and \code{as_continuous_pal()}: a function of class \code{pal_continuous} or \code{pal_discrete}. +For \code{is_pal()}, \code{is_continuous_pal()}, \code{is_discret_pal()}, \code{is_colour_pal()}, +or \code{is_numeric_pal()}: a logical value of length 1. +For \code{palette_nlevels()} a single integer. For \code{palette_na_safe()} a boolean. +For \code{palette_type()} a string. +} +\description{ +These constructor functions attach metadata to palette functions. This +metadata can be used in testing or coercion. +} +\examples{ +new_discrete_palette( + fun = grDevices::terrain.colors, + type = "colour", nlevels = 255 +) + +new_continuous_palette( + fun = function(x) rescale(x, to = c(1, 0)), + type = "numeric", na_safe = FALSE +) +} diff --git a/man/pal_manual.Rd b/man/pal_manual.Rd index 394abff2..a2ec082c 100644 --- a/man/pal_manual.Rd +++ b/man/pal_manual.Rd @@ -5,12 +5,15 @@ \alias{manual_pal} \title{Manual palette (discrete)} \usage{ -pal_manual(values) +pal_manual(values, type = NULL) -manual_pal(values) +manual_pal(values, type = NULL) } \arguments{ \item{values}{vector of values to be used as a palette.} + +\item{type}{A string giving the type of return values. Some example strings +include \code{"colour"}, \code{"numeric"}, \code{"linetype"} or \code{"shape"}.} } \description{ Manual palette (discrete)