From 813d0bd8c7d4df3b3cba170de54233076b346c1c Mon Sep 17 00:00:00 2001 From: Kara Woo Date: Thu, 20 Aug 2020 13:39:25 -0700 Subject: [PATCH] Set file background from plot theme (#4164) * Add bg argument that defaults to plot.background fill colour * Add NEWS bullet * Add test for background color of saved file --- DESCRIPTION | 3 ++- NEWS.md | 3 +++ R/save.r | 9 +++++++-- man/ggsave.Rd | 4 ++++ tests/testthat/test-ggsave.R | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 383dd5a511..f07f473b5b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -63,7 +63,8 @@ Suggests: sf (>= 0.7-3), svglite (>= 1.2.0.9001), testthat (>= 2.1.0), - vdiffr (>= 0.3.0) + vdiffr (>= 0.3.0), + xml2 Enhances: sp License: GPL-2 | file LICENSE URL: http://ggplot2.tidyverse.org, https://github.com/tidyverse/ggplot2 diff --git a/NEWS.md b/NEWS.md index ff33dc03d2..d1dacb18ea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # ggplot2 (development version) +* `ggsave()` now sets the default background to match the fill value of the + `plot.background` theme element (@karawoo, #4057) + * Extended `stat_ecdf()` to calculate the cdf from either x or y instead from y only (@jgjl, #4005). * Fixed a bug in `labeller()` so that `.default` is passed to `as_labeller()` diff --git a/R/save.r b/R/save.r index 51435fbfb6..1bdd11381c 100644 --- a/R/save.r +++ b/R/save.r @@ -38,6 +38,8 @@ #' @param limitsize When `TRUE` (the default), `ggsave()` will not #' save images larger than 50x50 inches, to prevent the common error of #' specifying dimensions in pixels. +#' @param bg Background colour. If `NULL`, uses the `plot.background` fill value +#' from the plot theme. #' @param ... Other arguments passed on to the graphics device function, #' as specified by `device`. #' @export @@ -74,7 +76,7 @@ ggsave <- function(filename, plot = last_plot(), device = NULL, path = NULL, scale = 1, width = NA, height = NA, units = c("in", "cm", "mm"), - dpi = 300, limitsize = TRUE, ...) { + dpi = 300, limitsize = TRUE, bg = NULL, ...) { dpi <- parse_dpi(dpi) dev <- plot_dev(device, filename, dpi = dpi) @@ -84,8 +86,11 @@ ggsave <- function(filename, plot = last_plot(), if (!is.null(path)) { filename <- file.path(path, filename) } + if (is_null(bg)) { + bg <- calc_element("plot.background", plot_theme(plot))$fill + } old_dev <- grDevices::dev.cur() - dev(filename = filename, width = dim[1], height = dim[2], ...) + dev(filename = filename, width = dim[1], height = dim[2], bg = bg, ...) on.exit(utils::capture.output({ grDevices::dev.off() if (old_dev > 1) grDevices::dev.set(old_dev) # restore old device unless null device diff --git a/man/ggsave.Rd b/man/ggsave.Rd index 7dfc28f8a0..8d6a6102b4 100644 --- a/man/ggsave.Rd +++ b/man/ggsave.Rd @@ -15,6 +15,7 @@ ggsave( units = c("in", "cm", "mm"), dpi = 300, limitsize = TRUE, + bg = NULL, ... ) } @@ -43,6 +44,9 @@ If not supplied, uses the size of current graphics device.} save images larger than 50x50 inches, to prevent the common error of specifying dimensions in pixels.} +\item{bg}{Background colour. If \code{NULL}, uses the \code{plot.background} fill value +from the plot theme.} + \item{...}{Other arguments passed on to the graphics device function, as specified by \code{device}.} } diff --git a/tests/testthat/test-ggsave.R b/tests/testthat/test-ggsave.R index 03502ca721..4a4fbe0667 100644 --- a/tests/testthat/test-ggsave.R +++ b/tests/testthat/test-ggsave.R @@ -28,6 +28,20 @@ test_that("ggsave restores previous graphics device", { expect_identical(old_dev, dev.cur()) }) +test_that("ggsave uses theme background as image background", { + path <- tempfile() + on.exit(unlink(path)) + p <- ggplot(mtcars, aes(disp, mpg)) + + geom_point() + + coord_fixed() + + theme(plot.background = element_rect(fill = "#00CCCC")) + ggsave(path, p, device = "svg", width = 5, height = 5) + img <- xml2::read_xml(path) + # Find background rect in svg + bg <- as.character(xml2::xml_find_first(img, xpath = "d1:rect/@style")) + expect_true(grepl("fill: #00CCCC", bg)) +}) + # plot_dim --------------------------------------------------------------- test_that("guesses and informs if dim not specified", {