Skip to content

Add value matching to breaks in manual_scale #3579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@

* Increase the default `nbin` of `guide_colourbar()` to place the ticks more precisely (#3508, @yutannihilation).

* Modified `manual_scale` to match `values` with the order of `breaks` whenever
`values` is an unnamed vector. Previously, unnamed `values` would be matched
to the limits of the scale and ignore the order of any `breaks` provided. Note
that this may change the appearance of plots that previously relied on the
unordered behaviour. (#2429, @idno0001)

# ggplot2 3.2.1

This is a patch release fixing a few regressions introduced in 3.2.0 as well as
Expand Down
22 changes: 17 additions & 5 deletions R/scale-manual.r
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
#' name(s) of the aesthetic(s) that this scale works with. This can be useful, for
#' example, to apply colour settings to the `colour` and `fill` aesthetics at the
#' same time, via `aesthetics = c("colour", "fill")`.
#' @param values a set of aesthetic values to map data values to. If this
#' is a named vector, then the values will be matched based on the names.
#' If unnamed, values will be matched in order (usually alphabetical) with
#' the limits of the scale. Any data values that don't match will be
#' given `na.value`.
#' @param values a set of aesthetic values to map data values to. The values
#' will be matched in order (usually alphabetical) with the limits of the
#' scale, or with `breaks` if provided. If this is a named vector, then the
#' values will be matched based on the names instead. Data values that don't
#' match will be given `na.value`.
#' @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
Expand Down Expand Up @@ -124,6 +124,18 @@ manual_scale <- function(aesthetic, values = NULL, ...) {
force(values)
}

# order values according to breaks
args <- list(...)
if (is.vector(values) && is.null(names(values))
&& "breaks" %in% names(args)) {
if (length(args[["breaks"]]) != length(values)) {
stop("Differing number of values and breaks in manual scale. ",
length(values), " values provided compared to ",
length(args[["breaks"]]), " breaks.", call. = FALSE)
}
names(values) <- args[["breaks"]]
}

pal <- function(n) {
if (n > length(values)) {
stop("Insufficient values in manual scale. ", n, " needed but only ",
Expand Down
10 changes: 5 additions & 5 deletions man/scale_manual.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions tests/testthat/test-scale-manual.r
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,17 @@ test_that("generic scale can be used in place of aesthetic-specific scales", {

expect_equal(layer_data(p1), layer_data(p2))
})

test_that("named values do not match with breaks in manual scales", {
s <- scale_fill_manual(values = c("data_red" = "red", "data_black" = "black"),
breaks = c("data_black", "data_red"))
s$train(c("data_black", "data_red"))
expect_equal(s$map(c("data_red", "data_black")), c("red", "black"))
})

test_that("unnamed values match breaks in manual scales", {
s <- scale_fill_manual(values = c("red", "black"),
breaks = c("data_red", "data_black"))
s$train(c("data_red", "data_black"))
expect_equal(s$map(c("data_red", "data_black")), c("red", "black"))
})