From 82bf7d93b45dfe6b64fbe5095cdbbe30cac5ce98 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 10:42:34 +0100 Subject: [PATCH 1/6] fix early exit --- R/geom-hex.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/geom-hex.R b/R/geom-hex.R index 0e67b49ad9..0240c52b1a 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -5,10 +5,10 @@ GeomHex <- ggproto("GeomHex", Geom, draw_group = function(self, data, panel_params, coord, lineend = "butt", linejoin = "mitre", linemitre = 10) { - data <- fix_linewidth(data, snake_class(self)) if (empty(data)) { return(zeroGrob()) } + data <- fix_linewidth(data, snake_class(self)) # Get hex sizes if (!is.null(data$width)) { From 3b9867cb75b0a128151f794effb1620ae4e36b7f Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 10:48:35 +0100 Subject: [PATCH 2/6] exploit `hexbin::hexcoords(n)` arg --- R/geom-hex.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/geom-hex.R b/R/geom-hex.R index 0240c52b1a..d17f769cd5 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -25,9 +25,8 @@ GeomHex <- ggproto("GeomHex", Geom, dy <- resolution(data$y, FALSE, TRUE) / sqrt(3) / 2 * 1.15 } - hexC <- hexbin::hexcoords(dx, dy, n = 1) - n <- nrow(data) + hexC <- hexbin::hexcoords(dx, dy, n = n) hexdata <- data[rep(seq_len(n), each = 6), c("x", "y")] hexdata$x <- rep.int(hexC$x, n) + hexdata$x From 6ccb3b6721bd5bef674f5f7f9a2ba414b5fe7cae Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 10:48:46 +0100 Subject: [PATCH 3/6] add `radius` aesthetic --- R/geom-hex.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/geom-hex.R b/R/geom-hex.R index d17f769cd5..0d196221c0 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -57,6 +57,7 @@ GeomHex <- ggproto("GeomHex", Geom, fill = from_theme(fill %||% col_mix(ink, paper)), linewidth = from_theme(borderwidth), linetype = from_theme(bordertype), + radius = 1, alpha = NA ), From fbf5c971431465f9a4c0461a362612332814efb5 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 10:49:03 +0100 Subject: [PATCH 4/6] use `radius` in hexagon construction --- R/geom-hex.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/geom-hex.R b/R/geom-hex.R index 0d196221c0..a8c9cc2979 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -28,9 +28,9 @@ GeomHex <- ggproto("GeomHex", Geom, n <- nrow(data) hexC <- hexbin::hexcoords(dx, dy, n = n) - hexdata <- data[rep(seq_len(n), each = 6), c("x", "y")] - hexdata$x <- rep.int(hexC$x, n) + hexdata$x - hexdata$y <- rep.int(hexC$y, n) + hexdata$y + hexdata <- vec_rep_each(data[c("x", "y", "radius")], times = 6L) + hexdata$x <- hexC$x * hexdata$radius + hexdata$x + hexdata$y <- hexC$y * hexdata$radius + hexdata$y coords <- coord$transform(hexdata, panel_params) From c1e55366393e2d5a18dd86f1882efcd6a5a2c4c2 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 11:15:13 +0100 Subject: [PATCH 5/6] add example --- R/geom-hex.R | 3 +++ man/geom_hex.Rd | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/R/geom-hex.R b/R/geom-hex.R index a8c9cc2979..71c88a4cf6 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -99,5 +99,8 @@ GeomHex <- ggproto("GeomHex", Geom, #' # Or by specifying the width of the bins #' d + geom_hex(binwidth = c(1, 1000)) #' d + geom_hex(binwidth = c(.1, 500)) +#' +#' # The hexagons can be scaled by tuning the radius aesthetic +#' d + geom_hex(aes(radius = after_stat(ncount))) #' } geom_hex <- make_constructor(GeomHex, stat = 'binhex') diff --git a/man/geom_hex.Rd b/man/geom_hex.Rd index fce589bbff..9f295cc507 100644 --- a/man/geom_hex.Rd +++ b/man/geom_hex.Rd @@ -175,6 +175,9 @@ d + geom_hex(bins = 30) # Or by specifying the width of the bins d + geom_hex(binwidth = c(1, 1000)) d + geom_hex(binwidth = c(.1, 500)) + +# The hexagons can be scaled by tuning the radius aesthetic +d + geom_hex(aes(radius = after_stat(ncount))) } } \seealso{ @@ -192,6 +195,7 @@ d + geom_hex(binwidth = c(.1, 500)) • \tab \code{\link[=aes_group_order]{group}} \tab → inferred \cr • \tab \code{\link[=aes_linetype_size_shape]{linetype}} \tab → via \code{theme()} \cr • \tab \code{\link[=aes_linetype_size_shape]{linewidth}} \tab → via \code{theme()} \cr + • \tab \code{radius} \tab → \code{1} \cr } \code{stat_binhex()} understands the following aesthetics. Required aesthetics are displayed in bold and defaults are displayed for optional aesthetics: From 4bf6a7c45c78490c8ccdb2a86e55aadc45333f64 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 5 Nov 2025 11:23:03 +0100 Subject: [PATCH 6/6] add test --- .../geom-hex/hexes-with-different-sizes.svg | 60 +++++++++++++++++++ tests/testthat/test-geom-hex.R | 11 ++++ 2 files changed, 71 insertions(+) create mode 100644 tests/testthat/_snaps/geom-hex/hexes-with-different-sizes.svg diff --git a/tests/testthat/_snaps/geom-hex/hexes-with-different-sizes.svg b/tests/testthat/_snaps/geom-hex/hexes-with-different-sizes.svg new file mode 100644 index 0000000000..134814cb90 --- /dev/null +++ b/tests/testthat/_snaps/geom-hex/hexes-with-different-sizes.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +-1.0 +-0.5 +0.0 +0.5 +1.0 + + + + + + + + + + +0 +1 +2 +3 +4 +x +y +hexes with different sizes + + diff --git a/tests/testthat/test-geom-hex.R b/tests/testthat/test-geom-hex.R index 498f00d407..516bc8a060 100644 --- a/tests/testthat/test-geom-hex.R +++ b/tests/testthat/test-geom-hex.R @@ -27,6 +27,17 @@ test_that("bin size are picked up from stat", { geom_hex(aes(x = x, y = y), binwidth = c(0.1, 0.1)) + coord_cartesian(xlim = c(-1, 1), ylim = c(-1, 1)) ) + + expect_doppelganger( + "hexes with different sizes", + ggplot(data.frame(x = 1:3, y = 0, r = (1:3)/6)) + + geom_hex( + aes(x = x, y = y, radius = r), + stat = "identity" + ) + + coord_cartesian(xlim = c(0, 4), y = c(-1, 1)) + ) + }) test_that("geom_hex works in non-linear coordinate systems", {