diff --git a/NEWS.md b/NEWS.md index 10d8e7586a..3215794ff5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # ggplot2 (development version) +* Legends in `scale_*_manual()` can show `NA` values again when the `values` is + a named vector (@teunbrand, #5214, #5286). + +* `scale_*_manual()` with a named `values` argument now emits a warning when + none of those names match the values found in the data (@teunbrand, #5298). + * `coord_munch()` can now close polygon shapes (@teunbrand, #3271) * You can now omit either `xend` or `yend` from `geom_segment()` as only one diff --git a/R/scale-manual.R b/R/scale-manual.R index 7bee306d4e..9fd9f832cb 100644 --- a/R/scale-manual.R +++ b/R/scale-manual.R @@ -141,7 +141,8 @@ scale_discrete_manual <- function(aesthetics, ..., values, breaks = waiver()) { manual_scale(aesthetics, values, breaks, ...) } -manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ..., limits = NULL) { +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)) { @@ -152,7 +153,17 @@ manual_scale <- function(aesthetic, values = NULL, breaks = waiver(), ..., limit if (is.null(limits) && !is.null(names(values))) { # Limits as function to access `values` names later on (#4619) - limits <- function(x) intersect(x, names(values)) %||% character() + force(aesthetic) + limits <- function(x) { + x <- intersect(x, c(names(values), NA)) %||% character() + if (length(x) < 1) { + cli::cli_warn(paste0( + "No shared levels found between {.code names(values)} of the manual ", + "scale and the data's {.field {aesthetic}} values." + )) + } + x + } } # order values according to breaks diff --git a/tests/testthat/_snaps/scale-manual.md b/tests/testthat/_snaps/scale-manual.md new file mode 100644 index 0000000000..faf69a7899 --- /dev/null +++ b/tests/testthat/_snaps/scale-manual.md @@ -0,0 +1,4 @@ +# names of values used in manual scales + + No shared levels found between `names(values)` of the manual scale and the data's colour values. + diff --git a/tests/testthat/test-scale-manual.R b/tests/testthat/test-scale-manual.R index 53a1f770fd..532e18b2f6 100644 --- a/tests/testthat/test-scale-manual.R +++ b/tests/testthat/test-scale-manual.R @@ -6,6 +6,19 @@ test_that("names of values used in manual scales", { s2 <- scale_colour_manual(values = c("8" = "c", "4" = "a", "6" = "b"), na.value = NA) s2$train(c("4", "8")) expect_equal(s2$map(c("4", "6", "8")), c("a", NA, "c")) + expect_equal(s2$get_limits(), c("4", "8")) + + s3 <- scale_colour_manual(values = c("8" = "c", "4" = "a", "6" = "b"), na.value = "x") + s3$train(c("4", "8", NA)) + expect_equal(s3$map(c("4", "6", "8")), c("a", "x", "c")) + expect_equal(s3$get_limits(), c("4", "8", NA)) + + # Names do not match data + s <- scale_colour_manual(values = c("foo" = "x", "bar" = "y")) + s$train(c("A", "B")) + expect_snapshot_warning( + expect_equal(s$get_limits(), character()) + ) })