From 77474a281f6fb13cdfa8f51e59104d8532d532b0 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 May 2026 08:47:31 +0200 Subject: [PATCH 1/5] Discrepancy between geom_point2 and geom_point_borderless (and similar) Fixes #395 --- DESCRIPTION | 2 +- NAMESPACE | 4 +++ NEWS.md | 8 +++++ R/geom_point2.R | 90 ++++++++++++++++++++++++++++++++++++---------- man/geom_point2.Rd | 47 +++++++++++++++++------- 5 files changed, 119 insertions(+), 32 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 55905b784..97c981ac3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: see Title: Model Visualisation Toolbox for 'easystats' and 'ggplot2' -Version: 0.13.0.3 +Version: 0.13.0.4 Authors@R: c(person(given = "Daniel", family = "Lüdecke", diff --git a/NAMESPACE b/NAMESPACE index baf540162..c96270233 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -83,13 +83,17 @@ export(flat_colors) export(geom_binomdensity) export(geom_count2) export(geom_count_borderless) +export(geom_count_halo) export(geom_from_list) export(geom_jitter2) export(geom_jitter_borderless) +export(geom_jitter_halo) export(geom_point2) export(geom_point_borderless) +export(geom_point_halo) export(geom_pointrange2) export(geom_pointrange_borderless) +export(geom_pointrange_halo) export(geom_pooljitter) export(geom_poolpoint) export(geom_violindot) diff --git a/NEWS.md b/NEWS.md index c69d58ce1..be3c064fd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,14 @@ * Updated plot-method for `performance::check_model()` for Bayesian ordinal models. +* New `geom_point_halo()`, `geom_pointrange_halo()`, `geom_jitter_halo()` and + `geom_count_halo()` geoms, which add a slight contour around the points + +## Bug fixes + +* Fixed the `*_borless` aliases for `geom_point2()` or `geom_jitter2()`, which + were broken and did not render as intended. + # see 0.13.0 ## Breaking Changes diff --git a/R/geom_point2.R b/R/geom_point2.R index 24389c93c..fdec0a5cb 100644 --- a/R/geom_point2.R +++ b/R/geom_point2.R @@ -1,19 +1,25 @@ -#' Better looking points +#' @title Better looking points +#' @name geom_point2 #' -#' Somewhat nicer points (especially in case of transparency) without outline -#' strokes (borders, contours) by default. +#' @description +#' The `*_borderless` geoms (and their shortcuts ending in `2`, such as `geom_point2` +#' or `geom_point_borderless`) render points without an outline stroke by default. +#' This prevents harsh edges and yields a smoother, cleaner look, especially when +#' using transparency. +#' +#' In contrast, the `*_halo` variants feature a border that automatically matches +#' the plot's background color. This creates a subtle visual separation (a "halo" +#' effect) that keeps overlapping points distinct. #' #' @param size Size of points. #' @param stroke Stroke thickness. #' @param shape Shape of points. -#' @param ... Other arguments to be passed to -#' [ggplot2::geom_point()], -#' [ggplot2::geom_jitter()], -#' [ggplot2::geom_pointrange()], or -#' [ggplot2::geom_count()]. +#' @param ... Other arguments to be passed to [ggplot2::geom_point()], +#' [ggplot2::geom_jitter()], [ggplot2::geom_pointrange()], or +#' [ggplot2::geom_count()]. #' -#' @note The color aesthetics for `geom_point_borderless()` is `"fill"`, not -#' `"color"`. See 'Examples'. +#' @note The color aesthetics for the `*_borderless()` and `*_halo()` functions +#' are `"fill"`, not `"color"`. See 'Examples'. #' #' @examplesIf requireNamespace("patchwork", quietly = TRUE) #' library(ggplot2) @@ -29,13 +35,18 @@ #' #' plots(normal, new, n_columns = 2) #' -#' ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + +#' ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, color = Species)) + #' geom_point_borderless(size = 4) + #' theme_modern() #' #' theme_set(theme_abyss()) -#' ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + +#' ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, color = Species)) + #' geom_point_borderless(size = 4) +#' +#' # add "halo" effect - note that the aesthetics is "fill", not "color" +#' theme_set(theme_abyss()) +#' ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + +#' geom_point_halo(size = 12) #' @export geom_point2 <- function(..., stroke = 0, shape = 16) { geom_point(stroke = stroke, shape = shape, ...) @@ -66,22 +77,65 @@ geom_count_borderless <- geom_count2 #' @rdname geom_point2 #' @export -geom_point_borderless <- function(...) { - geom_point(pch = 21, color = .get_theme_bg_color(), ...) +geom_point_borderless <- geom_point2 + + +#' @rdname geom_point2 +#' @export +geom_jitter_borderless <- geom_jitter2 + + +#' @rdname geom_point2 +#' @export +geom_pointrange_borderless <- geom_pointrange2 + + +#' @rdname geom_point2 +#' @export +geom_point_halo <- function(...) { + fun <- ggplot2::geom_point + .geom_halo(fun, ...) +} + + +#' @rdname geom_point2 +#' @export +geom_jitter_halo <- function(...) { + fun <- ggplot2::geom_jitter + .geom_halo(fun, ...) } #' @rdname geom_point2 #' @export -geom_jitter_borderless <- function(...) { - geom_jitter(pch = 21, color = .get_theme_bg_color(), ...) +geom_count_halo <- function(...) { + fun <- ggplot2::geom_count + .geom_halo(fun, ...) } #' @rdname geom_point2 #' @export -geom_pointrange_borderless <- function(...) { - geom_pointrange(pch = 21, color = .get_theme_bg_color(), ...) +geom_pointrange_halo <- function(...) { + fun <- ggplot2::geom_pointrange + .geom_halo(fun, ...) +} + + +.geom_halo <- function(fun, ...) { + dots <- list(...) + if (!is.null(dots$color)) { + dots$fill <- dots$color + } + if (!is.null(dots$colour)) { + dots$fill <- dots$colour + } + + dots$colour <- NULL + dots$color <- .get_theme_bg_color() + + fun_args <- c(list(pch = 21), dots) + do.call(fun, fun_args) } diff --git a/man/geom_point2.Rd b/man/geom_point2.Rd index 17bc5ba68..6d3e32636 100644 --- a/man/geom_point2.Rd +++ b/man/geom_point2.Rd @@ -9,6 +9,10 @@ \alias{geom_point_borderless} \alias{geom_jitter_borderless} \alias{geom_pointrange_borderless} +\alias{geom_point_halo} +\alias{geom_jitter_halo} +\alias{geom_count_halo} +\alias{geom_pointrange_halo} \title{Better looking points} \usage{ geom_point2(..., stroke = 0, shape = 16) @@ -21,17 +25,23 @@ geom_count2(..., stroke = 0) geom_count_borderless(..., stroke = 0) -geom_point_borderless(...) +geom_point_borderless(..., stroke = 0, shape = 16) -geom_jitter_borderless(...) +geom_jitter_borderless(..., size = 2, stroke = 0, shape = 16) -geom_pointrange_borderless(...) +geom_pointrange_borderless(..., stroke = 0) + +geom_point_halo(...) + +geom_jitter_halo(...) + +geom_count_halo(...) + +geom_pointrange_halo(...) } \arguments{ -\item{...}{Other arguments to be passed to -\code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}, -\code{\link[ggplot2:geom_jitter]{ggplot2::geom_jitter()}}, -\code{\link[ggplot2:geom_pointrange]{ggplot2::geom_pointrange()}}, or +\item{...}{Other arguments to be passed to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}, +\code{\link[ggplot2:geom_jitter]{ggplot2::geom_jitter()}}, \code{\link[ggplot2:geom_pointrange]{ggplot2::geom_pointrange()}}, or \code{\link[ggplot2:geom_count]{ggplot2::geom_count()}}.} \item{stroke}{Stroke thickness.} @@ -41,12 +51,18 @@ geom_pointrange_borderless(...) \item{size}{Size of points.} } \description{ -Somewhat nicer points (especially in case of transparency) without outline -strokes (borders, contours) by default. +The \verb{*_borderless} geoms (and their shortcuts ending in \code{2}, such as \code{geom_point2} +or \code{geom_point_borderless}) render points without an outline stroke by default. +This prevents harsh edges and yields a smoother, cleaner look, especially when +using transparency. + +In contrast, the \verb{*_halo} variants feature a border that automatically matches +the plot's background color. This creates a subtle visual separation (a "halo" +effect) that keeps overlapping points distinct. } \note{ -The color aesthetics for \code{geom_point_borderless()} is \code{"fill"}, not -\code{"color"}. See 'Examples'. +The color aesthetics for the \verb{*_borderless()} and \verb{*_halo()} functions +are \code{"fill"}, not \code{"color"}. See 'Examples'. } \examples{ \dontshow{if (requireNamespace("patchwork", quietly = TRUE)) withAutoprint(\{ # examplesIf} @@ -63,12 +79,17 @@ new <- ggplot(iris, aes(x = Petal.Width, y = Sepal.Length)) + plots(normal, new, n_columns = 2) -ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + +ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, color = Species)) + geom_point_borderless(size = 4) + theme_modern() theme_set(theme_abyss()) -ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + +ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, color = Species)) + geom_point_borderless(size = 4) + +# add "halo" effect - note that the aesthetics is "fill", not "color" +theme_set(theme_abyss()) +ggplot(iris, aes(x = Petal.Width, y = Sepal.Length, fill = Species)) + + geom_point_halo(size = 12) \dontshow{\}) # examplesIf} } From 261e600b39e79ee3dbbaf087878123e6f6125b98 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 May 2026 08:48:09 +0200 Subject: [PATCH 2/5] typo --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index be3c064fd..8011ffa5b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,7 +10,7 @@ ## Bug fixes -* Fixed the `*_borless` aliases for `geom_point2()` or `geom_jitter2()`, which +* Fixed the `*_borderless` aliases for `geom_point2()` or `geom_jitter2()`, which were broken and did not render as intended. # see 0.13.0 From 1a28b1ed25815fe39c441bcfe405e8a72cfc4072 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 May 2026 09:01:40 +0200 Subject: [PATCH 3/5] add tests --- .../geom-point-borderless-1.svg | 206 +++++++++++++++++ .../geom-point-borderless-2.svg | 216 ++++++++++++++++++ .../geom-point-halo-1.svg | 216 ++++++++++++++++++ tests/testthat/test-vdiffr_geoms_borderless.R | 47 ++++ 4 files changed, 685 insertions(+) create mode 100644 tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-1.svg create mode 100644 tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-2.svg create mode 100644 tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg create mode 100644 tests/testthat/test-vdiffr_geoms_borderless.R diff --git a/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-1.svg b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-1.svg new file mode 100644 index 000000000..fd89bb248 --- /dev/null +++ b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-1.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5 +6 +7 +8 + +0.0 +0.5 +1.0 +1.5 +2.0 +2.5 +Petal.Width +Sepal.Length + +Species + + + +setosa +versicolor +virginica +geom_point_borderless_1 + + diff --git a/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-2.svg b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-2.svg new file mode 100644 index 000000000..933d531ba --- /dev/null +++ b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-borderless-2.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5 +6 +7 +8 + +0.0 +0.5 +1.0 +1.5 +2.0 +2.5 +Petal.Width +Sepal.Length + +Species + + + +setosa +versicolor +virginica +geom_point_borderless_2 + + diff --git a/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg new file mode 100644 index 000000000..77bbe9271 --- /dev/null +++ b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5 +6 +7 +8 + +0.0 +0.5 +1.0 +1.5 +2.0 +2.5 +Petal.Width +Sepal.Length + +Species + + + +setosa +versicolor +virginica +geom_point_halo_1 + + diff --git a/tests/testthat/test-vdiffr_geoms_borderless.R b/tests/testthat/test-vdiffr_geoms_borderless.R new file mode 100644 index 000000000..c7eb5fa4b --- /dev/null +++ b/tests/testthat/test-vdiffr_geoms_borderless.R @@ -0,0 +1,47 @@ +test_that("borderless geoms work correctly", { + skip_on_cran() + skip_if_not_installed("ggplot2") + skip_if_not_installed("vdiffr") + data(iris) + + p <- ggplot2::ggplot( + iris, + ggplot2::aes(x = Petal.Width, y = Sepal.Length, color = Species) + ) + + geom_point_borderless(size = 4) + + theme_modern() + + set.seed(123) + vdiffr::expect_doppelganger( + title = "geom_point_borderless_1", + fig = p + ) + + ggplot2::theme_set(theme_abyss()) + p <- ggplot2::ggplot( + iris, + ggplot2::aes(x = Petal.Width, y = Sepal.Length, color = Species) + ) + + theme_abyss() + + geom_point_borderless(size = 4) + + set.seed(123) + vdiffr::expect_doppelganger( + title = "geom_point_borderless_2", + fig = p + ) + + ggplot2::theme_set(theme_abyss()) + p <- ggplot2::ggplot( + iris, + ggplot2::aes(x = Petal.Width, y = Sepal.Length, fill = Species) + ) + + theme_abyss() + + geom_point_halo(size = 12) + + set.seed(123) + vdiffr::expect_doppelganger( + title = "geom_point_halo_1", + fig = p + ) +}) From 41021d8a12ddf96eae7489d4668b18a84190d4d9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 May 2026 09:17:26 +0200 Subject: [PATCH 4/5] fix --- R/geom_point2.R | 10 +- .../geom-point-halo-1.svg | 306 +++++++++--------- 2 files changed, 156 insertions(+), 160 deletions(-) diff --git a/R/geom_point2.R b/R/geom_point2.R index fdec0a5cb..df9ef6931 100644 --- a/R/geom_point2.R +++ b/R/geom_point2.R @@ -131,7 +131,7 @@ geom_pointrange_halo <- function(...) { dots$fill <- dots$colour } - dots$colour <- NULL + dots$colour <- dots$shape <- dots$pch <- NULL dots$color <- .get_theme_bg_color() fun_args <- c(list(pch = 21), dots) @@ -142,14 +142,10 @@ geom_pointrange_halo <- function(...) { .get_theme_bg_color <- function() { current_theme <- ggplot2::theme_get() - if (is.null(current_theme$panel.grid.major)) { - current_theme$panel.grid.major <- current_theme$panel.grid - } - bg_color <- ifelse( - is.null(current_theme$panel.grid.major$colour), + is.null(current_theme$panel.background$fill), "white", - current_theme$panel.grid.major$colour + current_theme$panel.background$fill ) bg_color diff --git a/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg index 77bbe9271..46a4400b6 100644 --- a/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg +++ b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg @@ -37,156 +37,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -205,9 +205,9 @@ Sepal.Length Species - - - + + + setosa versicolor virginica From 56e86d7aeb34e16a97e31ed6f7932c5344788a02 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 May 2026 09:19:29 +0200 Subject: [PATCH 5/5] rd --- R/geom_point2.R | 4 ++-- man/geom_point2.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/geom_point2.R b/R/geom_point2.R index df9ef6931..0e6c5e21e 100644 --- a/R/geom_point2.R +++ b/R/geom_point2.R @@ -18,8 +18,8 @@ #' [ggplot2::geom_jitter()], [ggplot2::geom_pointrange()], or #' [ggplot2::geom_count()]. #' -#' @note The color aesthetics for the `*_borderless()` and `*_halo()` functions -#' are `"fill"`, not `"color"`. See 'Examples'. +#' @note The color aesthetics for the `*_halo()` functions is `"fill"`, not +#' `"color"`. See 'Examples'. #' #' @examplesIf requireNamespace("patchwork", quietly = TRUE) #' library(ggplot2) diff --git a/man/geom_point2.Rd b/man/geom_point2.Rd index 6d3e32636..d42a5ef06 100644 --- a/man/geom_point2.Rd +++ b/man/geom_point2.Rd @@ -61,8 +61,8 @@ the plot's background color. This creates a subtle visual separation (a "halo" effect) that keeps overlapping points distinct. } \note{ -The color aesthetics for the \verb{*_borderless()} and \verb{*_halo()} functions -are \code{"fill"}, not \code{"color"}. See 'Examples'. +The color aesthetics for the \verb{*_halo()} functions is \code{"fill"}, not +\code{"color"}. See 'Examples'. } \examples{ \dontshow{if (requireNamespace("patchwork", quietly = TRUE)) withAutoprint(\{ # examplesIf}