From eb250b25b87d2ac9fed5b33cd4a018f22b6926df Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 19 Jun 2024 10:10:15 +0200 Subject: [PATCH 1/3] choose `na.value` when unmatched --- R/scale-.R | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/R/scale-.R b/R/scale-.R index 9eaa153590..4f0de50e34 100644 --- a/R/scale-.R +++ b/R/scale-.R @@ -969,23 +969,23 @@ ScaleDiscrete <- ggproto("ScaleDiscrete", Scale, self$n.breaks.cache <- n } - if (!is_null(names(pal))) { + na_value <- if (self$na.translate) self$na.value else NA + pal_names <- names(pal) + + if (!is_null(pal_names)) { # if pal is named, limit the pal by the names first, # then limit the values by the pal - idx_nomatch <- is.na(match(names(pal), limits)) - pal[idx_nomatch] <- NA - pal_match <- pal[match(as.character(x), names(pal))] - pal_match <- unname(pal_match) - } else { - # if pal is not named, limit the values directly - pal_match <- pal[match(as.character(x), limits)] + pal[is.na(match(pal_names, limits))] <- na_value + pal <- unname(pal) + limits <- pal_names } + pal <- c(pal, na_value) + pal_match <- pal[match(as.character(x), limits, nomatch = length(pal))] - if (self$na.translate) { - ifelse(is.na(x) | is.na(pal_match), self$na.value, pal_match) - } else { - pal_match + if (!is.na(na_value)) { + pal_match[is.na(x)] <- na_value } + pal_match }, rescale = function(self, x, limits = self$get_limits(), range = c(1, length(limits))) { From 0ac57ffbbee6fb0a94552d518543bca255315552 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 19 Jun 2024 10:10:21 +0200 Subject: [PATCH 2/3] add test --- tests/testthat/test-scale-manual.R | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/testthat/test-scale-manual.R b/tests/testthat/test-scale-manual.R index 4e45b65557..3d87268c41 100644 --- a/tests/testthat/test-scale-manual.R +++ b/tests/testthat/test-scale-manual.R @@ -152,3 +152,27 @@ test_that("limits and breaks (#4619)", { expect_equal(s3$map(c("4", "6", "8")), c("a", "b", "c")) expect_equal(s3$break_positions(), c("a", "c")) }) + +test_that("NAs from palette are not translated (#5929)", { + + s1 <- scale_colour_manual( + values = c("4" = "a", "6" = NA, "8" = "c"), + na.translate = TRUE, na.value = "x" + ) + s1$train(c("8", "6", "4")) + expect_equal(s1$map(c("4", "6", "8", "10")), c("a", NA, "c", "x")) + + s2 <- scale_colour_manual( + values = c("4" = "a", "6" = NA, "8" = "c"), + na.translate = TRUE, na.value = NA + ) + s2$train(c("8", "6", "4")) + expect_equal(s2$map(c("4", "6", "8", "10")), c("a", NA, "c", NA)) + + s3 <- scale_colour_manual( + values = c("4" = "a", "6" = NA, "8" = "c"), + na.translate = FALSE, na.value = "x" + ) + s3$train(c("8", "6", "4")) + expect_equal(s3$map(c("4", "6", "8", "10")), c("a", NA, "c", NA)) +}) From 69fc64a50032b52fec5fb0b8041fe9a335363e0d Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 19 Jun 2024 10:12:27 +0200 Subject: [PATCH 3/3] add news bullet --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 67c07b0b05..aeb06cf73b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* Missing values from discrete palettes are no longer translated + (@teunbrand, #5929). * `geom_rug()` prints a warning when `na.rm = FALSE`, as per documentation (@pn317, #5905) * `position_dodge(preserve = "single")` now handles multi-row geoms better, such as `geom_violin()` (@teunbrand based on @clauswilke's work, #2801).