From 77fc5c705efd19c96f6b69f078a0aeacc87c933d Mon Sep 17 00:00:00 2001 From: Kara Woo Date: Thu, 13 Jul 2017 14:41:15 -0700 Subject: [PATCH] Add built-in support for viridis color scales (#2178) * Begin viridis scales * Add to NEWS.md * Add documentation for continuous_scale parameters na.value and guide * Remove @description * tidyverse style for long calls to discrete_scale/continuous_scale oops * Use markdown url syntax * viridis_pal is now in the scales package * Shorten names to viridis_c and viridis_d * Add viridis examples based on the brewer examples * Add viridis tests * Update viridis tests * Use global options to control default continuous colour/fill scales * Don't set options in .onLoad() * Put closing paren on new line * Update NEWS.md --- DESCRIPTION | 5 +- NAMESPACE | 6 +++ NEWS.md | 9 ++++ R/scale-colour.r | 46 ++++++++++++++++++ R/scale-viridis.r | 105 +++++++++++++++++++++++++++++++++++++++++ R/zxx.r | 21 ++++----- man/scale_alpha.Rd | 3 +- man/scale_brewer.Rd | 3 +- man/scale_colour_continuous.Rd | 41 ++++++++++++++++ man/scale_gradient.Rd | 5 +- man/scale_grey.Rd | 3 +- man/scale_hue.Rd | 3 +- man/scale_viridis.Rd | 99 ++++++++++++++++++++++++++++++++++++++ tests/testthat/test-viridis.R | 12 +++++ 14 files changed, 342 insertions(+), 19 deletions(-) create mode 100644 R/scale-colour.r create mode 100644 R/scale-viridis.r create mode 100644 man/scale_colour_continuous.Rd create mode 100644 man/scale_viridis.Rd create mode 100644 tests/testthat/test-viridis.R diff --git a/DESCRIPTION b/DESCRIPTION index 7c56ca5df..3c8ed117e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,7 +43,8 @@ Suggests: rpart, rmarkdown, sf (>= 0.3-4), - svglite (>= 1.2.0.9001) + svglite (>= 1.2.0.9001), + viridisLite Remotes: hadley/scales, hadley/svglite @@ -169,6 +170,7 @@ Collate: 'scale-.r' 'scale-alpha.r' 'scale-brewer.r' + 'scale-colour.r' 'scale-continuous.r' 'scale-date.r' 'scale-discrete-.r' @@ -181,6 +183,7 @@ Collate: 'scale-shape.r' 'scale-size.r' 'scale-type.R' + 'scale-viridis.r' 'scales-.r' 'sf.R' 'stat-bin.r' diff --git a/NAMESPACE b/NAMESPACE index 9b9a7b2ed..908d67d1d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -385,6 +385,8 @@ export(scale_color_grey) export(scale_color_hue) export(scale_color_identity) export(scale_color_manual) +export(scale_color_viridis_c) +export(scale_color_viridis_d) export(scale_colour_brewer) export(scale_colour_continuous) export(scale_colour_date) @@ -398,6 +400,8 @@ export(scale_colour_grey) export(scale_colour_hue) export(scale_colour_identity) export(scale_colour_manual) +export(scale_colour_viridis_c) +export(scale_colour_viridis_d) export(scale_fill_brewer) export(scale_fill_continuous) export(scale_fill_date) @@ -411,6 +415,8 @@ export(scale_fill_grey) export(scale_fill_hue) export(scale_fill_identity) export(scale_fill_manual) +export(scale_fill_viridis_c) +export(scale_fill_viridis_d) export(scale_linetype) export(scale_linetype_continuous) export(scale_linetype_discrete) diff --git a/NEWS.md b/NEWS.md index fbfe0b9fe..aba915e5d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,14 @@ # ggplot2 2.2.1.9000 +* Default colour maps for continuous data are controlled by global options + `ggplot2.continuous.colour` and `ggplot2.continuous.fill`, which can be set to + either `"gradient"` or `"viridis"` (@karawoo). + +* Adds built-in support for `viridis` and related colour maps. Use the functions + `scale_colour_viridis_c()`/`scale_fill_viridis_c()` for continuous data and + `scale_colour_viridis_d()`/`scale_fill_viridis_d()` for discrete data + (@karawoo, #1526). + * Updated datetime scales for `alpha`, `size`, `colour`, and `fill` can take `date_breaks` and `date_labels` arguments (@karawoo, #1526). diff --git a/R/scale-colour.r b/R/scale-colour.r new file mode 100644 index 000000000..d3fd46033 --- /dev/null +++ b/R/scale-colour.r @@ -0,0 +1,46 @@ +#' Continuous colour scales +#' +#' Colour scales for continuous data default to the values of the +#' `ggplot2.continuous.colour` and `ggplot2.continuous.fill` options. If these +#' options are not present, `"gradient"` will be used. See [options()] for more +#' information. +#' +#' @param ... Additional parameters passed on to the scale type +#' @param type One of "gradient" (the default) or "viridis" indicating the +#' colour scale to use +#' @seealso [scale_colour_gradient()], [scale_colour_viridis_c()], +#' [scale_fill_gradient()], and [scale_fill_viridis_c()] +#' @export +#' @rdname scale_colour_continuous +#' @examples +#' v <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + +#' geom_tile() +#' v +#' +#' v + scale_fill_continuous(type = "gradient") +#' v + scale_fill_continuous(type = "viridis") +#' +#' # The above are equivalent to +#' v + scale_fill_gradient() +#' v + scale_fill_viridis_c() +scale_colour_continuous <- function(..., + type = getOption("ggplot2.continuous.colour", default = "gradient")) { + switch( + type, + gradient = scale_colour_gradient(...), + viridis = scale_colour_viridis_c(...), + stop("Unknown scale type", call. = FALSE) + ) +} + +#' @rdname scale_colour_continuous +#' @export +scale_fill_continuous <- function(..., + type = getOption("ggplot2.continuous.fill", default = "gradient")) { + switch( + type, + gradient = scale_fill_gradient(...), + viridis = scale_fill_viridis_c(...), + stop("Unknown scale type", call. = FALSE) + ) +} diff --git a/R/scale-viridis.r b/R/scale-viridis.r new file mode 100644 index 000000000..0b99b27dc --- /dev/null +++ b/R/scale-viridis.r @@ -0,0 +1,105 @@ +#' Viridis colour scales from viridisLite +#' +#' The `viridis` scales provide color maps that are perceptually uniform in both +#' color and black-and-white. They are also designed to be perceived by viewers +#' with common forms of color blindness. See also +#' . +#' +#' @inheritParams viridisLite::viridis +#' @inheritParams scales::gradient_n_pal +#' @inheritParams continuous_scale +#' @param ... Other arguments passed on to [discrete_scale()] or +#' [continuous_scale()] to control name, limits, breaks, labels and so forth. +#' @family colour scales +#' @rdname scale_viridis +#' @export +#' @examples +#' dsamp <- diamonds[sample(nrow(diamonds), 1000), ] +#' (d <- ggplot(dsamp, aes(carat, price)) + +#' geom_point(aes(colour = clarity))) +#' d + scale_colour_viridis_d() +#' +#' # Change scale label +#' d + scale_colour_viridis_d("Diamond\nclarity") +#' +#' # Select palette to use, see ?scales::viridis_pal for more details +#' d + scale_colour_viridis_d(option = "plasma") +#' d + scale_colour_viridis_d(option = "inferno") +#' +#' \donttest{ +#' # scale_fill_viridis_d works just the same as +#' # scale_colour_viridis_d but for fill colours +#' p <- ggplot(diamonds, aes(x = price, fill = cut)) + +#' geom_histogram(position = "dodge", binwidth = 1000) +#' p + scale_fill_viridis_d() +#' # the order of colour can be reversed +#' p + scale_fill_viridis_d(direction = -1) +#' } +#' +#' # Use viridis_c with continous data +#' v <- ggplot(faithfuld) + +#' geom_tile(aes(waiting, eruptions, fill = density)) +#' v +#' v + scale_fill_viridis_c() +#' v + scale_fill_viridis_c(option = "plasma") +scale_colour_viridis_d <- function(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D") { + discrete_scale( + "colour", + "viridis_d", + viridis_pal(alpha, begin, end, direction, option), + ... + ) +} + +#' @export +#' @rdname scale_viridis +scale_fill_viridis_d <- function(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D") { + discrete_scale( + "fill", + "viridis_d", + viridis_pal(alpha, begin, end, direction, option), + ... + ) +} + +#' @export +#' @rdname scale_viridis +scale_colour_viridis_c <- function(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D", values = NULL, + space = "Lab", na.value = "grey50", + guide = "colourbar") { + continuous_scale( + "colour", + "viridis_c", + gradient_n_pal( + viridis_pal(alpha, begin, end, direction, option)(6), + values, + space + ), + na.value = na.value, + guide = guide, + ... + ) +} + +#' @export +#' @rdname scale_viridis +scale_fill_viridis_c <- function(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D", values = NULL, + space = "Lab", na.value = "grey50", + guide = "colourbar") { + continuous_scale( + "fill", + "viridis_c", + gradient_n_pal( + viridis_pal(alpha, begin, end, direction, option)(6), + values, + space + ), + na.value = na.value, + guide = guide, + ... + ) +} diff --git a/R/zxx.r b/R/zxx.r index 42ac96eb3..1728dbd0d 100644 --- a/R/zxx.r +++ b/R/zxx.r @@ -8,11 +8,6 @@ scale_colour_discrete <- scale_colour_hue #' @export #' @rdname scale_gradient #' @usage NULL -scale_colour_continuous <- scale_colour_gradient - -#' @export -#' @rdname scale_gradient -#' @usage NULL scale_colour_datetime <- function(..., low = "#132B43", high = "#56B1F7", @@ -56,11 +51,6 @@ scale_fill_discrete <- scale_fill_hue #' @export #' @rdname scale_gradient #' @usage NULL -scale_fill_continuous <- scale_fill_gradient - -#' @export -#' @rdname scale_gradient -#' @usage NULL scale_fill_datetime <- function(..., low = "#132B43", high = "#56B1F7", @@ -75,7 +65,6 @@ scale_fill_datetime <- function(..., guide = guide, ... ) - } #' @export @@ -154,3 +143,13 @@ scale_color_identity <- scale_colour_identity #' @rdname scale_manual #' @usage NULL scale_color_manual <- scale_colour_manual + +#' @export +#' @rdname scale_viridis +#' @usage NULL +scale_color_viridis_d <- scale_colour_viridis_d + +#' @export +#' @rdname scale_viridis +#' @usage NULL +scale_color_viridis_c <- scale_colour_viridis_c diff --git a/man/scale_alpha.Rd b/man/scale_alpha.Rd index 374e625a2..ae94242ce 100644 --- a/man/scale_alpha.Rd +++ b/man/scale_alpha.Rd @@ -39,5 +39,6 @@ p + scale_alpha(range = c(0.4, 0.8)) Other colour scales: \code{\link{scale_colour_brewer}}, \code{\link{scale_colour_gradient}}, \code{\link{scale_colour_grey}}, - \code{\link{scale_colour_hue}} + \code{\link{scale_colour_hue}}, + \code{\link{scale_colour_viridis_d}} } diff --git a/man/scale_brewer.Rd b/man/scale_brewer.Rd index d959311a2..eca7aca15 100644 --- a/man/scale_brewer.Rd +++ b/man/scale_brewer.Rd @@ -110,5 +110,6 @@ v + scale_fill_distiller(palette = "Spectral") Other colour scales: \code{\link{scale_alpha}}, \code{\link{scale_colour_gradient}}, \code{\link{scale_colour_grey}}, - \code{\link{scale_colour_hue}} + \code{\link{scale_colour_hue}}, + \code{\link{scale_colour_viridis_d}} } diff --git a/man/scale_colour_continuous.Rd b/man/scale_colour_continuous.Rd new file mode 100644 index 000000000..d7590ec55 --- /dev/null +++ b/man/scale_colour_continuous.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/scale-colour.r +\name{scale_colour_continuous} +\alias{scale_colour_continuous} +\alias{scale_fill_continuous} +\title{Continuous colour scales} +\usage{ +scale_colour_continuous(..., type = getOption("ggplot2.continuous.colour", + default = "gradient")) + +scale_fill_continuous(..., type = getOption("ggplot2.continuous.fill", default + = "gradient")) +} +\arguments{ +\item{...}{Additional parameters passed on to the scale type} + +\item{type}{One of "gradient" (the default) or "viridis" indicating the +colour scale to use} +} +\description{ +Colour scales for continuous data default to the values of the +\code{ggplot2.continuous.colour} and \code{ggplot2.continuous.fill} options. If these +options are not present, \code{"gradient"} will be used. See \code{\link[=options]{options()}} for more +information. +} +\examples{ +v <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + +geom_tile() +v + +v + scale_fill_continuous(type = "gradient") +v + scale_fill_continuous(type = "viridis") + +# The above are equivalent to +v + scale_fill_gradient() +v + scale_fill_viridis_c() +} +\seealso{ +\code{\link[=scale_colour_gradient]{scale_colour_gradient()}}, \code{\link[=scale_colour_viridis_c]{scale_colour_viridis_c()}}, +\code{\link[=scale_fill_gradient]{scale_fill_gradient()}}, and \code{\link[=scale_fill_viridis_c]{scale_fill_viridis_c()}} +} diff --git a/man/scale_gradient.Rd b/man/scale_gradient.Rd index d02171229..4cbdeaf46 100644 --- a/man/scale_gradient.Rd +++ b/man/scale_gradient.Rd @@ -7,10 +7,8 @@ \alias{scale_fill_gradient2} \alias{scale_colour_gradientn} \alias{scale_fill_gradientn} -\alias{scale_colour_continuous} \alias{scale_colour_datetime} \alias{scale_colour_date} -\alias{scale_fill_continuous} \alias{scale_fill_datetime} \alias{scale_fill_date} \alias{scale_color_continuous} @@ -179,5 +177,6 @@ palette Other colour scales: \code{\link{scale_alpha}}, \code{\link{scale_colour_brewer}}, \code{\link{scale_colour_grey}}, - \code{\link{scale_colour_hue}} + \code{\link{scale_colour_hue}}, + \code{\link{scale_colour_viridis_d}} } diff --git a/man/scale_grey.Rd b/man/scale_grey.Rd index e79265fbb..c848ba971 100644 --- a/man/scale_grey.Rd +++ b/man/scale_grey.Rd @@ -94,5 +94,6 @@ ggplot(mtcars, aes(mpg, wt)) + Other colour scales: \code{\link{scale_alpha}}, \code{\link{scale_colour_brewer}}, \code{\link{scale_colour_gradient}}, - \code{\link{scale_colour_hue}} + \code{\link{scale_colour_hue}}, + \code{\link{scale_colour_viridis_d}} } diff --git a/man/scale_hue.Rd b/man/scale_hue.Rd index ee59f7f48..d303b23e6 100644 --- a/man/scale_hue.Rd +++ b/man/scale_hue.Rd @@ -128,5 +128,6 @@ ggplot(mtcars, aes(mpg, wt)) + Other colour scales: \code{\link{scale_alpha}}, \code{\link{scale_colour_brewer}}, \code{\link{scale_colour_gradient}}, - \code{\link{scale_colour_grey}} + \code{\link{scale_colour_grey}}, + \code{\link{scale_colour_viridis_d}} } diff --git a/man/scale_viridis.Rd b/man/scale_viridis.Rd new file mode 100644 index 000000000..490715496 --- /dev/null +++ b/man/scale_viridis.Rd @@ -0,0 +1,99 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/scale-viridis.r, R/zxx.r +\name{scale_colour_viridis_d} +\alias{scale_colour_viridis_d} +\alias{scale_fill_viridis_d} +\alias{scale_colour_viridis_c} +\alias{scale_fill_viridis_c} +\alias{scale_color_viridis_d} +\alias{scale_color_viridis_c} +\title{Viridis colour scales from viridisLite} +\usage{ +scale_colour_viridis_d(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D") + +scale_fill_viridis_d(..., alpha = 1, begin = 0, end = 1, direction = 1, + option = "D") + +scale_colour_viridis_c(..., alpha = 1, begin = 0, end = 1, + direction = 1, option = "D", values = NULL, space = "Lab", + na.value = "grey50", guide = "colourbar") + +scale_fill_viridis_c(..., alpha = 1, begin = 0, end = 1, direction = 1, + option = "D", values = NULL, space = "Lab", na.value = "grey50", + guide = "colourbar") +} +\arguments{ +\item{...}{Other arguments passed on to \code{\link[=discrete_scale]{discrete_scale()}} or +\code{\link[=continuous_scale]{continuous_scale()}} to control name, limits, breaks, labels and so forth.} + +\item{alpha}{The alpha transparency, a number in [0,1], see argument alpha in +\code{\link[grDevices]{hsv}}.} + +\item{begin}{The (corrected) hue in [0,1] at which the viridis colormap begins.} + +\item{end}{The (corrected) hue in [0,1] at which the viridis colormap ends.} + +\item{direction}{Sets the order of colors in the scale. If 1, the default, colors +are ordered from darkest to lightest. If -1, the order of colors is reversed.} + +\item{option}{A character string indicating the colormap option to use. Four +options are available: "magma" (or "A"), "inferno" (or "B"), "plasma" (or "C"), +and "viridis" (or "D", the default option).} + +\item{values}{if colours should not be evenly positioned along the gradient +this vector gives the position (between 0 and 1) for each colour in the +\code{colours} vector. See \code{\link{rescale}} for a convience function +to map an arbitrary range to between 0 and 1.} + +\item{space}{colour space in which to calculate gradient. Must be "Lab" - +other values are deprecated.} + +\item{na.value}{Missing values will be replaced with this value.} + +\item{guide}{A function used to create a guide or its name. See +\code{\link[=guides]{guides()}} for more info.} +} +\description{ +The \code{viridis} scales provide color maps that are perceptually uniform in both +color and black-and-white. They are also designed to be perceived by viewers +with common forms of color blindness. See also +\url{https://bids.github.io/colormap/}. +} +\examples{ +dsamp <- diamonds[sample(nrow(diamonds), 1000), ] +(d <- ggplot(dsamp, aes(carat, price)) + + geom_point(aes(colour = clarity))) +d + scale_colour_viridis_d() + +# Change scale label +d + scale_colour_viridis_d("Diamond\\nclarity") + +# Select palette to use, see ?scales::viridis_pal for more details +d + scale_colour_viridis_d(option = "plasma") +d + scale_colour_viridis_d(option = "inferno") + +\donttest{ +# scale_fill_viridis_d works just the same as +# scale_colour_viridis_d but for fill colours +p <- ggplot(diamonds, aes(x = price, fill = cut)) + + geom_histogram(position = "dodge", binwidth = 1000) +p + scale_fill_viridis_d() +# the order of colour can be reversed +p + scale_fill_viridis_d(direction = -1) +} + +# Use viridis_c with continous data +v <- ggplot(faithfuld) + + geom_tile(aes(waiting, eruptions, fill = density)) +v +v + scale_fill_viridis_c() +v + scale_fill_viridis_c(option = "plasma") +} +\seealso{ +Other colour scales: \code{\link{scale_alpha}}, + \code{\link{scale_colour_brewer}}, + \code{\link{scale_colour_gradient}}, + \code{\link{scale_colour_grey}}, + \code{\link{scale_colour_hue}} +} diff --git a/tests/testthat/test-viridis.R b/tests/testthat/test-viridis.R new file mode 100644 index 000000000..d1531c1e4 --- /dev/null +++ b/tests/testthat/test-viridis.R @@ -0,0 +1,12 @@ +context("Viridis") + +df <- data.frame(x = 1, y = 1, z = "a") + +test_that("Viridis scale changes point color", { + p1 <- ggplot(df, aes(x, y, colour = z)) + + geom_point() + p2 <- p1 + scale_colour_viridis_d() + + expect_false(layer_data(p1)$colour == layer_data(p2)$colour) + expect_equal(layer_data(p2)$colour, "#440154FF") +})