#' Color Palette
#'
#' Provides qualitative, diverging and sequential color schemes.
#' @param palette A [`character`] string giving the name of the palette to be
#' used (see below).
#' @param reverse A [`logical`] scalar: should the resulting vector of colors
#' should be reversed?
#' @param names A [`logical`] scalar: should the names of the colors should be
#' kept in the resulting vector?
#' @param lang A [`character`] string specifying the language for the color
#' names. It must be one of "`en`" (English, the default) or "`fr`" (French).
#' @param force A [`logical`] scalar. If `TRUE`, forces the color scheme to be
#' interpolated. It should not be used routinely with qualitative color
#' schemes, as they are designed to be used as is to remain color-blind safe.
#' @param ... Further arguments passed to
#' [colorRampPalette][grDevices::colorRamp].
#' @section Paul Tol's Color Schemes:
#' The following palettes are available. The maximum number of supported
#' colors is in brackets, this value is only relevant for the qualitative
#' color schemes (divergent and sequential schemes are linearly interpolated).
#' \describe{
#' \item{Qualitative data}{`bright` (7), `high contrast` (3), `vibrant` (7),
#' `muted` (9), `medium contrast` (6), `pale` (6), `dark` (6), `light` (9).}
#' \item{Diverging data}{`sunset` (11), `nightfall` (17), `BuRd` (9),
#' `PRGn` (9).}
#' \item{Sequential data}{`YlOrBr` (9), `iridescent` (23), `incandescent`
#' (11), `discrete rainbow` (23), `smooth rainbow` (34).}
#' }
#' @section Qualitative Color Schemes:
#' According to Paul Tol's technical note, the `bright`, `highcontrast`,
#' `vibrant` and `muted` color schemes are color-blind safe. The
#' `mediumcontrast` color scheme is designed for situations needing color
#' pairs.
#'
#' The `light` color scheme is reasonably distinct for both normal or
#' colorblind vision and is intended to fill labeled cells.
#'
#' The `pale` and `dark` schemes are not very distinct in either normal or
#' colorblind vision and should be used as a text background or to highlight
#' a cell in a table.
#'
#' Refer to the original document for details about the recommended uses (see
#' references).
#' @section Rainbow Color Scheme:
#' As a general rule, ordered data should not be represented using a rainbow
#' scheme. There are three main arguments against such use (Tol 2018):
#' \itemize{
#' \item{The spectral order of visible light carries no inherent magnitude
#' message.}
#' \item{Some bands of almost constant hue with sharp transitions between
#' them, can be perceived as jumps in the data.}
#' \item{Color-blind people have difficulty distinguishing some colors of
#' the rainbow.}
#' }
#' If such use cannot be avoided, Paul Tol's technical note provides two color
#' schemes that are reasonably clear in color-blind vision. To remain
#' color-blind safe, these two schemes must comply with the following
#' conditions:
#' \describe{
#' \item{`discreterainbow`}{This scheme must not be interpolated.}
#' \item{`smoothrainbow`}{This scheme does not have to be used over the full
#' range.}
#' }
#' @section Okabe and Ito Color Scheme:
#' The following (qualitative) color scheme is available:
#' \describe{
#' \item{`okabeito`}{Up to 8 colors.}
#' \item{`okabeito black`}{Up to 8 colors, with black as the last.}
#' }
#' @section Scientific Color Schemes:
#' The following (qualitative) color schemes are available:
#' \describe{
#' \item{`stratigraphy`}{International Chronostratigraphic Chart (175 colors).}
#' \item{`land`}{AVHRR Global Land Cover Classification (14 colors).}
#' \item{`soil`}{FAO Reference Soil Groups (24 colors).}
#' }
#' @return A palette function with the following attributes, that when called
#' with a single integer argument (the number of levels) returns a (named)
#' vector of colors.
#' \describe{
#' \item{palette}{A [`character`] string giving the name of the
#' color scheme.}
#' \item{type}{A [`character`] string giving the corresponding
#' data type. One of "`qualitative`", "`diverging`" or "`sequential`".}
#' \item{interpolate}{A [`logical`] scalar: can the color palette be
#' interpolated?}
#' \item{missing}{A [`character`] string giving the the hexadecimal
#' representation of the color that should be used for `NA` values.}
#' \item{max}{An [`integer`] giving the maximum number of color values.
#' Only relevant for non-interpolated color schemes.}
#' }
#'
#' For color schemes that can be interpolated (diverging and sequential data),
#' the color range can be limited with an additional argument. `range` allows
#' to remove a fraction of the color domain (before being interpolated; see
#' examples).
#' @references
#' Jones, A., Montanarella, L. & Jones, R. (Ed.) (2005). *Soil atlas of
#' Europe*. Luxembourg: European Commission, Office for Official Publications
#' of the European Communities. 128 pp. ISBN: 92-894-8120-X.
#'
#' Okabe, M. & Ito, K. (2008). *Color Universal Design (CUD): How to Make
#' Figures and Presentations That Are Friendly to Colorblind People*.
#' URL: \url{https://jfly.uni-koeln.de/color/}.
#'
#' Tol, P. (2021). *Colour Schemes*. SRON. Technical Note No.
#' SRON/EPS/TN/09-002, issue 3.2.
#' URL: \url{https://personal.sron.nl/~pault/data/colourschemes.pdf}
#'
#' \href{https://ccgm.org/}{Commission for the Geological Map of the World}
#' @example inst/examples/ex-palettes.R
#' @author N. Frerebeau
#' @family color palettes
#' @keywords color
#' @export
colour <- function(palette, reverse = FALSE, names = TRUE, lang = "en",
force = FALSE, ...) {
## Validation
palette <- gsub(pattern = "[[:blank:]]", replacement = "", x = palette)
palette <- match.arg(palette, names(.schemes), several.ok = FALSE)
lang <- match.arg(lang, c("en", "fr"), several.ok = FALSE)
## Get colors
col_palette <- .schemes[[palette]]
col_colors <- col_palette[["colours"]]
col_names <- col_palette[["names"]][[lang]]
col_type <- col_palette[["type"]]
col_interpolate <- col_palette[["interpolate"]]
col_missing <- col_palette[["missing"]]
col_scheme <- col_palette[["scheme"]]
k <- col_palette[["max"]]
## Reverse color order
if (reverse) col_colors <- rev(col_colors)
if (col_interpolate || force) {
## For color schemes that can be linearly interpolated
fun <- function(n, range = c(0, 1)) {
if (missing(n)) n <- k
# Validate
if (any(range > 1) | any(range < 0))
stop(sQuote("range"), " values must be in [0,1].", call. = FALSE)
# Remove starting colors
col_colors <- utils::tail(col_colors, k * (1 - range[[1]]))
# Remove ending colors
col_colors <- utils::head(col_colors, k * range[[2]])
# Interpolate
col <- grDevices::colorRampPalette(col_colors)(n)
# Set attributes
col <- structure(
col,
missing = col_missing,
class = c("color_scheme", "color_continuous")
)
return(col)
}
} else {
## No interpolation
## FIXME: add 'range = c(0, 1)' to prevent "multiple local function
## definitions" note in R CMD check
fun <- function(n, range = c(0, 1)) {
if (missing(n)) n <- k
# Validate
if (n > k) {
msg <- "%s color scheme supports up to %d values."
stop(sprintf(msg, sQuote(palette), k), call. = FALSE)
}
# Arrange color schemes
if (!is.null(col_scheme)) {
m <- col_scheme[[n]]
if (reverse) {
m <- rev(m)
col_colors <- rev(col_colors)
}
col <- col_colors[m]
} else if (col_type == "qualitative") {
m <- seq_len(n)
col <- col_colors[m]
} else {
m <- seq(from = 1, to = k, length.out = n)
col <- col_colors[m]
}
# Keep names?
if (names) names(col) <- col_names[m] else col <- unname(col)
# Set attributes
col <- structure(
col,
missing = col_missing,
class = c("color_scheme", "color_discrete")
)
return(col)
}
}
## Set attributes
fun <- structure(
fun,
palette = palette,
type = col_type,
missing = col_missing,
interpolate = col_interpolate || force,
max = as.integer(k)
)
return(fun)
}
#' @export
#' @rdname colour
color <- colour
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.