From d8a520bb2d7ebdfc3396e45a8a3eccc67ea212d0 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 21 Mar 2024 09:49:05 +0100 Subject: [PATCH 1/4] skip alignment if there is just one group --- R/stat-align.R | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/R/stat-align.R b/R/stat-align.R index 5f49b29152..3187ca28c0 100644 --- a/R/stat-align.R +++ b/R/stat-align.R @@ -40,22 +40,19 @@ StatAlign <- ggproto("StatAlign", Stat, if (empty(data)) { return(data_frame0()) } - + if (is_unique(data$group)) { + return(data) + } names <- flipped_names(flipped_aes) x <- data[[names$x]] y <- data[[names$y]] - if (is_unique(data$group)) { - # No need for interpolation - cross <- x[0] - } else { - # Find positions where 0 is crossed - pivot <- vec_unrep(data_frame0(group = data$group, y = y < 0)) - group_ends <- cumsum(vec_unrep(pivot$key$group)$times) - pivot <- cumsum(pivot$times)[-group_ends] - cross <- -y[pivot] * (x[pivot + 1] - x[pivot]) / - (y[pivot + 1] - y[pivot]) + x[pivot] - } + # Find positions where 0 is crossed + pivot <- vec_unrep(data_frame0(group = data$group, y = y < 0)) + group_ends <- cumsum(vec_unrep(pivot$key$group)$times) + pivot <- cumsum(pivot$times)[-group_ends] + cross <- -y[pivot] * (x[pivot + 1] - x[pivot]) / + (y[pivot + 1] - y[pivot]) + x[pivot] unique_loc <- unique(sort(c(x, cross))) adjust <- diff(range(unique_loc, na.rm = TRUE)) * 0.001 From 9f4f5f732269b2c17b34c0e86af254a4347d7015 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 21 Mar 2024 09:49:19 +0100 Subject: [PATCH 2/4] add extra group to test --- tests/testthat/test-stat-align.R | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-stat-align.R b/tests/testthat/test-stat-align.R index 411e29b2b8..87a69cbba7 100644 --- a/tests/testthat/test-stat-align.R +++ b/tests/testthat/test-stat-align.R @@ -48,19 +48,20 @@ test_that("alignment adjusts per panel", { # data into account (#5227) df <- data_frame0( - x = c(0, 1, 1000, 1001), - y = c(-1, 1, -1, 1), - g = c("A", "A", "B", "B") + x = c(0, 1, 1000, 1001, 0, 1, 1000, 1001), + y = c(-1, 1, -1, 1, -1, 1, -1, 1), + f = c("A", "A", "B", "B", "A", "A", "B", "B"), + g = c("a", "a", "b", "b", "c", "c", "d", "d") ) - p <- ggplot(df, aes(x, y)) + p <- ggplot(df, aes(x, y, group = g)) # Here, x-range is large, so adjustment should be larger - ld <- layer_data(p + geom_area(aes(fill = g))) + ld <- layer_data(p + geom_area(aes(fill = f))) expect_equal(diff(ld$x[1:2]), 1/6, tolerance = 1e-4) # Here, x-ranges are smaller, so adjustment should be smaller instead of # considering the data as a whole - ld <- layer_data(p + geom_area() + facet_wrap(vars(g), scales = "free_x")) + ld <- layer_data(p + geom_area() + facet_wrap(vars(f), scales = "free_x")) expect_equal(diff(ld$x[1:2]), 1e-3, tolerance = 1e-4) }) From 3aa945be0abce19d7ade71de90f3c13567572906 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 21 Mar 2024 10:25:41 +0100 Subject: [PATCH 3/4] skip stacking if every x position is unique --- R/position-stack.R | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/R/position-stack.R b/R/position-stack.R index ac445be071..2da5c91ef6 100644 --- a/R/position-stack.R +++ b/R/position-stack.R @@ -187,6 +187,10 @@ PositionStack <- ggproto("PositionStack", Position, if (is.null(params$var)) { return(data) } + if (!vec_duplicate_any(data$x)) { + # Every x is unique, nothing to stack here + return(flip_data(data, params$flipped_aes)) + } negative <- data$ymax < 0 negative[is.na(negative)] <- FALSE From af470862efb2f21f3385e41fd74c9b4cf9d42319 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 21 Mar 2024 10:34:34 +0100 Subject: [PATCH 4/4] add news bullets --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index a96a2e4b02..cce7a5809a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -26,6 +26,10 @@ * When legends detect the presence of values in a layer, `NA` is now detected if the data contains values outside the given breaks (@teunbrand, #5749). * `annotate()` now warns about `stat` or `position` arguments (@teunbrand, #5151) +* `stat_align()` skips computation when there is only 1 group and therefore + alignment is not necessary (#5788). +* `position_stack()` skips computation when all `x` values are unique and + therefore stacking is not necessary (#5788). # ggplot2 3.5.0