From 14f1dadc7b4f9d0014c39903ca83f9d017317a9a Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 25 Jun 2024 14:48:55 +0200 Subject: [PATCH 1/8] generalise angle heuristic --- R/guide-axis.R | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/R/guide-axis.R b/R/guide-axis.R index dc57ffd23e..73a5c577b7 100644 --- a/R/guide-axis.R +++ b/R/guide-axis.R @@ -568,49 +568,50 @@ axis_label_priority_between <- function(x, y) { ) } -#' Override axis text angle and alignment +#' Override text angle and alignment #' +#' @param element An `element_text()` #' @param axis_position One of bottom, left, top, or right #' @param angle The text angle, or NULL to override nothing #' #' @return An [element_text()] that contains parameters that should be #' overridden from the user- or theme-supplied element. #' @noRd -#' -axis_label_element_overrides <- function(axis_position, angle = NULL) { - - if (is.null(angle) || is.waive(angle)) { - return(element_text(angle = NULL, hjust = NULL, vjust = NULL)) +label_angle_heuristic <- function(element, position, angle) { + if (!inherits(element, "element_text") + || is.null(position) + || is.null(angle %|W|% NULL)) { + return(element) } - check_number_decimal(angle) angle <- angle %% 360 - arg_match0( - axis_position, - c("bottom", "left", "top", "right") - ) - if (axis_position == "bottom") { + arg_match0(position, .trbl) + + if (position == "bottom") { hjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 1 else 0 vjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 0 else 1 - } else if (axis_position == "left") { + } else if (position == "left") { hjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 0 else 1 vjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 0 else 1 - } else if (axis_position == "top") { + } else if (position == "top") { hjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 0 else 1 vjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 1 else 0 - } else if (axis_position == "right") { + } else if (position == "right") { hjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 1 else 0 vjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 1 else 0 } - element_text(angle = angle, hjust = hjust, vjust = vjust) + element$angle <- angle %||% element$angle + element$hjust <- hjust %||% element$hjust + element$vjust <- vjust %||% element$vjust + element } From 66ba5252fa662d067ea0f6e05c0ccf0c0a8daaaa Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 25 Jun 2024 14:49:08 +0200 Subject: [PATCH 2/8] apply heuristic --- R/guide-axis.R | 17 ++--------------- R/guide-legend.R | 3 +++ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/R/guide-axis.R b/R/guide-axis.R index 73a5c577b7..15954120c0 100644 --- a/R/guide-axis.R +++ b/R/guide-axis.R @@ -254,21 +254,8 @@ GuideAxis <- ggproto( }, override_elements = function(params, elements, theme) { - label <- elements$text - if (!inherits(label, "element_text")) { - return(elements) - } - label_overrides <- axis_label_element_overrides( - params$position, params$angle - ) - # label_overrides is an element_text, but label_element may not be; - # to merge the two elements, we just copy angle, hjust, and vjust - # unless their values are NULL - label$angle <- label_overrides$angle %||% label$angle - label$hjust <- label_overrides$hjust %||% label$hjust - label$vjust <- label_overrides$vjust %||% label$vjust - - elements$text <- label + elements$text <- + label_angle_heuristic(elements$text, params$position, params$angle) return(elements) }, diff --git a/R/guide-legend.R b/R/guide-legend.R index 95dba1cfa0..220e6a2370 100644 --- a/R/guide-legend.R +++ b/R/guide-legend.R @@ -374,6 +374,9 @@ GuideLegend <- ggproto( ggname("legend.key", element_grob(elements$key)) } + elements$text <- + label_angle_heuristic(elements$text, elements$text_position, params$angle) + elements }, From 686bdb403976cba61dd9a461b46bdc6ac7910ae5 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 25 Jun 2024 14:56:05 +0200 Subject: [PATCH 3/8] parameter plumbing --- R/guide-bins.R | 3 +++ R/guide-colorbar.R | 3 +++ R/guide-colorsteps.R | 2 ++ 3 files changed, 8 insertions(+) diff --git a/R/guide-bins.R b/R/guide-bins.R index e2bd0db428..a6ea2d7d90 100644 --- a/R/guide-bins.R +++ b/R/guide-bins.R @@ -65,6 +65,7 @@ guide_bins <- function( theme = NULL, # general + angle = NULL, position = NULL, direction = NULL, override.aes = list(), @@ -85,6 +86,7 @@ guide_bins <- function( theme = theme, # general + angle = angle, position = position, direction = direction, override.aes = rename_aes(override.aes), @@ -115,6 +117,7 @@ GuideBins <- ggproto( default_axis = element_line("black", linewidth = (0.5 / .pt)), default_ticks = element_line(inherit.blank = TRUE), + angle = NULL, direction = NULL, override.aes = list(), reverse = FALSE, diff --git a/R/guide-colorbar.R b/R/guide-colorbar.R index ca63f29b54..9af12785d9 100644 --- a/R/guide-colorbar.R +++ b/R/guide-colorbar.R @@ -124,6 +124,7 @@ guide_colourbar <- function( alpha = NA, draw.ulim = TRUE, draw.llim = TRUE, + angle = NULL, position = NULL, direction = NULL, reverse = FALSE, @@ -151,6 +152,7 @@ guide_colourbar <- function( nbin = nbin, display = display, alpha = alpha, + angle = angle, draw_lim = c(isTRUE(draw.llim), isTRUE(draw.ulim)), position = position, direction = direction, @@ -193,6 +195,7 @@ GuideColourbar <- ggproto( direction = NULL, reverse = FALSE, order = 0, + angle = NULL, # parameter name = "colourbar", diff --git a/R/guide-colorsteps.R b/R/guide-colorsteps.R index de10b51a04..b1005b41e7 100644 --- a/R/guide-colorsteps.R +++ b/R/guide-colorsteps.R @@ -49,6 +49,7 @@ guide_coloursteps <- function( title = waiver(), theme = NULL, alpha = NA, + angle = NULL, even.steps = TRUE, show.limits = NULL, direction = NULL, @@ -65,6 +66,7 @@ guide_coloursteps <- function( title = title, theme = theme, alpha = alpha, + angle = angle, even.steps = even.steps, show.limits = show.limits, direction = direction, From c753cb15f45d33533ad4452c8226578ad08e7ace Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 25 Jun 2024 15:01:03 +0200 Subject: [PATCH 4/8] document --- R/guide-bins.R | 4 ++++ R/guide-colorbar.R | 4 ++++ man/guide_bins.Rd | 6 ++++++ man/guide_colourbar.Rd | 7 +++++++ man/guide_coloursteps.Rd | 7 +++++++ 5 files changed, 28 insertions(+) diff --git a/R/guide-bins.R b/R/guide-bins.R index a6ea2d7d90..d519ca3c5e 100644 --- a/R/guide-bins.R +++ b/R/guide-bins.R @@ -11,6 +11,10 @@ NULL #' guide if they are mapped in the same way. #' #' @inheritParams guide_legend +#' @param angle Overrules the theme settings to automatically apply appropriate +#' `hjust` and `vjust` for angled legend text. Can be a single number +#' representing the text angle in degrees, or `NULL` to not overrule the +#' settings (default). #' @param show.limits Logical. Should the limits of the scale be shown with #' labels and ticks. Default is `NULL` meaning it will take the value from the #' scale. This argument is ignored if `labels` is given as a vector of diff --git a/R/guide-colorbar.R b/R/guide-colorbar.R index 9af12785d9..00b32ec9ea 100644 --- a/R/guide-colorbar.R +++ b/R/guide-colorbar.R @@ -32,6 +32,10 @@ NULL #' @param alpha A numeric between 0 and 1 setting the colour transparency of #' the bar. Use `NA` to preserve the alpha encoded in the colour itself #' (default). +#' @param angle Overrules the theme settings to automatically apply appropriate +#' `hjust` and `vjust` for angled legend text. Can be a single number +#' representing the text angle in degrees, or `NULL` to not overrule the +#' settings (default). #' @param draw.ulim A logical specifying if the upper limit tick marks should #' be visible. #' @param draw.llim A logical specifying if the lower limit tick marks should diff --git a/man/guide_bins.Rd b/man/guide_bins.Rd index ead7b8a099..8ee5311445 100644 --- a/man/guide_bins.Rd +++ b/man/guide_bins.Rd @@ -7,6 +7,7 @@ guide_bins( title = waiver(), theme = NULL, + angle = NULL, position = NULL, direction = NULL, override.aes = list(), @@ -26,6 +27,11 @@ specified in \code{\link[=labs]{labs()}} is used for the title.} differently from the plot's theme settings. The \code{theme} argument in the guide overrides, and is combined with, the plot's theme.} +\item{angle}{Overrules the theme settings to automatically apply appropriate +\code{hjust} and \code{vjust} for angled legend text. Can be a single number +representing the text angle in degrees, or \code{NULL} to not overrule the +settings (default).} + \item{position}{A character string indicating where the legend should be placed relative to the plot panels.} diff --git a/man/guide_colourbar.Rd b/man/guide_colourbar.Rd index 8e29943a44..9a441f39cc 100644 --- a/man/guide_colourbar.Rd +++ b/man/guide_colourbar.Rd @@ -14,6 +14,7 @@ guide_colourbar( alpha = NA, draw.ulim = TRUE, draw.llim = TRUE, + angle = NULL, position = NULL, direction = NULL, reverse = FALSE, @@ -31,6 +32,7 @@ guide_colorbar( alpha = NA, draw.ulim = TRUE, draw.llim = TRUE, + angle = NULL, position = NULL, direction = NULL, reverse = FALSE, @@ -77,6 +79,11 @@ be visible.} \item{draw.llim}{A logical specifying if the lower limit tick marks should be visible.} +\item{angle}{Overrules the theme settings to automatically apply appropriate +\code{hjust} and \code{vjust} for angled legend text. Can be a single number +representing the text angle in degrees, or \code{NULL} to not overrule the +settings (default).} + \item{position}{A character string indicating where the legend should be placed relative to the plot panels.} diff --git a/man/guide_coloursteps.Rd b/man/guide_coloursteps.Rd index 97e66d6207..3219e533b4 100644 --- a/man/guide_coloursteps.Rd +++ b/man/guide_coloursteps.Rd @@ -9,6 +9,7 @@ guide_coloursteps( title = waiver(), theme = NULL, alpha = NA, + angle = NULL, even.steps = TRUE, show.limits = NULL, direction = NULL, @@ -22,6 +23,7 @@ guide_colorsteps( title = waiver(), theme = NULL, alpha = NA, + angle = NULL, even.steps = TRUE, show.limits = NULL, direction = NULL, @@ -45,6 +47,11 @@ guide overrides, and is combined with, the plot's theme.} the bar. Use \code{NA} to preserve the alpha encoded in the colour itself (default).} +\item{angle}{Overrules the theme settings to automatically apply appropriate +\code{hjust} and \code{vjust} for angled legend text. Can be a single number +representing the text angle in degrees, or \code{NULL} to not overrule the +settings (default).} + \item{even.steps}{Should the rendered size of the bins be equal, or should they be proportional to their length in the data space? Defaults to \code{TRUE}} From f2b4113e3e3eedf4dad1e99e206540c78db75d3b Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 25 Jun 2024 15:02:20 +0200 Subject: [PATCH 5/8] add news bullet --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 80d4dd7d02..e4f7198313 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # ggplot2 (development version) +* `guide_bins()`, `guide_colourbar()` and `guide_coloursteps()` gain an `angle` + argument to overrule theme settings, similar to `guide_axis(angle)` + (@teunbrand, #4594). * (internal) rearranged the code of `Facet$draw_paensl()` method (@teunbrand). * `geom_rug()` prints a warning when `na.rm = FALSE`, as per documentation (@pn317, #5905) * `position_dodge(preserve = "single")` now handles multi-row geoms better, From d4ffad68f3194d1d36dd11a13ed00f9f4e2887a7 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 11 Jul 2024 00:28:24 +0200 Subject: [PATCH 6/8] digusting simplification --- R/guide-axis.R | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/R/guide-axis.R b/R/guide-axis.R index 15954120c0..dc79ede510 100644 --- a/R/guide-axis.R +++ b/R/guide-axis.R @@ -570,32 +570,17 @@ label_angle_heuristic <- function(element, position, angle) { || is.null(angle %|W|% NULL)) { return(element) } - check_number_decimal(angle) - angle <- angle %% 360 - arg_match0(position, .trbl) - if (position == "bottom") { - - hjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 1 else 0 - vjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 0 else 1 - - } else if (position == "left") { - - hjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 0 else 1 - vjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 0 else 1 - - } else if (position == "top") { - - hjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 0 else 1 - vjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 1 else 0 - - } else if (position == "right") { + check_number_decimal(angle) + radian <- deg2rad(angle) + digits <- 3 - hjust = if (angle %in% c(90, 270)) 0.5 else if (angle > 90 & angle < 270) 1 else 0 - vjust = if (angle %in% c(0, 180)) 0.5 else if (angle < 180) 1 else 0 + cosine <- sign(round(cos(radian), digits)) / 2 + 0.5 + sine <- sign(round(sin(radian), digits)) / 2 + 0.5 - } + hjust <- switch(position, left = cosine, right = 1 - cosine, top = 1 - sine, sine) + vjust <- switch(position, left = 1 - sine, right = sine, top = 1 - cosine, cosine) element$angle <- angle %||% element$angle element$hjust <- hjust %||% element$hjust From 4269e5cc87860404d33773cd134db69378cca67b Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 11 Jul 2024 00:40:04 +0200 Subject: [PATCH 7/8] add comments for future generations --- R/guide-axis.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/R/guide-axis.R b/R/guide-axis.R index dc79ede510..6c77d8aa6c 100644 --- a/R/guide-axis.R +++ b/R/guide-axis.R @@ -576,9 +576,14 @@ label_angle_heuristic <- function(element, position, angle) { radian <- deg2rad(angle) digits <- 3 + # Taking the sign of the (co)sine snaps the value to c(-1, 0, 1) + # Doing `x / 2 + 0.5` rescales it to c(0, 0.5, 1), which are good values for justification + # The rounding step ensures we can get (co)sine to exact 0 so it can become 0.5 + # which we need for center-justifications cosine <- sign(round(cos(radian), digits)) / 2 + 0.5 sine <- sign(round(sin(radian), digits)) / 2 + 0.5 + # Depending on position, we might need to swap or flip justification values hjust <- switch(position, left = cosine, right = 1 - cosine, top = 1 - sine, sine) vjust <- switch(position, left = 1 - sine, right = sine, top = 1 - cosine, cosine) From 8396b5f7e1c4a088b1b10f075587d5adb78c88d3 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 11 Jul 2024 09:16:50 +0200 Subject: [PATCH 8/8] accept phase-shift in angles --- .../coord_sf/coord-sf-with-custom-guides.svg | 42 +++++----- .../guides/axis-guides-negative-rotation.svg | 80 +++++++++---------- ...axis-guides-vertical-negative-rotation.svg | 80 +++++++++---------- 3 files changed, 101 insertions(+), 101 deletions(-) diff --git a/tests/testthat/_snaps/coord_sf/coord-sf-with-custom-guides.svg b/tests/testthat/_snaps/coord_sf/coord-sf-with-custom-guides.svg index b38125acd3..78e321d395 100644 --- a/tests/testthat/_snaps/coord_sf/coord-sf-with-custom-guides.svg +++ b/tests/testthat/_snaps/coord_sf/coord-sf-with-custom-guides.svg @@ -47,27 +47,27 @@ -80 -° -W -79 -° -W -78 -° -W -77 -° -W -76 -° -W -75 -° -W -40 -° -N +80 +° +W +79 +° +W +78 +° +W +77 +° +W +76 +° +W +75 +° +W +40 +° +N 35 ° N diff --git a/tests/testthat/_snaps/guides/axis-guides-negative-rotation.svg b/tests/testthat/_snaps/guides/axis-guides-negative-rotation.svg index f5ad2b2273..8902fa04cd 100644 --- a/tests/testthat/_snaps/guides/axis-guides-negative-rotation.svg +++ b/tests/testthat/_snaps/guides/axis-guides-negative-rotation.svg @@ -70,16 +70,16 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 @@ -91,16 +91,16 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 @@ -112,27 +112,27 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 diff --git a/tests/testthat/_snaps/guides/axis-guides-vertical-negative-rotation.svg b/tests/testthat/_snaps/guides/axis-guides-vertical-negative-rotation.svg index fb7d39a9d3..1d83ebc1e2 100644 --- a/tests/testthat/_snaps/guides/axis-guides-vertical-negative-rotation.svg +++ b/tests/testthat/_snaps/guides/axis-guides-vertical-negative-rotation.svg @@ -70,16 +70,16 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 @@ -91,16 +91,16 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 @@ -112,27 +112,27 @@ -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000 -1,000 -2,000 -3,000 -4,000 -5,000 -6,000 -7,000 -8,000 -9,000 -10,000 +1,000 +2,000 +3,000 +4,000 +5,000 +6,000 +7,000 +8,000 +9,000 +10,000