diff --git a/NEWS.md b/NEWS.md
index 02cbf5465f..713d2198f8 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).
* `coord_*(expand)` can now take a logical vector to control expansion at any
side of the panel (top, right, bottom, left) (@teunbrand, #6020)
* (Breaking) The defaults for all geoms can be set at one in the theme.
@@ -24,7 +27,7 @@
class through new `Coord$draw_panel()` method.
* `theme(strip.clip)` now defaults to `"on"` and is independent of Coord
clipping (@teunbrand, 5952).
-* (internal) rearranged the code of `Facet$draw_paensl()` method (@teunbrand).
+* (internal) rearranged the code of `Facet$draw_panels()` method (@teunbrand).
* Axis labels are now justified across facet panels (@teunbrand, #5820)
* Fixed bug in `stat_function()` so x-axis title now produced automatically
when no data added. (@phispu, #5647).
diff --git a/R/guide-axis.R b/R/guide-axis.R
index 8280219f3d..bc2a2e1596 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)
},
@@ -584,49 +571,40 @@ 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)
}
+ arg_match0(position, .trbl)
check_number_decimal(angle)
- angle <- angle %% 360
- arg_match0(
- axis_position,
- c("bottom", "left", "top", "right")
- )
-
- if (axis_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") {
-
- 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") {
-
- 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") {
-
- 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)
+ 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)
+
+ element$angle <- angle %||% element$angle
+ element$hjust <- hjust %||% element$hjust
+ element$vjust <- vjust %||% element$vjust
+ element
}
diff --git a/R/guide-bins.R b/R/guide-bins.R
index 518655cbba..0124ea6052 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
@@ -65,6 +69,7 @@ guide_bins <- function(
theme = NULL,
# general
+ angle = NULL,
position = NULL,
direction = NULL,
override.aes = list(),
@@ -85,6 +90,7 @@ guide_bins <- function(
theme = theme,
# general
+ angle = angle,
position = position,
direction = direction,
override.aes = rename_aes(override.aes),
@@ -115,6 +121,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 d03484edae..586caee124 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
@@ -124,6 +128,7 @@ guide_colourbar <- function(
alpha = NA,
draw.ulim = TRUE,
draw.llim = TRUE,
+ angle = NULL,
position = NULL,
direction = NULL,
reverse = FALSE,
@@ -151,6 +156,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 +199,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 52b6e1809d..54cd89a948 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,
@@ -66,6 +67,7 @@ guide_coloursteps <- function(
title = title,
theme = theme,
alpha = alpha,
+ angle = angle,
even.steps = even.steps,
show.limits = show.limits,
position = position,
diff --git a/R/guide-legend.R b/R/guide-legend.R
index 4dd088f358..671acf1a1c 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
},
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 a2938df745..5bec4a8d73 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,
@@ -23,6 +24,7 @@ guide_colorsteps(
title = waiver(),
theme = NULL,
alpha = NA,
+ angle = NULL,
even.steps = TRUE,
show.limits = NULL,
direction = NULL,
@@ -47,6 +49,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}}
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