From 959bfeca443434f74d827b9077ac6f6b6d068480 Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Wed, 9 Apr 2025 16:13:38 +0800 Subject: [PATCH 1/6] make sure using the prepared `r_axis_inside` for all methods --- R/coord-radial.R | 74 ++++++++++++++++++++++------------------------ man/coord_polar.Rd | 15 +++++----- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/R/coord-radial.R b/R/coord-radial.R index 8df50bcb1e..1e10f4b8f0 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -166,7 +166,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, xlimits <- self$limits$r ylimits <- self$limits$theta } - params <- c( + panel_params <- c( view_scales_polar(scale_x, self$theta, xlimits, expand = params$expand[c(4, 2)] ), @@ -177,21 +177,39 @@ CoordRadial <- ggproto("CoordRadial", Coord, arc = self$arc, inner_radius = self$inner_radius) ) - axis_rotation <- self$r_axis_inside + panel_params$r_axis_inside <- self$r_axis_inside + if (isFALSE(self$r_axis_inside)) { + place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) + if (!any(place)) { + cli::cli_warn(c( + "No appropriate placement found for {.arg r_axis_inside}.", + i = "Axis will be placed at panel edge." + )) + panel_params$r_axis_inside <- TRUE + } else { + panel_params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" + panel_params$fake_arc <- switch( + which(place[c(1, 3, 2, 4)])[1], + c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) + ) * pi + } + } + + axis_rotation <- panel_params$r_axis_inside if (is.numeric(axis_rotation)) { theta_scale <- switch(self$theta, x = scale_x, y = scale_y) axis_rotation <- theta_scale$transform(axis_rotation) - axis_rotation <- oob_squish(axis_rotation, params$theta.range) + axis_rotation <- oob_squish(axis_rotation, panel_params$theta.range) axis_rotation <- theta_rescale( - axis_rotation, params$theta.range, - params$arc, 1 + axis_rotation, panel_params$theta.range, + panel_params$arc, 1 ) - params$axis_rotation <- rep_len(axis_rotation, length.out = 2) + panel_params$axis_rotation <- rep_len(axis_rotation, length.out = 2) } else { - params$axis_rotation <- params$arc + panel_params$axis_rotation <- panel_params$arc } - params + panel_params }, setup_panel_guides = function(self, panel_params, guides, params = list()) { @@ -229,7 +247,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, opposite_r <- isTRUE(scales$r$position %in% c("bottom", "left")) } - if (!isFALSE(self$r_axis_inside)) { + if (!isFALSE(panel_params$r_axis_inside)) { r_position <- c("left", "right") # If both opposite direction and opposite position, don't flip @@ -244,7 +262,9 @@ CoordRadial <- ggproto("CoordRadial", Coord, guide_params[["r"]]$angle <- guide_params[["r"]]$angle %|W|% arc[1] guide_params[["r.sec"]]$angle <- guide_params[["r.sec"]]$angle %|W|% arc[2] } else { - r_position <- c(params$r_axis, opposite_position(params$r_axis)) + r_position <- c(panel_params$r_axis, + opposite_position(panel_params$r_axis) + ) if (opposite_r) { r_position <- rev(r_position) } @@ -285,7 +305,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, scale = panel_params[t] ) - if (!isFALSE(self$r_axis_inside)) { + if (!isFALSE(panel_params$r_axis_inside)) { # For radial axis, we need to pretend that rotation starts at 0 and # the bounding box is for circles, otherwise tick positions will be # spaced too closely. @@ -293,7 +313,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, } else { # When drawing radial axis outside, we need to pretend that arcs starts # at horizontal or vertical position to have the transform work right. - mod <- list(arc = params$fake_arc) + mod <- list(arc = panel_params$fake_arc) } temp <- modify_list(panel_params, mod) @@ -337,14 +357,14 @@ CoordRadial <- ggproto("CoordRadial", Coord, }, render_axis_v = function(self, panel_params, theme) { - if (!isFALSE(self$r_axis_inside)) { + if (!isFALSE(panel_params$r_axis_inside)) { return(list(left = zeroGrob(), right = zeroGrob())) } CoordCartesian$render_axis_v(panel_params, theme) }, render_axis_h = function(self, panel_params, theme) { - if (!isFALSE(self$r_axis_inside)) { + if (!isFALSE(panel_params$r_axis_inside)) { return(list(top = zeroGrob(), bottom = zeroGrob())) } CoordCartesian$render_axis_h(panel_params, theme) @@ -363,7 +383,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, border <- element_render(theme, "panel.border", fill = NA) - if (isFALSE(self$r_axis_inside)) { + if (isFALSE(panel_params$r_axis_inside)) { out <- grobTree( panel_guides_grob(panel_params$guides, "theta", theme), panel_guides_grob(panel_params$guides, "theta.sec", theme), @@ -449,30 +469,6 @@ CoordRadial <- ggproto("CoordRadial", Coord, lapply(scales_x, scale_flip_position) lapply(scales_y, scale_flip_position) - }, - - setup_params = function(self, data) { - params <- ggproto_parent(Coord, self)$setup_params(data) - if (!isFALSE(self$r_axis_inside)) { - return(params) - } - - place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) - if (!any(place)) { - cli::cli_warn(c( - "No appropriate placement found for {.arg r_axis_inside}.", - i = "Axis will be placed at panel edge." - )) - params$r_axis_inside <- TRUE - return(params) - } - - params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" - params$fake_arc <- switch( - which(place[c(1, 3, 2, 4)])[1], - c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) - ) * pi - params } ) diff --git a/man/coord_polar.Rd b/man/coord_polar.Rd index 23bbcb97ea..3bc579bcbc 100644 --- a/man/coord_polar.Rd +++ b/man/coord_polar.Rd @@ -138,14 +138,13 @@ ggplot(mtcars, aes(disp, mpg)) + # Similar with coord_cartesian(), you can set limits. ggplot(mtcars, aes(disp, mpg)) + - geom_point() + - coord_radial( - start = -0.4 * pi, - end = 0.4 * pi, inner.radius = 0.3, - thetalim = c(200, 300), - rlim = c(15, 30), - clip = "on" - ) + geom_point() + + coord_radial( + start = -0.4 * pi, + end = 0.4 * pi, inner.radius = 0.3, + thetalim = c(200, 300), + rlim = c(15, 30), + ) } \seealso{ The \href{https://ggplot2-book.org/coord#polar-coordinates-with-coord_polar}{polar coordinates section} of the online ggplot2 book. From ac3349dd1c77114c59ca29a7c4fdbf6041585dc1 Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Wed, 9 Apr 2025 16:27:23 +0800 Subject: [PATCH 2/6] reduce the code changes --- R/coord-radial.R | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/R/coord-radial.R b/R/coord-radial.R index 1e10f4b8f0..0469964fb8 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -166,7 +166,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, xlimits <- self$limits$r ylimits <- self$limits$theta } - panel_params <- c( + params <- c( view_scales_polar(scale_x, self$theta, xlimits, expand = params$expand[c(4, 2)] ), @@ -177,7 +177,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, arc = self$arc, inner_radius = self$inner_radius) ) - panel_params$r_axis_inside <- self$r_axis_inside + params$r_axis_inside <- self$r_axis_inside if (isFALSE(self$r_axis_inside)) { place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) if (!any(place)) { @@ -185,31 +185,31 @@ CoordRadial <- ggproto("CoordRadial", Coord, "No appropriate placement found for {.arg r_axis_inside}.", i = "Axis will be placed at panel edge." )) - panel_params$r_axis_inside <- TRUE + params$r_axis_inside <- TRUE } else { - panel_params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" - panel_params$fake_arc <- switch( + params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" + params$fake_arc <- switch( which(place[c(1, 3, 2, 4)])[1], c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) ) * pi } } - axis_rotation <- panel_params$r_axis_inside + axis_rotation <- params$r_axis_inside if (is.numeric(axis_rotation)) { theta_scale <- switch(self$theta, x = scale_x, y = scale_y) axis_rotation <- theta_scale$transform(axis_rotation) - axis_rotation <- oob_squish(axis_rotation, panel_params$theta.range) + axis_rotation <- oob_squish(axis_rotation, params$theta.range) axis_rotation <- theta_rescale( - axis_rotation, panel_params$theta.range, - panel_params$arc, 1 + axis_rotation, params$theta.range, + params$arc, 1 ) - panel_params$axis_rotation <- rep_len(axis_rotation, length.out = 2) + params$axis_rotation <- rep_len(axis_rotation, length.out = 2) } else { - panel_params$axis_rotation <- panel_params$arc + params$axis_rotation <- params$arc } - panel_params + params }, setup_panel_guides = function(self, panel_params, guides, params = list()) { From d91200fec74ae3e28f3106278c4e4547742121df Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Thu, 10 Apr 2025 23:23:00 +0800 Subject: [PATCH 3/6] Use `$setup_params()` to prepare `r_axis_inside` --- R/coord-radial.R | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/R/coord-radial.R b/R/coord-radial.R index 0469964fb8..d4a23bd3b1 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -166,7 +166,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, xlimits <- self$limits$r ylimits <- self$limits$theta } - params <- c( + panel_params <- c( view_scales_polar(scale_x, self$theta, xlimits, expand = params$expand[c(4, 2)] ), @@ -174,42 +174,37 @@ CoordRadial <- ggproto("CoordRadial", Coord, expand = params$expand[c(3, 1)] ), list(bbox = polar_bbox(self$arc, inner_radius = self$inner_radius), - arc = self$arc, inner_radius = self$inner_radius) + arc = self$arc, inner_radius = self$inner_radius, + r_axis_inside = params$r_axis_inside) ) - params$r_axis_inside <- self$r_axis_inside - if (isFALSE(self$r_axis_inside)) { - place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) - if (!any(place)) { - cli::cli_warn(c( - "No appropriate placement found for {.arg r_axis_inside}.", - i = "Axis will be placed at panel edge." - )) - params$r_axis_inside <- TRUE + if (isFALSE(panel_params$r_axis_inside)) { + if (any(params$place[c(1, 3)])) { + panel_params$r_axis <- "left" } else { - params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" - params$fake_arc <- switch( - which(place[c(1, 3, 2, 4)])[1], - c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) - ) * pi + panel_params$r_axis <- "bottom" } + panel_params$fake_arc <- switch( + which(params$place[c(1, 3, 2, 4)])[1], + c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) + ) * pi } - axis_rotation <- params$r_axis_inside + axis_rotation <- panel_params$r_axis_inside if (is.numeric(axis_rotation)) { theta_scale <- switch(self$theta, x = scale_x, y = scale_y) axis_rotation <- theta_scale$transform(axis_rotation) - axis_rotation <- oob_squish(axis_rotation, params$theta.range) + axis_rotation <- oob_squish(axis_rotation, panel_params$theta.range) axis_rotation <- theta_rescale( - axis_rotation, params$theta.range, - params$arc, 1 + axis_rotation, panel_params$theta.range, + panel_params$arc, 1 ) - params$axis_rotation <- rep_len(axis_rotation, length.out = 2) + panel_params$axis_rotation <- rep_len(axis_rotation, length.out = 2) } else { - params$axis_rotation <- params$arc + panel_params$axis_rotation <- panel_params$arc } - params + panel_params }, setup_panel_guides = function(self, panel_params, guides, params = list()) { @@ -469,6 +464,25 @@ CoordRadial <- ggproto("CoordRadial", Coord, lapply(scales_x, scale_flip_position) lapply(scales_y, scale_flip_position) + }, + + setup_params = function(self, data) { + params <- ggproto_parent(Coord, self)$setup_params(data) + params$r_axis_inside <- self$r_axis_inside + if (!isFALSE(params$r_axis_inside)) { + return(params) + } + + place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) + if (!any(place)) { + cli::cli_warn(c( + "No appropriate placement found for {.arg r_axis_inside}.", + i = "Axis will be placed at panel edge." + )) + params$r_axis_inside <- TRUE + } + params$place <- place + params } ) From 41fba616dc89b8bfab18bf39d512e8b30a5296a9 Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Thu, 10 Apr 2025 23:57:31 +0800 Subject: [PATCH 4/6] check `r.axis.inside` in the CoordRadial constructor --- R/coord-radial.R | 63 ++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/R/coord-radial.R b/R/coord-radial.R index d4a23bd3b1..65691eac7c 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -102,6 +102,16 @@ coord_radial <- function(theta = "x", arc <- switch(reverse, thetar = , theta = rev(arc), arc) r.axis.inside <- r.axis.inside %||% !(abs(arc[2] - arc[1]) >= 1.999 * pi) + if (isFALSE(r.axis.inside)) { + place <- in_arc(c(0, 0.5, 1, 1.5) * pi, arc) + if (!any(place)) { + cli::cli_warn(c( + "No appropriate placement found for {.arg r.axis.inside}.", + i = "Will use {.code r.axis.inside = TRUE} instead" + )) + r.axis.inside <- TRUE + } + } inner.radius <- c(inner.radius, 1) * 0.4 inner.radius <- switch(reverse, thetar = , r = rev, identity)(inner.radius) @@ -174,23 +184,10 @@ CoordRadial <- ggproto("CoordRadial", Coord, expand = params$expand[c(3, 1)] ), list(bbox = polar_bbox(self$arc, inner_radius = self$inner_radius), - arc = self$arc, inner_radius = self$inner_radius, - r_axis_inside = params$r_axis_inside) + arc = self$arc, inner_radius = self$inner_radius) ) - if (isFALSE(panel_params$r_axis_inside)) { - if (any(params$place[c(1, 3)])) { - panel_params$r_axis <- "left" - } else { - panel_params$r_axis <- "bottom" - } - panel_params$fake_arc <- switch( - which(params$place[c(1, 3, 2, 4)])[1], - c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) - ) * pi - } - - axis_rotation <- panel_params$r_axis_inside + axis_rotation <- self$r_axis_inside if (is.numeric(axis_rotation)) { theta_scale <- switch(self$theta, x = scale_x, y = scale_y) axis_rotation <- theta_scale$transform(axis_rotation) @@ -242,7 +239,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, opposite_r <- isTRUE(scales$r$position %in% c("bottom", "left")) } - if (!isFALSE(panel_params$r_axis_inside)) { + if (!isFALSE(self$r_axis_inside)) { r_position <- c("left", "right") # If both opposite direction and opposite position, don't flip @@ -257,9 +254,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, guide_params[["r"]]$angle <- guide_params[["r"]]$angle %|W|% arc[1] guide_params[["r.sec"]]$angle <- guide_params[["r.sec"]]$angle %|W|% arc[2] } else { - r_position <- c(panel_params$r_axis, - opposite_position(panel_params$r_axis) - ) + r_position <- c(params$r_axis, opposite_position(params$r_axis)) if (opposite_r) { r_position <- rev(r_position) } @@ -300,7 +295,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, scale = panel_params[t] ) - if (!isFALSE(panel_params$r_axis_inside)) { + if (!isFALSE(self$r_axis_inside)) { # For radial axis, we need to pretend that rotation starts at 0 and # the bounding box is for circles, otherwise tick positions will be # spaced too closely. @@ -308,7 +303,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, } else { # When drawing radial axis outside, we need to pretend that arcs starts # at horizontal or vertical position to have the transform work right. - mod <- list(arc = panel_params$fake_arc) + mod <- list(arc = params$fake_arc) } temp <- modify_list(panel_params, mod) @@ -352,14 +347,14 @@ CoordRadial <- ggproto("CoordRadial", Coord, }, render_axis_v = function(self, panel_params, theme) { - if (!isFALSE(panel_params$r_axis_inside)) { + if (!isFALSE(self$r_axis_inside)) { return(list(left = zeroGrob(), right = zeroGrob())) } CoordCartesian$render_axis_v(panel_params, theme) }, render_axis_h = function(self, panel_params, theme) { - if (!isFALSE(panel_params$r_axis_inside)) { + if (!isFALSE(self$r_axis_inside)) { return(list(top = zeroGrob(), bottom = zeroGrob())) } CoordCartesian$render_axis_h(panel_params, theme) @@ -378,7 +373,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, border <- element_render(theme, "panel.border", fill = NA) - if (isFALSE(panel_params$r_axis_inside)) { + if (isFALSE(self$r_axis_inside)) { out <- grobTree( panel_guides_grob(panel_params$guides, "theta", theme), panel_guides_grob(panel_params$guides, "theta.sec", theme), @@ -468,20 +463,14 @@ CoordRadial <- ggproto("CoordRadial", Coord, setup_params = function(self, data) { params <- ggproto_parent(Coord, self)$setup_params(data) - params$r_axis_inside <- self$r_axis_inside - if (!isFALSE(params$r_axis_inside)) { - return(params) - } - - place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) - if (!any(place)) { - cli::cli_warn(c( - "No appropriate placement found for {.arg r_axis_inside}.", - i = "Axis will be placed at panel edge." - )) - params$r_axis_inside <- TRUE + if (isFALSE(self$r_axis_inside)) { + place <- in_arc(c(0, 0.5, 1, 1.5) * pi, self$arc) + params$r_axis <- if (any(place[c(1, 3)])) "left" else "bottom" + params$fake_arc <- switch( + which(place[c(1, 3, 2, 4)])[1], + c(0, 2), c(1, 3), c(0.5, 2.5), c(1.5, 3.5) + ) * pi } - params$place <- place params } ) From 6ce6a686bae70e86e029940f5b6a680eb38aa6f5 Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Fri, 11 Apr 2025 01:51:15 +0800 Subject: [PATCH 5/6] more direct indicative warning message --- R/coord-radial.R | 16 ++++++++-------- tests/testthat/_snaps/coord-polar.md | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/R/coord-radial.R b/R/coord-radial.R index 65691eac7c..3cef9c2b5b 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -106,7 +106,7 @@ coord_radial <- function(theta = "x", place <- in_arc(c(0, 0.5, 1, 1.5) * pi, arc) if (!any(place)) { cli::cli_warn(c( - "No appropriate placement found for {.arg r.axis.inside}.", + "No appropriate placement found for outside {.field r.axis}.", i = "Will use {.code r.axis.inside = TRUE} instead" )) r.axis.inside <- TRUE @@ -176,7 +176,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, xlimits <- self$limits$r ylimits <- self$limits$theta } - panel_params <- c( + params <- c( view_scales_polar(scale_x, self$theta, xlimits, expand = params$expand[c(4, 2)] ), @@ -191,17 +191,17 @@ CoordRadial <- ggproto("CoordRadial", Coord, if (is.numeric(axis_rotation)) { theta_scale <- switch(self$theta, x = scale_x, y = scale_y) axis_rotation <- theta_scale$transform(axis_rotation) - axis_rotation <- oob_squish(axis_rotation, panel_params$theta.range) + axis_rotation <- oob_squish(axis_rotation, params$theta.range) axis_rotation <- theta_rescale( - axis_rotation, panel_params$theta.range, - panel_params$arc, 1 + axis_rotation, params$theta.range, + params$arc, 1 ) - panel_params$axis_rotation <- rep_len(axis_rotation, length.out = 2) + params$axis_rotation <- rep_len(axis_rotation, length.out = 2) } else { - panel_params$axis_rotation <- panel_params$arc + params$axis_rotation <- params$arc } - panel_params + params }, setup_panel_guides = function(self, panel_params, guides, params = list()) { diff --git a/tests/testthat/_snaps/coord-polar.md b/tests/testthat/_snaps/coord-polar.md index 62138ccf99..051d068eb5 100644 --- a/tests/testthat/_snaps/coord-polar.md +++ b/tests/testthat/_snaps/coord-polar.md @@ -9,8 +9,8 @@ --- - No appropriate placement found for `r_axis_inside`. - i Axis will be placed at panel edge. + No appropriate placement found for `r.axis.inside`. + i Will use `r.axis.inside = TRUE` instead # when both x and y are AsIs, they are not transformed From 5358e6db7939e3869151099f47286d20abc6868b Mon Sep 17 00:00:00 2001 From: Yunuuuu Date: Fri, 11 Apr 2025 01:51:42 +0800 Subject: [PATCH 6/6] accept the test --- tests/testthat/_snaps/coord-polar.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/_snaps/coord-polar.md b/tests/testthat/_snaps/coord-polar.md index 051d068eb5..fcbe964bea 100644 --- a/tests/testthat/_snaps/coord-polar.md +++ b/tests/testthat/_snaps/coord-polar.md @@ -9,7 +9,7 @@ --- - No appropriate placement found for `r.axis.inside`. + No appropriate placement found for outside r.axis. i Will use `r.axis.inside = TRUE` instead # when both x and y are AsIs, they are not transformed