From 9516283851e1402e780333d9148531c70a35c4ca Mon Sep 17 00:00:00 2001 From: Alboukadel Kassambara Date: Thu, 9 Jul 2026 12:15:39 +0200 Subject: [PATCH] Add a preset argument for publication-grade output in one token New preset argument bundles publication-grade defaults: preset = "publication" sets white cell outlines and the colorblind-safe RdBu palette in a single token. It fills only the arguments the caller did not supply (detected with missing() before any reassignment), so an explicit outline.color, colors, or palette always overrides the preset. Defaults to NULL, leaving every existing call byte-identical. --- NEWS.md | 7 + R/ggcorrplot.R | 22 +- man/ggcorrplot.Rd | 10 +- .../ggcorrplot-works-preset-publication.svg | 345 ++++++++++++++++++ tests/testthat/test-preset.R | 50 +++ tests/testthat/test-vdiffr.R | 6 + 6 files changed, 438 insertions(+), 2 deletions(-) create mode 100644 tests/testthat/_snaps/vdiffr/ggcorrplot-works-preset-publication.svg create mode 100644 tests/testthat/test-preset.R diff --git a/NEWS.md b/NEWS.md index 0b0bf8b..73a0393 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,13 @@ ## New features +- New argument `preset` for publication-grade output in one token: + `ggcorrplot(corr, preset = "publication")` sets white cell outlines and the + colorblind-safe `"RdBu"` palette. It only fills arguments you did not supply, so + anything you pass explicitly (e.g. `outline.color`, `colors`, `palette`) + overrides the preset. Defaults to `NULL` (no preset), leaving existing calls + unchanged. + - New argument `palette` to pick a built-in colorblind-safe diverging palette for the fill gradient: `ggcorrplot(corr, palette = "RdBu")` (or `"PuOr"`). Each is an 11-stop ramp with white at zero and the usual cool = negative / warm = diff --git a/R/ggcorrplot.R b/R/ggcorrplot.R index b30323d..783f002 100644 --- a/R/ggcorrplot.R +++ b/R/ggcorrplot.R @@ -43,6 +43,12 @@ #' ramp, white at zero, cool = negative / warm = positive) and takes precedence #' over \code{colors}. Defaults to \code{NULL} (use \code{colors}), so existing #' calls are unchanged. +#' @param preset optional name of a bundle of publication-grade defaults. The only +#' value, \code{"publication"}, sets white cell outlines and the colorblind-safe +#' \code{"RdBu"} palette in one token. It fills only the arguments you did not +#' supply, so any argument you pass explicitly (e.g. \code{outline.color}, +#' \code{colors}, \code{palette}) overrides the preset. Defaults to \code{NULL} +#' (no preset), leaving existing calls unchanged. #' @param outline.color the outline color of square or circle. Default value is #' "gray". #' @param hc.order logical value. If TRUE, correlation matrix will be hc.ordered @@ -246,7 +252,8 @@ ggcorrplot <- function(corr, lower.method = NULL, upper.method = NULL, hc.rect = NULL, - palette = NULL) { + palette = NULL, + preset = NULL) { type <- match.arg(type) method <- match.arg(method) # Resolve on insig[1] (not match.arg(insig)) so a caller passing the old @@ -256,6 +263,19 @@ ggcorrplot <- function(corr, # "stars" made c("pch", "blank") non-identical. Scalar/partial matching and the # default are unchanged. insig <- match.arg(insig[1], c("pch", "blank", "stars")) + # A preset is a bundle of "publication-grade" defaults (white cell outlines and + # a colorblind-safe diverging palette). It fills ONLY the arguments the caller + # did not supply -- detected with missing() BEFORE any reassignment, so an + # explicit argument always overrides the preset, and preset = NULL (the default) + # changes nothing. This must run above the palette block, which reassigns + # `colors`/`palette`. + if (!is.null(preset)) { + preset <- match.arg(preset, "publication") + if (missing(outline.color)) outline.color <- "white" + # Reach for the preset palette only when the caller pinned neither `palette` + # nor `colors`, so an explicit `colors` is never clobbered. + if (missing(palette) && missing(colors)) palette <- "RdBu" + } # A named colorblind-safe diverging palette is a convenience shortcut for # `colors`: when set (non-NULL, the default), it supplies the fill gradient and # takes precedence over `colors`. `palette = NULL` leaves `colors` untouched, so diff --git a/man/ggcorrplot.Rd b/man/ggcorrplot.Rd index eeeba0d..ac9ce87 100644 --- a/man/ggcorrplot.Rd +++ b/man/ggcorrplot.Rd @@ -44,7 +44,8 @@ ggcorrplot( lower.method = NULL, upper.method = NULL, hc.rect = NULL, - palette = NULL + palette = NULL, + preset = NULL ) cor_pmat(x, ..., use = c("pairwise.complete.obs", "everything")) @@ -196,6 +197,13 @@ ramp, white at zero, cool = negative / warm = positive) and takes precedence over \code{colors}. Defaults to \code{NULL} (use \code{colors}), so existing calls are unchanged.} +\item{preset}{optional name of a bundle of publication-grade defaults. The only +value, \code{"publication"}, sets white cell outlines and the colorblind-safe +\code{"RdBu"} palette in one token. It fills only the arguments you did not +supply, so any argument you pass explicitly (e.g. \code{outline.color}, +\code{colors}, \code{palette}) overrides the preset. Defaults to \code{NULL} +(no preset), leaving existing calls unchanged.} + \item{x}{numeric matrix or data frame} \item{...}{other arguments to be passed to the function cor.test.} diff --git a/tests/testthat/_snaps/vdiffr/ggcorrplot-works-preset-publication.svg b/tests/testthat/_snaps/vdiffr/ggcorrplot-works-preset-publication.svg new file mode 100644 index 0000000..055947d --- /dev/null +++ b/tests/testthat/_snaps/vdiffr/ggcorrplot-works-preset-publication.svg @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +-0.9 +-0.8 +-0.8 +0.7 +-0.9 +0.4 +0.7 +0.6 +0.5 +-0.6 +-0.9 +1 +0.9 +0.8 +-0.7 +0.8 +-0.6 +-0.8 +-0.5 +-0.5 +0.5 +-0.8 +0.9 +1 +0.8 +-0.7 +0.9 +-0.4 +-0.7 +-0.6 +-0.6 +0.4 +-0.8 +0.8 +0.8 +1 +-0.4 +0.7 +-0.7 +-0.7 +-0.2 +-0.1 +0.7 +0.7 +-0.7 +-0.7 +-0.4 +1 +-0.7 +0.1 +0.4 +0.7 +0.7 +-0.1 +-0.9 +0.8 +0.9 +0.7 +-0.7 +1 +-0.2 +-0.6 +-0.7 +-0.6 +0.4 +0.4 +-0.6 +-0.4 +-0.7 +0.1 +-0.2 +1 +0.7 +-0.2 +-0.2 +-0.7 +0.7 +-0.8 +-0.7 +-0.7 +0.4 +-0.6 +0.7 +1 +0.2 +0.2 +-0.6 +0.6 +-0.5 +-0.6 +-0.2 +0.7 +-0.7 +-0.2 +0.2 +1 +0.8 +0.1 +0.5 +-0.5 +-0.6 +-0.1 +0.7 +-0.6 +-0.2 +0.2 +0.8 +1 +0.3 +-0.6 +0.5 +0.4 +0.7 +-0.1 +0.4 +-0.7 +-0.6 +0.1 +0.3 +1 + + +mpg +cyl +disp +hp +drat +wt +qsec +vs +am +gear +carb +mpg +cyl +disp +hp +drat +wt +qsec +vs +am +gear +carb +Corr + + + + + + + + + + + +-1.0 +-0.5 +0.0 +0.5 +1.0 +ggcorrplot works - preset publication + + diff --git a/tests/testthat/test-preset.R b/tests/testthat/test-preset.R new file mode 100644 index 0000000..2678714 --- /dev/null +++ b/tests/testthat/test-preset.R @@ -0,0 +1,50 @@ +# preset = "publication": a one-token bundle of publication-grade defaults (white +# cell outlines + the colorblind-safe RdBu palette). It fills only the arguments +# the caller did NOT supply, so explicit arguments always win, and preset = NULL +# (the default) changes nothing. + +corr <- round(cor(mtcars), 1) +fill <- function(p) ggplot2::ggplot_build(p)$data[[1]]$fill +outline <- function(p) { + i <- which(vapply(p$layers, function(l) class(l$geom)[1], "") %in% c("GeomTile", "GeomPoint"))[1] + p$layers[[i]]$aes_params$colour +} + +test_that("preset = 'publication' sets white outlines and the RdBu palette in one token", { + p <- ggcorrplot(corr, preset = "publication") + expect_identical(outline(p), "white") + expect_equal(fill(p), fill(ggcorrplot(corr, palette = "RdBu", outline.color = "white"))) +}) + +test_that("preset = NULL (the default) leaves every existing call unchanged", { + expect_equal( + ggplot2::ggplot_build(ggcorrplot(corr))$data, + ggplot2::ggplot_build(ggcorrplot(corr, preset = NULL))$data + ) + # the default outline is still gray, not white + expect_identical(outline(ggcorrplot(corr)), "gray") +}) + +test_that("an explicit outline.color overrides the preset", { + expect_identical(outline(ggcorrplot(corr, preset = "publication", outline.color = "black")), "black") +}) + +test_that("an explicit colors overrides the preset palette (colors is not clobbered)", { + # user pins colors -> preset must NOT swap in RdBu + expect_equal( + fill(ggcorrplot(corr, preset = "publication", colors = c("blue", "white", "red"))), + fill(ggcorrplot(corr)) + ) +}) + +test_that("an explicit palette overrides the preset palette", { + expect_equal( + fill(ggcorrplot(corr, preset = "publication", palette = "PuOr")), + fill(ggcorrplot(corr, palette = "PuOr")) + ) +}) + +test_that("an unknown preset errors", { + expect_error(ggcorrplot(corr, preset = "fancy")) + expect_error(ggcorrplot(corr, preset = "Publication")) # match.arg is case-sensitive +}) diff --git a/tests/testthat/test-vdiffr.R b/tests/testthat/test-vdiffr.R index 692af0b..209a902 100644 --- a/tests/testthat/test-vdiffr.R +++ b/tests/testthat/test-vdiffr.R @@ -66,5 +66,11 @@ if (getRversion() >= "4.1") { title = "ggcorrplot works - palette RdBu", fig = ggcorrplot(corr, palette = "RdBu", outline.color = "white", lab = TRUE) ) + + set.seed(123) + vdiffr::expect_doppelganger( + title = "ggcorrplot works - preset publication", + fig = ggcorrplot(corr, preset = "publication", lab = TRUE) + ) }) }