diff --git a/NEWS.md b/NEWS.md index 61683895da..32327bbcfd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -21,6 +21,9 @@ * ggplot2 now works in Turkish locale (@yutannihilation, #3011). +* `coord_sf()`, `coord_map()`, and `coord_polar()` now squash `-Inf` and `Inf` + into the min and max of the plot (@yutannihilation, #2972). + # ggplot2 3.1.0 ## Breaking changes diff --git a/R/coord-map.r b/R/coord-map.r index fa507198b5..d1f1448472 100644 --- a/R/coord-map.r +++ b/R/coord-map.r @@ -116,6 +116,10 @@ CoordMap <- ggproto("CoordMap", Coord, out$x <- rescale(out$x, 0:1, panel_params$x.proj) out$y <- rescale(out$y, 0:1, panel_params$y.proj) + # mproject() converts Inf to NA, so we need to restore them from data. + out$x[is.infinite(data$x)] <- squish_infinite(data$x) + out$y[is.infinite(data$y)] <- squish_infinite(data$y) + out }, diff --git a/R/coord-polar.r b/R/coord-polar.r index 0169990750..c7d61d02c3 100644 --- a/R/coord-polar.r +++ b/R/coord-polar.r @@ -337,10 +337,12 @@ theta_rescale_no_clip <- function(coord, x, panel_params) { } theta_rescale <- function(coord, x, panel_params) { + x <- squish_infinite(x, panel_params$theta.range) rotate <- function(x) (x + coord$start) %% (2 * pi) * coord$direction rotate(rescale(x, c(0, 2 * pi), panel_params$theta.range)) } r_rescale <- function(coord, x, panel_params) { + x <- squish_infinite(x, panel_params$r.range) rescale(x, c(0, 0.4), panel_params$r.range) } diff --git a/R/sf.R b/R/sf.R index 4d54e4c459..f59b8c396a 100644 --- a/R/sf.R +++ b/R/sf.R @@ -433,7 +433,7 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, function(x) sf_rescale01_x(x, panel_params$y_range) ) - data + transform_position(data, squish_infinite, squish_infinite) }, diff --git a/tests/testthat/test-coord-map.R b/tests/testthat/test-coord-map.R index 3976a22551..39a3493b04 100644 --- a/tests/testthat/test-coord-map.R +++ b/tests/testthat/test-coord-map.R @@ -11,3 +11,15 @@ test_that("USA state map drawn", { coord_map("mercator") ) }) + +test_that("Inf is squished to range", { + d <- cdata( + ggplot(data_frame(x = 0, y = 0)) + + geom_point(aes(x,y)) + + annotate("text", -Inf, Inf, label = "Top-left") + + coord_map() + ) + + expect_equal(d[[2]]$x, 0) + expect_equal(d[[2]]$y, 1) +}) diff --git a/tests/testthat/test-coord-polar.r b/tests/testthat/test-coord-polar.r index 4e6057a0f5..f0b92fe166 100644 --- a/tests/testthat/test-coord-polar.r +++ b/tests/testthat/test-coord-polar.r @@ -65,6 +65,22 @@ test_that("clipping can be turned off and on", { expect_equal(coord$clip, "off") }) +test_that("Inf is squished to range", { + d <- cdata( + ggplot(data_frame(x = "a", y = 1), aes(x, y)) + + geom_col() + + coord_polar() + + annotate("text", Inf, Inf, label = "Top-Center") + + annotate("text", -Inf, -Inf, label = "Center-Center") + ) + + # 0.4 is the upper limit of radius hardcoded in r_rescale() + expect_equal(d[[2]]$r, 0.4) + expect_equal(d[[2]]$theta, 0) + expect_equal(d[[3]]$r, 0) + expect_equal(d[[3]]$theta, 0) +}) + # Visual tests ------------------------------------------------------------ diff --git a/tests/testthat/test-coord_sf.R b/tests/testthat/test-coord_sf.R index 4db7937a9f..baf56d6dbc 100644 --- a/tests/testthat/test-coord_sf.R +++ b/tests/testthat/test-coord_sf.R @@ -160,3 +160,15 @@ test_that("axis labels can be set manually", { }) +test_that("Inf is squished to range", { + skip_if_not_installed("sf") + + d <- cdata( + ggplot(sf::st_point(c(0, 0))) + + geom_sf() + + annotate("text", -Inf, Inf, label = "Top-left") + ) + + expect_equal(d[[2]]$x, 0) + expect_equal(d[[2]]$y, 1) +})