From 14e1b4b85a59897c21984dd9dc8c922fefce7a7e Mon Sep 17 00:00:00 2001 From: Teun van den Brand <49372158+teunbrand@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:12:28 +0100 Subject: [PATCH 1/4] instead of removing, `position_stack()` sets incomplete data to missing --- R/position-stack.R | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/R/position-stack.R b/R/position-stack.R index 7be91d3abf..cff83ac74d 100644 --- a/R/position-stack.R +++ b/R/position-stack.R @@ -175,11 +175,10 @@ PositionStack <- ggproto("PositionStack", Position, ymax = as.numeric(ifelse(data$ymax == 0, data$ymin, data$ymax)) ) - data <- remove_missing( - data, - vars = c("x", "xmin", "xmax", "y"), - name = "position_stack" - ) + vars <- intersect(c("x", "xmin", "xmax", "y"), names(data)) + missing <- detect_missing(data, vars) + data[missing, vars] <- NA + flip_data(data, params$flipped_aes) }, From e0c98ed6e6c466aa4c26f2afc40d7df7228b403e Mon Sep 17 00:00:00 2001 From: Teun van den Brand <49372158+teunbrand@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:12:50 +0100 Subject: [PATCH 2/4] adjust test --- tests/testthat/test-geom-col.R | 4 ++-- tests/testthat/test-scales.R | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-geom-col.R b/tests/testthat/test-geom-col.R index 456f03142f..17c61064d9 100644 --- a/tests/testthat/test-geom-col.R +++ b/tests/testthat/test-geom-col.R @@ -7,8 +7,8 @@ test_that("geom_col removes columns with parts outside the plot limits", { ggplotGrob(p + ylim(0.5, 4)), "Removed 3 rows containing missing values or values outside the scale range" ) - expect_warning( # warning created at build stage - ggplot_build(p + ylim(0, 2.5)), + expect_warning( # warning created at render stage + ggplotGrob(p + ylim(0, 2.5)), "Removed 1 row containing missing values or values outside the scale range" ) }) diff --git a/tests/testthat/test-scales.R b/tests/testthat/test-scales.R index 2b1c80729d..cabb9b20b8 100644 --- a/tests/testthat/test-scales.R +++ b/tests/testthat/test-scales.R @@ -111,10 +111,14 @@ test_that("oob affects position values", { } base + scale_y_continuous(limits = c(-0,5)) - expect_warning(low_censor <- cdata(base + y_scale(c(0, 5), censor)), + low_censor <- cdata(base + y_scale(c(0, 5), censor)) + mid_censor <- cdata(base + y_scale(c(3, 7), censor)) + handle <- GeomBar$handle_na + + expect_warning(low_censor[[1]] <- handle(low_censor[[1]], list(na.rm = FALSE)), "Removed 1 row containing missing values or values outside the scale range") - expect_warning(mid_censor <- cdata(base + y_scale(c(3, 7), censor)), - "Removed 2 rows containing missing values or values outside the scale range") + expect_warning(mid_censor[[1]] <- handle(mid_censor[[1]], list(na.rm = FALSE)), + "Removed 3 rows containing missing values or values outside the scale range") low_squish <- cdata(base + y_scale(c(0, 5), squish)) mid_squish <- cdata(base + y_scale(c(3, 7), squish)) @@ -127,7 +131,7 @@ test_that("oob affects position values", { # Bars depend on limits and oob expect_equal(low_censor[[1]]$y, c(0.2, 1)) - expect_equal(mid_censor[[1]]$y, c(0.5)) + expect_equal(mid_censor[[1]]$y, numeric(0)) expect_equal(low_squish[[1]]$y, c(0.2, 1, 1)) expect_equal(mid_squish[[1]]$y, c(0, 0.5, 1)) }) From c1757c0d61c6ac8619765103b3590b36f207e4bf Mon Sep 17 00:00:00 2001 From: Teun van den Brand <49372158+teunbrand@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:30:08 +0100 Subject: [PATCH 3/4] add test --- R/stat-count.R | 3 +-- tests/testthat/test-stat-count.R | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/R/stat-count.R b/R/stat-count.R index 705e0f4226..81790d7aa1 100644 --- a/R/stat-count.R +++ b/R/stat-count.R @@ -75,8 +75,7 @@ StatCount <- ggproto("StatCount", Stat, x <- data$x weight <- data$weight %||% rep(1, length(x)) - count <- as.numeric(tapply(weight, x, sum, na.rm = TRUE)) - count[is.na(count)] <- 0 + count <- as.vector(rowsum(weight, x, na.rm = TRUE)) bars <- data_frame0( count = count, diff --git a/tests/testthat/test-stat-count.R b/tests/testthat/test-stat-count.R index 827ac9f109..7483becf94 100644 --- a/tests/testthat/test-stat-count.R +++ b/tests/testthat/test-stat-count.R @@ -4,3 +4,14 @@ test_that("stat_count() checks the aesthetics", { p <- ggplot(mtcars) + stat_count(aes(factor(gear), mpg)) expect_snapshot_error(ggplot_build(p)) }) + +test_that("stat_count() respects uniqueness of `x`", { + # For #4609, converting x to factor loses smallest digits, so here we test + # if they are retained + df <- data_frame0(x = c(1, 2, 1, 2) + rep(c(0, 1.01 * .Machine$double.eps), each = 2)) + p <- ggplot(df, aes(x)) + stat_count(position = "identity") + data <- layer_data(p) + + expect_length(vec_unique(df$x), 4) + expect_equal(data$y, rep(1, 4)) +}) From b1d30ffe7e116ec88faecbf9d27a696ceb38a0dc Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 14 Dec 2023 12:41:53 +0100 Subject: [PATCH 4/4] Add news bullet --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 55dffd0401..0100c68e9d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # ggplot2 (development version) +* `stat_count()` treats `x` as unique in the same manner `unique()` does + (#4609). + * The `trans` argument in scales and secondary axes has been renamed to `transform`. The `trans` argument itself is deprecated. To access the transformation from the scale, a new `get_transformation()` method is