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..8011ffa5b 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 `*_borderless` 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..0e6c5e21e 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 `*_halo()` functions is `"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,36 +77,75 @@ 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_borderless <- function(...) {
- geom_jitter(pch = 21, color = .get_theme_bg_color(), ...)
+geom_jitter_halo <- function(...) {
+ fun <- ggplot2::geom_jitter
+ .geom_halo(fun, ...)
}
#' @rdname geom_point2
#' @export
-geom_pointrange_borderless <- function(...) {
- geom_pointrange(pch = 21, color = .get_theme_bg_color(), ...)
+geom_count_halo <- function(...) {
+ fun <- ggplot2::geom_count
+ .geom_halo(fun, ...)
}
-.get_theme_bg_color <- function() {
- current_theme <- ggplot2::theme_get()
+#' @rdname geom_point2
+#' @export
+geom_pointrange_halo <- function(...) {
+ fun <- ggplot2::geom_pointrange
+ .geom_halo(fun, ...)
+}
+
- if (is.null(current_theme$panel.grid.major)) {
- current_theme$panel.grid.major <- current_theme$panel.grid
+.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 <- dots$shape <- dots$pch <- NULL
+ dots$color <- .get_theme_bg_color()
+
+ fun_args <- c(list(pch = 21), dots)
+ do.call(fun, fun_args)
+}
+
+
+.get_theme_bg_color <- function() {
+ current_theme <- ggplot2::theme_get()
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/man/geom_point2.Rd b/man/geom_point2.Rd
index 17bc5ba68..d42a5ef06 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,11 +51,17 @@ 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
+The color aesthetics for the \verb{*_halo()} functions is \code{"fill"}, not
\code{"color"}. See 'Examples'.
}
\examples{
@@ -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}
}
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 @@
+
+
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 @@
+
+
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..46a4400b6
--- /dev/null
+++ b/tests/testthat/_snaps/vdiffr_geoms_borderless/geom-point-halo-1.svg
@@ -0,0 +1,216 @@
+
+
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
+ )
+})