diff --git a/NEWS.md b/NEWS.md index 7d306c43c1..f7a93a88e4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # ggplot2 (development version) +* Aesthetics of length 1 are now recycled to 0 if the length of the data is 0 + (@thomasp85, #4588) + * Setting `size = NA` will no longer cause `guide_legend()` to error (@thomasp85, #4559) diff --git a/R/geom-.r b/R/geom-.r index e513769c03..8265d6cd4c 100644 --- a/R/geom-.r +++ b/R/geom-.r @@ -208,7 +208,7 @@ NULL .stroke <- 96 / 25.4 check_aesthetics <- function(x, n) { - ns <- vapply(x, length, numeric(1)) + ns <- vapply(x, length, integer(1)) good <- ns == 1L | ns == n if (all(good)) { diff --git a/R/layer.r b/R/layer.r index 197d32549d..dcb66f92bf 100644 --- a/R/layer.r +++ b/R/layer.r @@ -264,7 +264,8 @@ Layer <- ggproto("Layer", NULL, if (length(evaled) == 0) { n <- 0 } else { - n <- max(vapply(evaled, length, integer(1))) + aes_n <- vapply(evaled, length, integer(1)) + n <- if (min(aes_n) == 0) 0L else max(aes_n) } } check_aesthetics(evaled, n) diff --git a/tests/testthat/test-aes-setting.r b/tests/testthat/test-aes-setting.r index baa6a12077..4c3e055ea8 100644 --- a/tests/testthat/test-aes-setting.r +++ b/tests/testthat/test-aes-setting.r @@ -13,6 +13,17 @@ test_that("aesthetic parameters match length of data", { set_colours(rep("red", 5)) }) +test_that("Length 1 aesthetics are recycled to 0", { + p <- ggplot(data.frame(x = numeric(), y = numeric())) + + geom_point(aes(x, y, colour = "red")) + + expect_silent(plot(p)) + + data <- layer_data(p) + + expect_equal(nrow(data), 0) +}) + test_that("legend filters out aesthetics not of length 1", { df <- data_frame(x = 1:5, y = 1:5) p <- ggplot(df, aes(x, y, colour = factor(x))) +