diff --git a/NEWS.md b/NEWS.md index d8167c66c9..3090a3fa3b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* `coord_radial()` now displays no axis instead of throwing an error when + a scale has no breaks (@teunbrand, #6271). * The `fatten` argument has been deprecated in `geom_boxplot()`, `geom_crossbar()` and `geom_pointrange()` (@teunbrand, #4881). * Axis labels are now preserved better when using `coord_sf(expand = TRUE)` and diff --git a/R/coord-radial.R b/R/coord-radial.R index ef6130fb34..bc933ea1d7 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -250,11 +250,18 @@ CoordRadial <- ggproto("CoordRadial", Coord, names(gdefs) <- aesthetics # Train theta guide - for (t in intersect(c("theta", "theta.sec"), aesthetics[!empty])) { - gdefs[[t]] <- guides[[t]]$train(gdefs[[t]], panel_params[[t]]) - gdefs[[t]] <- guides[[t]]$transform(gdefs[[t]], self, panel_params) - gdefs[[t]] <- guides[[t]]$get_layer_key(gdefs[[t]], layers) - } + t <- intersect(c("theta", "theta.sec"), aesthetics[!empty]) + gdefs[t] <- Map( + function(guide, guide_param, scale) { + guide_param$theme_suffix <- "theta" + guide_param <- guide$train(guide_param, scale) + guide_param <- guide$transform(guide_param, self, panel_params) + guide_param <- guide$get_layer_key(guide_param, layers) + }, + guide = guides[t], + guide_param = gdefs[t], + scale = panel_params[t] + ) if (!isFALSE(self$r_axis_inside)) { # For radial axis, we need to pretend that rotation starts at 0 and @@ -269,17 +276,18 @@ CoordRadial <- ggproto("CoordRadial", Coord, temp <- modify_list(panel_params, mod) # Train radial guide - for (r in intersect(c("r", "r.sec"), aesthetics[!empty])) { - gdefs[[r]] <- guides[[r]]$train(gdefs[[r]], panel_params[[r]]) - gdefs[[r]] <- guides[[r]]$transform(gdefs[[r]], self, temp) # Use temp - gdefs[[r]] <- guides[[r]]$get_layer_key(gdefs[[r]], layers) - } - - # Set theme suffixes - gdefs$theta$theme_suffix <- "theta" - gdefs$theta.sec$theme_suffix <- "theta" - gdefs$r$theme_suffix <- "r" - gdefs$r.sec$theme_suffix <- "r" + r <- intersect(c("r", "r.sec"), aesthetics[!empty]) + gdefs[r] <- Map( + function(guide, guide_param, scale) { + guide_param$theme_suffix <- "r" + guide_param <- guide$train(guide_param, scale) + guide_param <- guide$transform(guide_param, self, temp) + guide_param <- guide$get_layer_key(guide_param, layers) + }, + guide = guides[r], + guide_param = gdefs[r], + scale = panel_params[r] + ) panel_params$guides$update_params(gdefs) panel_params diff --git a/R/guide-axis-theta.R b/R/guide-axis-theta.R index 7f4c3c9246..af96a337b6 100644 --- a/R/guide-axis-theta.R +++ b/R/guide-axis-theta.R @@ -63,22 +63,26 @@ GuideAxisTheta <- ggproto( transform = function(params, coord, panel_params) { - opposite_var <- setdiff(c("x", "y"), params$aesthetic) - opposite_value <- switch(params$position, top = , right = , theta.sec = -Inf, Inf) - if (is.unsorted(panel_params$inner_radius %||% NA)) { - opposite_value <- -opposite_value - } - if (nrow(params$key) > 0) { - params$key[[opposite_var]] <- opposite_value - } - if (nrow(params$decor) > 0) { - params$decor[[opposite_var]] <- opposite_value + position <- params$position + + if (!is.null(position)) { + opposite_var <- setdiff(c("x", "y"), params$aesthetic) + opposite_value <- switch(position, top = , right = , theta.sec = -Inf, Inf) + if (is.unsorted(panel_params$inner_radius %||% NA)) { + opposite_value <- -opposite_value + } + if (nrow(params$key) > 0) { + params$key[[opposite_var]] <- opposite_value + } + if (nrow(params$decor) > 0) { + params$decor[[opposite_var]] <- opposite_value + } } params <- GuideAxis$transform(params, coord, panel_params) key <- params$key - n <- nrow(key) + n <- vec_size(key) if (n < 1) { return(params) } diff --git a/R/guides-.R b/R/guides-.R index 63a17cc430..3ea09c7104 100644 --- a/R/guides-.R +++ b/R/guides-.R @@ -525,7 +525,7 @@ Guides <- ggproto( coord <- coord %||% default_inside_position %||% just groups$justs[[i]] <- just - groups$coord[[i]] <- coord + groups$coords[[i]] <- coord } groups <- vec_group_loc(vec_slice(groups, keep)) @@ -540,10 +540,10 @@ Guides <- ggproto( # prepare output for (i in vec_seq_along(groups)) { adjust <- NULL - position <- groups$key$position[i] + position <- groups$key$positions[i] if (position == "inside") { adjust <- theme( - legend.position.inside = groups$key$coord[[i]], + legend.position.inside = groups$key$coords[[i]], legend.justification.inside = groups$key$justs[[i]] ) } diff --git a/tests/testthat/test-coord-polar.R b/tests/testthat/test-coord-polar.R index 1f662d2322..466162b0f5 100644 --- a/tests/testthat/test-coord-polar.R +++ b/tests/testthat/test-coord-polar.R @@ -197,6 +197,18 @@ test_that("radial coords can be reversed", { expect_equal(as.numeric(fwd$y), rev(as.numeric(rev$y))) }) +test_that("coord_radial can deal with empty breaks (#6271)", { + p <- ggplot_build( + ggplot(mtcars, aes(mpg, disp)) + + geom_point() + + coord_radial() + + scale_x_continuous(breaks = numeric()) + + scale_y_continuous(breaks = numeric()) + ) + guides <- p$layout$panel_params[[1]]$guides$guides + is_none <- vapply(guides, inherits, logical(1), what = "GuideNone") + expect_true(all(is_none)) +}) # Visual tests ------------------------------------------------------------