From a2ef967f5dff2ff5ead0da2f8fee4eb3d60aff79 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Sep 2024 15:06:39 +0200 Subject: [PATCH 1/7] inheritance of NA-margins --- R/theme.R | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/R/theme.R b/R/theme.R index 43c379f9b6..b094f30f8b 100644 --- a/R/theme.R +++ b/R/theme.R @@ -864,6 +864,15 @@ combine_elements <- function(e1, e2) { return(e1) } + if (inherits(e1, "margin") && inherits(e2, "margin")) { + if (anyNA(e2)) { + e2[is.na(e2)] <- unit(0, "pt") + } + if (anyNA(e1)) { + e1[is.na(e1)] <- e2[is.na(e1)] + } + } + # If neither of e1 or e2 are element_* objects, return e1 if (!inherits(e1, "element") && !inherits(e2, "element")) { return(e1) @@ -893,6 +902,10 @@ combine_elements <- function(e1, e2) { e1$linewidth <- e2$linewidth * unclass(e1$linewidth) } + if (inherits(e1, "element_text")) { + e1$margin <- combine_elements(e1$margin, e2$margin) + } + # If e2 is 'richer' than e1, fill e2 with e1 parameters if (is.subclass(e2, e1)) { new <- defaults(e1, e2) From 4ce398f5427dfed332001209d9dee4c9f7b8568c Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Sep 2024 15:33:09 +0200 Subject: [PATCH 2/7] add `part_margin()` function --- NAMESPACE | 1 + R/margins.R | 7 +++++++ R/theme-elements.R | 2 +- man/element.Rd | 5 ++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index f0ccf3bec1..7f3120db86 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -496,6 +496,7 @@ export(new_guide) export(old_guide) export(panel_cols) export(panel_rows) +export(part_margin) export(pattern_alpha) export(position_dodge) export(position_dodge2) diff --git a/R/margins.R b/R/margins.R index 176072b4de..2640b8e1c5 100644 --- a/R/margins.R +++ b/R/margins.R @@ -8,6 +8,13 @@ margin <- function(t = 0, r = 0, b = 0, l = 0, unit = "pt") { class(u) <- c("margin", class(u)) u } + +#' @rdname element +#' @export +part_margin <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { + margin(t = t, r = r, b = b, l = l, unit = unit) +} + is.margin <- function(x) { inherits(x, "margin") } diff --git a/R/theme-elements.R b/R/theme-elements.R index 747bb0cf78..abcd2168b2 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -11,7 +11,7 @@ #' - `element_geom()`: defaults for drawing layers. #' #' `rel()` is used to specify sizes relative to the parent, -#' `margin()` is used to specify the margins of elements. +#' `margin()` and `part_margin()` are used to specify the margins of elements. #' #' @param fill Fill colour. #' @param colour,color Line/border colour. Color is an alias for colour. diff --git a/man/element.Rd b/man/element.Rd index adb1b7eb22..4bbb1d492c 100644 --- a/man/element.Rd +++ b/man/element.Rd @@ -8,6 +8,7 @@ \alias{element_geom} \alias{rel} \alias{margin} +\alias{part_margin} \title{Theme elements} \usage{ element_blank() @@ -66,6 +67,8 @@ element_geom( rel(x) margin(t = 0, r = 0, b = 0, l = 0, unit = "pt") + +part_margin(t = NA, r = NA, b = NA, l = NA, unit = "pt") } \arguments{ \item{fill}{Fill colour.} @@ -145,7 +148,7 @@ specify the display of how non-data components of the plot are drawn. } \code{rel()} is used to specify sizes relative to the parent, -\code{margin()} is used to specify the margins of elements. +\code{margin()} and \code{part_margin()} are used to specify the margins of elements. } \examples{ plot <- ggplot(mpg, aes(displ, hwy)) + geom_point() From 63cc7e4c8979964d142dfe899dc0c73d6a13cf9e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Sep 2024 15:39:29 +0200 Subject: [PATCH 3/7] setup merge method for margins --- NAMESPACE | 1 + R/theme.R | 12 ++++++++++++ man/merge_element.Rd | 3 +++ 3 files changed, 16 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 7f3120db86..4696b0e590 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -96,6 +96,7 @@ S3method(makeContext,dotstackGrob) S3method(merge_element,default) S3method(merge_element,element) S3method(merge_element,element_blank) +S3method(merge_element,margin) S3method(pattern_alpha,GridPattern) S3method(pattern_alpha,GridTilingPattern) S3method(pattern_alpha,default) diff --git a/R/theme.R b/R/theme.R index b094f30f8b..7e3f30995a 100644 --- a/R/theme.R +++ b/R/theme.R @@ -831,6 +831,18 @@ merge_element.element <- function(new, old) { new } +#' @rdname merge_element +#' @export +merge_element.margin <- function(new, old) { + if (is.null(old) || inherits(old, "element_blank")) { + return(new) + } + if (anyNA(new)) { + new[is.na(new)] <- old[is.na(new)] + } + new +} + #' Combine the properties of two elements #' #' @param e1 An element object diff --git a/man/merge_element.Rd b/man/merge_element.Rd index 4071e6c69a..ca993eeec3 100644 --- a/man/merge_element.Rd +++ b/man/merge_element.Rd @@ -5,6 +5,7 @@ \alias{merge_element.default} \alias{merge_element.element_blank} \alias{merge_element.element} +\alias{merge_element.margin} \title{Merge a parent element into a child element} \usage{ merge_element(new, old) @@ -14,6 +15,8 @@ merge_element(new, old) \method{merge_element}{element_blank}(new, old) \method{merge_element}{element}(new, old) + +\method{merge_element}{margin}(new, old) } \arguments{ \item{new}{The child element in the theme hierarchy} From 1fb967d4331db71622048dd8b866379eb3c9a80f Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Sep 2024 15:40:50 +0200 Subject: [PATCH 4/7] add test --- tests/testthat/test-theme.R | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/testthat/test-theme.R b/tests/testthat/test-theme.R index 36ad577c65..9d11740620 100644 --- a/tests/testthat/test-theme.R +++ b/tests/testthat/test-theme.R @@ -616,6 +616,22 @@ test_that("complete_theme completes a theme", { reset_theme_settings() }) +test_that("part_margin() mechanics work as expected", { + + t <- theme_gray() + + theme(plot.margin = part_margin(b = 11)) + + test <- calc_element("plot.margin", t) + expect_equal(as.numeric(test), c(5.5, 5.5, 11, 5.5)) + + t <- theme_gray() + + theme(margins = part_margin(b = 11)) + + test <- calc_element("plot.margin", t) + expect_equal(as.numeric(test), c(5.5, 5.5, 11, 5.5)) + +}) + # Visual tests ------------------------------------------------------------ test_that("aspect ratio is honored", { From ad51647a072dfea40dd55a9bc8df91b31cc9e23e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Sep 2024 15:43:06 +0200 Subject: [PATCH 5/7] add news bullet --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5df6059f0f..1d09ca6b13 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* Theme margins can have NA-units to inherit from parent elements. The new + function `part_margin()` has NA-units as default (@teunbrand, #6155) * Built-in `theme_*()` functions now have `ink` and `paper` arguments to control foreground and background colours respectively (@teunbrand) * The `summary()` method for ggplots is now more terse about facets From b4987341844adc9342ea4e9192b60c48f6964748 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 20 Sep 2024 08:48:47 +0200 Subject: [PATCH 6/7] rename `part_margin()` to `margin_part()` --- NAMESPACE | 2 +- R/margins.R | 2 +- man/element.Rd | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 4696b0e590..304e7ef6ac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -485,6 +485,7 @@ export(layer_sf) export(lims) export(map_data) export(margin) +export(margin_part) export(max_height) export(max_width) export(mean_cl_boot) @@ -497,7 +498,6 @@ export(new_guide) export(old_guide) export(panel_cols) export(panel_rows) -export(part_margin) export(pattern_alpha) export(position_dodge) export(position_dodge2) diff --git a/R/margins.R b/R/margins.R index 2640b8e1c5..a6637f3e57 100644 --- a/R/margins.R +++ b/R/margins.R @@ -11,7 +11,7 @@ margin <- function(t = 0, r = 0, b = 0, l = 0, unit = "pt") { #' @rdname element #' @export -part_margin <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { +margin_part <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { margin(t = t, r = r, b = b, l = l, unit = unit) } diff --git a/man/element.Rd b/man/element.Rd index 4bbb1d492c..b6e530d198 100644 --- a/man/element.Rd +++ b/man/element.Rd @@ -8,7 +8,7 @@ \alias{element_geom} \alias{rel} \alias{margin} -\alias{part_margin} +\alias{margin_part} \title{Theme elements} \usage{ element_blank() @@ -68,7 +68,7 @@ rel(x) margin(t = 0, r = 0, b = 0, l = 0, unit = "pt") -part_margin(t = NA, r = NA, b = NA, l = NA, unit = "pt") +margin_part(t = NA, r = NA, b = NA, l = NA, unit = "pt") } \arguments{ \item{fill}{Fill colour.} From 4cf042682b48008460b06b15a19abd2035e1912d Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 20 Sep 2024 08:48:47 +0200 Subject: [PATCH 7/7] rename `part_margin()` to `margin_part()` --- NAMESPACE | 2 +- NEWS.md | 2 +- R/margins.R | 2 +- R/theme-elements.R | 2 +- man/element.Rd | 6 +++--- tests/testthat/test-theme.R | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 4696b0e590..304e7ef6ac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -485,6 +485,7 @@ export(layer_sf) export(lims) export(map_data) export(margin) +export(margin_part) export(max_height) export(max_width) export(mean_cl_boot) @@ -497,7 +498,6 @@ export(new_guide) export(old_guide) export(panel_cols) export(panel_rows) -export(part_margin) export(pattern_alpha) export(position_dodge) export(position_dodge2) diff --git a/NEWS.md b/NEWS.md index 1d09ca6b13..0bc74080a1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ # ggplot2 (development version) * Theme margins can have NA-units to inherit from parent elements. The new - function `part_margin()` has NA-units as default (@teunbrand, #6155) + function `margin_part()` has NA-units as default (@teunbrand, #6155) * Built-in `theme_*()` functions now have `ink` and `paper` arguments to control foreground and background colours respectively (@teunbrand) * The `summary()` method for ggplots is now more terse about facets diff --git a/R/margins.R b/R/margins.R index 2640b8e1c5..a6637f3e57 100644 --- a/R/margins.R +++ b/R/margins.R @@ -11,7 +11,7 @@ margin <- function(t = 0, r = 0, b = 0, l = 0, unit = "pt") { #' @rdname element #' @export -part_margin <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { +margin_part <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { margin(t = t, r = r, b = b, l = l, unit = unit) } diff --git a/R/theme-elements.R b/R/theme-elements.R index abcd2168b2..05e882a078 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -11,7 +11,7 @@ #' - `element_geom()`: defaults for drawing layers. #' #' `rel()` is used to specify sizes relative to the parent, -#' `margin()` and `part_margin()` are used to specify the margins of elements. +#' `margin()` and `margin_part()` are used to specify the margins of elements. #' #' @param fill Fill colour. #' @param colour,color Line/border colour. Color is an alias for colour. diff --git a/man/element.Rd b/man/element.Rd index 4bbb1d492c..6d78b6ae1e 100644 --- a/man/element.Rd +++ b/man/element.Rd @@ -8,7 +8,7 @@ \alias{element_geom} \alias{rel} \alias{margin} -\alias{part_margin} +\alias{margin_part} \title{Theme elements} \usage{ element_blank() @@ -68,7 +68,7 @@ rel(x) margin(t = 0, r = 0, b = 0, l = 0, unit = "pt") -part_margin(t = NA, r = NA, b = NA, l = NA, unit = "pt") +margin_part(t = NA, r = NA, b = NA, l = NA, unit = "pt") } \arguments{ \item{fill}{Fill colour.} @@ -148,7 +148,7 @@ specify the display of how non-data components of the plot are drawn. } \code{rel()} is used to specify sizes relative to the parent, -\code{margin()} and \code{part_margin()} are used to specify the margins of elements. +\code{margin()} and \code{margin_part()} are used to specify the margins of elements. } \examples{ plot <- ggplot(mpg, aes(displ, hwy)) + geom_point() diff --git a/tests/testthat/test-theme.R b/tests/testthat/test-theme.R index 9d11740620..a98c0fb3f7 100644 --- a/tests/testthat/test-theme.R +++ b/tests/testthat/test-theme.R @@ -616,16 +616,16 @@ test_that("complete_theme completes a theme", { reset_theme_settings() }) -test_that("part_margin() mechanics work as expected", { +test_that("margin_part() mechanics work as expected", { t <- theme_gray() + - theme(plot.margin = part_margin(b = 11)) + theme(plot.margin = margin_part(b = 11)) test <- calc_element("plot.margin", t) expect_equal(as.numeric(test), c(5.5, 5.5, 11, 5.5)) t <- theme_gray() + - theme(margins = part_margin(b = 11)) + theme(margins = margin_part(b = 11)) test <- calc_element("plot.margin", t) expect_equal(as.numeric(test), c(5.5, 5.5, 11, 5.5))