Skip to content

Commit 4af1337

Browse files
authored
Fix back-transformation of ranges in coords (#2821)
* rename range() function of coord to backtransform_range() * fix typo * Add range function to Coord(). * add range() to coord_trans() * add warnings * fix range functions for coord_flip() and coord_polar() * Expand documentation for summarise_layout(). Closes #2895. * improve back-compatibility * fix broken regression test * reinstate vdiffr deps * revise news
1 parent daddf74 commit 4af1337

16 files changed

+179
-17
lines changed

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
* `coord_sf()` now accepts two new parameters, `label_graticule` and `label_axes`,
1919
that can be used to specify which graticules to label on which side of the plot
2020
(@clauswilke, #2846).
21+
22+
* `Coord` objects now have a function `backtransform_range()` that returns the
23+
panel range in data coordinates. This change may affect developers of custom coords,
24+
who now should implement this function. It may also affect developers of custom
25+
geoms that use the `range()` function. In some applications, `backtransform_range()`
26+
may be more appropriate.
27+
(@clauswilke, #2821).
2128

2229
* `geom_sf()` now respects `lineend`, `linejoin`, and `linemitre` parameters
2330
for lines and polygons (@alistaire47, #2826)

R/coord-.r

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,21 @@
1313
#' - `render_bg`: Renders background elements.
1414
#' - `render_axis_h`: Renders the horizontal axes.
1515
#' - `render_axis_v`: Renders the vertical axes.
16+
#' - `backtransform_range(panel_params)`: Extracts the panel range provided
17+
#' in `panel_params` (created by `setup_panel_params()`, see below) and
18+
#' back-transforms to data coordinates. This back-transformation can be needed
19+
#' for coords such as `coord_trans()` where the range in the transformed
20+
#' coordinates differs from the range in the untransformed coordinates. Returns
21+
#' a list of two ranges, `x` and `y`, and these correspond to the variables
22+
#' mapped to the `x` and `y` aesthetics, even for coords such as `coord_flip()`
23+
#' where the `x` aesthetic is shown along the y direction and vice versa.
1624
#' - `range(panel_params)`: Extracts the panel range provided
1725
#' in `panel_params` (created by `setup_panel_params()`, see below) and
18-
#' back-transforms to data coordinates. This back-transformation is needed
19-
#' for coords such as `coord_flip()`, `coord_polar()`, `coord_trans()` where
20-
#' the range in the transformed coordinates differs from the range in the
21-
#' untransformed coordinates.
26+
#' returns it. Unlike `backtransform_range()`, this function does not perform
27+
#' any back-transformation and instead returns final transformed coordinates. Returns
28+
#' a list of two ranges, `x` and `y`, and these correspond to the variables
29+
#' mapped to the `x` and `y` aesthetics, even for coords such as `coord_flip()`
30+
#' where the `x` aesthetic is shown along the y direction and vice versa.
2231
#' - `transform`: Transforms x and y coordinates.
2332
#' - `distance`: Calculates distance.
2433
#' - `is_linear`: Returns `TRUE` if the coordinate system is
@@ -84,11 +93,22 @@ Coord <- ggproto("Coord",
8493
# transform range given in transformed coordinates
8594
# back into range in given in (possibly scale-transformed)
8695
# data coordinates
87-
range = function(panel_params) {
96+
backtransform_range = function(self, panel_params) {
8897
warning(
89-
"range backtransformation not implemented in this coord; plot may be wrong.",
98+
"range backtransformation not implemented in this coord; results may be wrong.",
9099
call. = FALSE
91100
)
101+
# return result from range function for backwards compatibility
102+
# before ggplot2 3.0.1
103+
self$range(panel_params)
104+
},
105+
106+
# return range stored in panel_params
107+
range = function(panel_params) {
108+
warning(
109+
"range calculation not implemented in this coord; results may be wrong.",
110+
call. = FALSE
111+
)
92112
list(x = panel_params$x.range, y = panel_params$y.range)
93113
},
94114

R/coord-cartesian-.r

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ CoordCartesian <- ggproto("CoordCartesian", Coord,
8787
list(x = panel_params$x.range, y = panel_params$y.range)
8888
},
8989

90+
backtransform_range = function(self, panel_params) {
91+
self$range(panel_params)
92+
},
93+
9094
transform = function(data, panel_params) {
9195
rescale_x <- function(data) rescale(data, from = panel_params$x.range)
9296
rescale_y <- function(data) rescale(data, from = panel_params$y.range)

R/coord-flip.r

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ CoordFlip <- ggproto("CoordFlip", CoordCartesian,
4444
CoordCartesian$transform(data, panel_params)
4545
},
4646

47+
backtransform_range = function(self, panel_params) {
48+
self$range(panel_params)
49+
},
50+
4751
range = function(panel_params) {
52+
# summarise_layout() expects the original x and y ranges here,
53+
# not the ones we would get after flipping the axes
4854
list(x = panel_params$y.range, y = panel_params$x.range)
4955
},
5056

R/coord-map.r

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,19 @@ CoordMap <- ggproto("CoordMap", Coord,
119119
out
120120
},
121121

122-
range = function(panel_params) {
122+
backtransform_range = function(panel_params) {
123123
# range is stored in data coordinates and doesn't have to be back-transformed
124124
list(x = panel_params$x.range, y = panel_params$y.range)
125125
},
126126

127+
range = function(panel_params) {
128+
# Range in projected coordinates:
129+
# list(x = panel_params$x.proj, y = panel_params$y.proj)
130+
# However, coord_map() does never really work with transformed coordinates,
131+
# so return unprojected data coordinates here
132+
list(x = panel_params$x.range, y = panel_params$y.range)
133+
},
134+
127135
distance = function(x, y, panel_params) {
128136
max_dist <- dist_central_angle(panel_params$x.range, panel_params$y.range)
129137
dist_central_angle(x, y) / max_dist

R/coord-munch.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ coord_munch <- function(coord, data, range, segment_length = 0.01) {
1515
if (coord$is_linear()) return(coord$transform(data, range))
1616

1717
# range has theta and r values; get corresponding x and y values
18-
ranges <- coord$range(range)
18+
ranges <- coord$backtransform_range(range)
1919

2020
# Convert any infinite locations into max/min
2121
# Only need to work with x and y because for munching, those are the

R/coord-polar.r

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,13 @@ CoordPolar <- ggproto("CoordPolar", Coord,
9090
dist_polar(r, theta)
9191
},
9292

93+
backtransform_range = function(self, panel_params) {
94+
self$range(panel_params)
95+
},
96+
9397
range = function(self, panel_params) {
98+
# summarise_layout() expects that the x and y ranges here
99+
# match the setting from self$theta and self$r
94100
setNames(
95101
list(panel_params$theta.range, panel_params$r.range),
96102
c(self$theta, self$r)

R/coord-transform.r

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,20 @@ CoordTrans <- ggproto("CoordTrans", Coord,
119119
dist_euclidean(self$trans$x$transform(x), self$trans$y$transform(y)) / max_dist
120120
},
121121

122-
range = function(self, panel_params) {
122+
backtransform_range = function(self, panel_params) {
123123
list(
124124
x = self$trans$x$inverse(panel_params$x.range),
125125
y = self$trans$y$inverse(panel_params$y.range)
126126
)
127127
},
128128

129+
range = function(self, panel_params) {
130+
list(
131+
x = panel_params$x.range,
132+
y = panel_params$y.range
133+
)
134+
},
135+
129136
transform = function(self, data, panel_params) {
130137
trans_x <- function(data) transform_value(self$trans$x, data, panel_params$x.range)
131138
trans_y <- function(data) transform_value(self$trans$y, data, panel_params$y.range)

R/geom-abline.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ geom_abline <- function(mapping = NULL, data = NULL,
111111
#' @export
112112
GeomAbline <- ggproto("GeomAbline", Geom,
113113
draw_panel = function(data, panel_params, coord) {
114-
ranges <- coord$range(panel_params)
114+
ranges <- coord$backtransform_range(panel_params)
115115

116116
data$x <- ranges$x[1]
117117
data$xend <- ranges$x[2]

R/geom-hline.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ geom_hline <- function(mapping = NULL, data = NULL,
3737
#' @export
3838
GeomHline <- ggproto("GeomHline", Geom,
3939
draw_panel = function(data, panel_params, coord) {
40-
ranges <- coord$range(panel_params)
40+
ranges <- coord$backtransform_range(panel_params)
4141

4242
data$x <- ranges$x[1]
4343
data$xend <- ranges$x[2]

0 commit comments

Comments
 (0)