Skip to content

Commit 0d0dc62

Browse files
authored
after_*() length checks (#5902)
* throw warnings * simplify `try_fetch()` block in legend * add tests * add news bullet * nicer pluralisation
1 parent 5199cee commit 0d0dc62

File tree

5 files changed

+44
-11
lines changed

5 files changed

+44
-11
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@
8888
to different position aesthetics of the same axis (@teunbrand, #5818).
8989
* In `stat_bin()`, the default `boundary` is now chosen to better adhere to
9090
the `nbin` argument (@teunbrand, #5882, #5036)
91+
* `after_stat()` and `after_scale()` throw warnings when the computed aesthetics
92+
are not of the correct length (#5901).
9193

9294
# ggplot2 3.5.1
9395

R/geom-.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ Geom <- ggproto("Geom",
167167
}
168168

169169
names(modified_aes) <- names(rename_aes(modifiers))
170+
171+
modified_aes <- cleanup_mismatched_data(modified_aes, nrow(data), "after_scale")
172+
170173
modified_aes <- data_frame0(!!!compact(modified_aes))
171174

172175
data <- cunion(modified_aes, data)

R/guide-legend.R

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,17 +238,7 @@ GuideLegend <- ggproto(
238238
is_modified <- is_scaled_aes(aesthetics) | is_staged_aes(aesthetics)
239239
modifiers <- aesthetics[is_modified]
240240

241-
data <- try_fetch(
242-
layer$geom$use_defaults(params$key[matched_aes],
243-
layer_params, modifiers),
244-
error = function(cnd) {
245-
cli::cli_warn(
246-
"Failed to apply {.fn after_scale} modifications to legend",
247-
parent = cnd
248-
)
249-
layer$geom$use_defaults(params$key[matched_aes], layer_params, list())
250-
}
251-
)
241+
data <- layer$geom$use_defaults(params$key[matched_aes], layer_params, modifiers)
252242
data$.draw <- keep_key_data(params$key, df, matched_aes, layer$show.legend)
253243
} else {
254244
reps <- rep(1, nrow(params$key))

R/layer.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ Layer <- ggproto("Layer", NULL,
412412
if (self$stat$retransform) {
413413
stat_data <- plot$scales$transform_df(stat_data)
414414
}
415+
stat_data <- cleanup_mismatched_data(stat_data, nrow(data), "after_stat")
415416

416417
cunion(stat_data, data)
417418
},
@@ -498,3 +499,18 @@ set_draw_key <- function(geom, draw_key = NULL) {
498499
ggproto("", geom, draw_key = draw_key)
499500
}
500501

502+
cleanup_mismatched_data <- function(data, n, fun) {
503+
failed <- !lengths(data) %in% c(0, 1, n)
504+
if (!any(failed)) {
505+
return(data)
506+
}
507+
508+
failed <- names(data)[failed]
509+
cli::cli_warn(
510+
"Failed to apply {.fn {fun}} for the following \\
511+
aesthetic{?s}: {.field {failed}}."
512+
)
513+
514+
data[failed] <- NULL
515+
data
516+
}

tests/testthat/test-aes-calculated.R

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,28 @@ test_that("staged aesthetics warn appropriately for duplicated names", {
7070
expect_snapshot_warning(ggplot_build(p))
7171
})
7272

73+
test_that("calculated aesthetics throw warnings when lengths mismatch", {
74+
75+
df <- data.frame(x = 1:2)
76+
77+
p <- ggplot(df, aes(x, x))
78+
79+
expect_warning(
80+
ggplot_build(
81+
p + geom_point(aes(colour = after_stat(c("A", "B", "C"))))
82+
),
83+
"Failed to apply"
84+
)
85+
86+
expect_warning(
87+
ggplot_build(
88+
p + geom_point(aes(colour = after_scale(c("red", "green", "blue"))))
89+
),
90+
"Failed to apply"
91+
)
92+
93+
})
94+
7395
test_that("A deprecated warning is issued when stat(var) or ..var.. is used", {
7496
p1 <- ggplot(NULL, aes(stat(foo)))
7597
expect_snapshot_warning(b1 <- ggplot_build(p1))

0 commit comments

Comments
 (0)