From 38cc44b520fd909630a3aee8eff3a5ab867e322c Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 7 May 2021 10:53:54 +0200 Subject: [PATCH 1/7] allow fewer elements in named values vector --- NEWS.md | 4 ++++ R/scale-manual.r | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 5820554735..0549b9f5da 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # ggplot2 (development version) +* Manual scales now allow named vectors passed to `values` to contain fewer + elements than existing in the data. Elements not present in values will be set + to `NA` (@thomasp85, #3451) + * Add support for the BrailleR package for creating descriptions of the plot when rendered (@thomasp85, #4459) diff --git a/R/scale-manual.r b/R/scale-manual.r index ffd3fcda2a..2390c6ee71 100644 --- a/R/scale-manual.r +++ b/R/scale-manual.r @@ -141,7 +141,7 @@ manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ...) { } pal <- function(n) { - if (n > length(values)) { + if (is.null(names(values)) && n > length(values)) { abort(glue("Insufficient values in manual scale. {n} needed but only {length(values)} provided.")) } values From 3ad3dce3598be4bfc4c0afe4629e97aaa14bf46f Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 7 May 2021 14:41:22 +0200 Subject: [PATCH 2/7] new implementation --- R/scale-manual.r | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/R/scale-manual.r b/R/scale-manual.r index 2390c6ee71..7f9c2f7853 100644 --- a/R/scale-manual.r +++ b/R/scale-manual.r @@ -121,7 +121,7 @@ scale_discrete_manual <- function(aesthetics, ..., values, breaks = waiver()) { } -manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ...) { +manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), limits = NULL, ...) { # check for missing `values` parameter, in lieu of providing # a default to all the different scale_*_manual() functions if (is_missing(values)) { @@ -130,6 +130,10 @@ manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ...) { force(values) } + if (is.null(limits)) { + limits <- names(values) + } + # order values according to breaks if (is.vector(values) && is.null(names(values)) && !is.waive(breaks) && !is.null(breaks) && !is.function(breaks)) { @@ -141,7 +145,7 @@ manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ...) { } pal <- function(n) { - if (is.null(names(values)) && n > length(values)) { + if (n > length(values)) { abort(glue("Insufficient values in manual scale. {n} needed but only {length(values)} provided.")) } values From 5daf327d44655e91ea81a09aa67d559518e7ecd9 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 7 May 2021 15:57:54 +0200 Subject: [PATCH 3/7] fixing --- R/scale-manual.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/scale-manual.r b/R/scale-manual.r index 7f9c2f7853..4d94077281 100644 --- a/R/scale-manual.r +++ b/R/scale-manual.r @@ -150,5 +150,5 @@ manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), limits = N } values } - discrete_scale(aesthetic, "manual", pal, breaks = breaks, ...) + discrete_scale(aesthetic, "manual", pal, breaks = breaks, limits = limits, ...) } From feac44c47e789dc3bd2df6546ccebf53bd480bf4 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 10 May 2021 09:21:17 +0200 Subject: [PATCH 4/7] Add na.value defaults --- R/scale-manual.r | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/R/scale-manual.r b/R/scale-manual.r index 4d94077281..d7cb4b7e8c 100644 --- a/R/scale-manual.r +++ b/R/scale-manual.r @@ -80,38 +80,38 @@ NULL #' @rdname scale_manual #' @export -scale_colour_manual <- function(..., values, aesthetics = "colour", breaks = waiver()) { - manual_scale(aesthetics, values, breaks, ...) +scale_colour_manual <- function(..., values, aesthetics = "colour", breaks = waiver(), na.value = "grey50") { + manual_scale(aesthetics, values, breaks, ..., na.value = na.value) } #' @rdname scale_manual #' @export -scale_fill_manual <- function(..., values, aesthetics = "fill", breaks = waiver()) { - manual_scale(aesthetics, values, breaks, ...) +scale_fill_manual <- function(..., values, aesthetics = "fill", breaks = waiver(), na.value = "grey50") { + manual_scale(aesthetics, values, breaks, ..., na.value = na.value) } #' @rdname scale_manual #' @export -scale_size_manual <- function(..., values, breaks = waiver()) { - manual_scale("size", values, breaks, ...) +scale_size_manual <- function(..., values, breaks = waiver(), na.value = NA) { + manual_scale("size", values, breaks, ..., na.value = na.value) } #' @rdname scale_manual #' @export -scale_shape_manual <- function(..., values, breaks = waiver()) { - manual_scale("shape", values, breaks, ...) +scale_shape_manual <- function(..., values, breaks = waiver(), na.value = NA) { + manual_scale("shape", values, breaks, ..., na.value = na.value) } #' @rdname scale_manual #' @export -scale_linetype_manual <- function(..., values, breaks = waiver()) { - manual_scale("linetype", values, breaks, ...) +scale_linetype_manual <- function(..., values, breaks = waiver(), na.value = "blank") { + manual_scale("linetype", values, breaks, ..., na.value = na.value) } #' @rdname scale_manual #' @export -scale_alpha_manual <- function(..., values, breaks = waiver()) { - manual_scale("alpha", values, breaks, ...) +scale_alpha_manual <- function(..., values, breaks = waiver(), na.value = NA) { + manual_scale("alpha", values, breaks, ..., na.value = na.value) } #' @rdname scale_manual From 9207e8883d0b5b1c15a71af66eab08787c3deb8f Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 10 May 2021 09:50:43 +0200 Subject: [PATCH 5/7] fix test --- tests/testthat/test-scale-manual.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-scale-manual.r b/tests/testthat/test-scale-manual.r index fecce1de20..b8af871e99 100644 --- a/tests/testthat/test-scale-manual.r +++ b/tests/testthat/test-scale-manual.r @@ -88,12 +88,12 @@ test_that("unnamed values match breaks in manual scales", { test_that("limits works (#3262)", { # named charachter vector - s1 <- scale_colour_manual(values = c("8" = "c", "4" = "a", "6" = "b"), limits = c("4", "8")) + s1 <- scale_colour_manual(values = c("8" = "c", "4" = "a", "6" = "b"), limits = c("4", "8"), na.value = NA) s1$train(c("4", "6", "8")) expect_equal(s1$map(c("4", "6", "8")), c("a", NA, "c")) # named charachter vector - s2 <- scale_colour_manual(values = c("c", "a", "b"), limits = c("4", "8")) + s2 <- scale_colour_manual(values = c("c", "a", "b"), limits = c("4", "8"), na.value = NA) s2$train(c("4", "6", "8")) expect_equal(s2$map(c("4", "6", "8")), c("c", NA, "a")) }) From 7dd8e59a1eff75d2dea7e8d8d84d2b0c538fa702 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 10 May 2021 10:06:15 +0200 Subject: [PATCH 6/7] update docs --- man/scale_manual.Rd | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/man/scale_manual.Rd b/man/scale_manual.Rd index ad9a742df3..31287ec383 100644 --- a/man/scale_manual.Rd +++ b/man/scale_manual.Rd @@ -11,17 +11,29 @@ \alias{scale_color_manual} \title{Create your own discrete scale} \usage{ -scale_colour_manual(..., values, aesthetics = "colour", breaks = waiver()) +scale_colour_manual( + ..., + values, + aesthetics = "colour", + breaks = waiver(), + na.value = "grey50" +) -scale_fill_manual(..., values, aesthetics = "fill", breaks = waiver()) +scale_fill_manual( + ..., + values, + aesthetics = "fill", + breaks = waiver(), + na.value = "grey50" +) -scale_size_manual(..., values, breaks = waiver()) +scale_size_manual(..., values, breaks = waiver(), na.value = NA) -scale_shape_manual(..., values, breaks = waiver()) +scale_shape_manual(..., values, breaks = waiver(), na.value = NA) -scale_linetype_manual(..., values, breaks = waiver()) +scale_linetype_manual(..., values, breaks = waiver(), na.value = "blank") -scale_alpha_manual(..., values, breaks = waiver()) +scale_alpha_manual(..., values, breaks = waiver(), na.value = NA) scale_discrete_manual(aesthetics, ..., values, breaks = waiver()) } From 9fd9fdf0dc2e0ab02067f7ebda4c01e57a9bc812 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 10 May 2021 10:33:57 +0200 Subject: [PATCH 7/7] Add missing param --- R/scale-manual.r | 2 ++ man/scale_manual.Rd | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/scale-manual.r b/R/scale-manual.r index d7cb4b7e8c..63e2839371 100644 --- a/R/scale-manual.r +++ b/R/scale-manual.r @@ -28,6 +28,8 @@ #' - A character vector of breaks #' - A function that takes the limits as input and returns breaks #' as output +#' @param na.value The aesthetic value to use for missing (`NA`) values +#' #' @section Color Blindness: #' Many color palettes derived from RGB combinations (like the "rainbow" color #' palette) are not suitable to support all viewers, especially those with diff --git a/man/scale_manual.Rd b/man/scale_manual.Rd index 31287ec383..b4386bbc58 100644 --- a/man/scale_manual.Rd +++ b/man/scale_manual.Rd @@ -59,9 +59,6 @@ The default, \code{TRUE}, uses the levels that appear in the data; \item{\code{na.translate}}{Unlike continuous scales, discrete scales can easily show missing values, and do so by default. If you want to remove missing values from a discrete scale, specify \code{na.translate = FALSE}.} - \item{\code{na.value}}{If \code{na.translate = TRUE}, what aesthetic value should the -missing values be displayed as? Does not apply to position scales -where \code{NA} is always placed at the far right.} \item{\code{scale_name}}{The name of the scale that should be used for error messages associated with this scale.} \item{\code{name}}{The name of the scale. Used as the axis or legend title. If @@ -102,6 +99,8 @@ same time, via \code{aesthetics = c("colour", "fill")}.} \item A function that takes the limits as input and returns breaks as output }} + +\item{na.value}{The aesthetic value to use for missing (\code{NA}) values} } \description{ These functions allow you to specify your own set of mappings from levels in the