Skip to content

Commit 2902ec0

Browse files
authored
Make coord_sf() default use projected coords (#4496)
1 parent 7f9f23e commit 2902ec0

File tree

11 files changed

+115
-109
lines changed

11 files changed

+115
-109
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
on:
2-
push:
3-
branches:
4-
- master
5-
pull_request:
6-
branches:
7-
- master
1+
#on:
2+
# push:
3+
# branches:
4+
# - master
5+
# pull_request:
6+
# branches:
7+
# - master
8+
9+
on: [push, pull_request]
810

911
name: R-CMD-check
1012

NEWS.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ small selection of feature refinements.
99

1010
* `coord_sf()` now has an argument `default_crs` that specifies the coordinate
1111
reference system (CRS) for non-sf layers and scale/coord limits. This argument
12-
defaults to the World Geodetic System 1984 (WGS84), which means x and y
13-
positions are interpreted as longitude and latitude. This is a potentially
14-
breaking change for users who use projected coordinates in non-sf layers or in
15-
limits. Setting `default_crs = NULL` recovers the old behavior. Further,
16-
authors of extension packages implementing `stat_sf()`-like functionality are
17-
encouraged to look at the source code of `stat_sf()`'s `compute_group()`
18-
function to see how to provide scale-limit hints to `coord_sf()`
19-
(@clauswilke, #3659).
12+
defaults to `NULL`, which means non-sf layers are assumed to be in projected
13+
coordinates, as in prior ggplot2 versions. Setting `default_crs = sf::st_crs(4326)`
14+
provides a simple way to interpret x and y positions as longitude and latitude,
15+
regardless of the CRS used by `coord_sf()`. Authors of extension packages
16+
implementing `stat_sf()`-like functionality are encouraged to look at the source
17+
code of `stat_sf()`'s `compute_group()` function to see how to provide scale-limit
18+
hints to `coord_sf()` (@clauswilke, #3659).
2019

2120
* `ggsave()` now uses ragg to render raster output if ragg is available. It also
2221
handles custom devices that sets a default unit (e.g. `ragg::agg_png`)

R/annotation-map.r

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ NULL
4242
#' p +
4343
#' coord_sf(
4444
#' crs = st_crs(3347),
45+
#' default_crs = st_crs(4326), # data is provided as long-lat
4546
#' xlim = c(-84, -76),
4647
#' ylim = c(34, 37.2)
4748
#' )
@@ -53,7 +54,7 @@ NULL
5354
#' data = nc, inherit.aes = FALSE,
5455
#' fill = NA, color = "black", size = 0.1
5556
#' ) +
56-
#' coord_sf(crs = st_crs(3347))
57+
#' coord_sf(crs = st_crs(3347), default_crs = st_crs(4326))
5758
#' }}}
5859
annotation_map <- function(map, ...) {
5960
# Get map input into correct form

R/coord-sf.R

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
268268
is_free = function() FALSE,
269269

270270
# for regular geoms (such as geom_path, geom_polygon, etc.), CoordSf is non-linear
271-
is_linear = function() FALSE,
271+
# if the default_crs option is being used, i.e., not set to NULL
272+
is_linear = function(self) is.null(self$get_default_crs()),
272273

273274
distance = function(self, x, y, panel_params) {
274275
d <- self$backtransform_range(panel_params)
@@ -588,29 +589,26 @@ calc_limits_bbox <- function(method, xlim, ylim, crs, default_crs) {
588589
#' be projected before plotting. If not specified, will use the CRS defined
589590
#' in the first sf layer of the plot.
590591
#' @param default_crs The default CRS to be used for non-sf layers (which
591-
#' don't carry any CRS information) and scale limits. If not specified, this
592-
#' defaults to the World Geodetic System 1984 (WGS84), which means x and y
593-
#' positions are interpreted as longitude and latitude, respectively. If
594-
#' set to `NULL`, uses the setting for `crs`, which means that then all
592+
#' don't carry any CRS information) and scale limits. The default value of
593+
#' `NULL` means that the setting for `crs` is used. This implies that all
595594
#' non-sf layers and scale limits are assumed to be specified in projected
596-
#' coordinates.
595+
#' coordinates. A useful alternative setting is `default_crs = sf::st_crs(4326)`,
596+
#' which means x and y positions are interpreted as longitude and latitude,
597+
#' respectively, in the World Geodetic System 1984 (WGS84).
597598
#' @param xlim,ylim Limits for the x and y axes. These limits are specified
598-
#' in the units of the default CRS. To specify limits in projected coordinates,
599-
#' set `default_crs = NULL`. How limit specifications translate into the exact
599+
#' in the units of the default CRS. By default, this means projected coordinates
600+
#' (`default_crs = NULL`). How limit specifications translate into the exact
600601
#' region shown on the plot can be confusing when non-linear or rotated coordinate
601-
#' systems are used. First, different methods can be preferable under different
602-
#' conditions. See parameter `lims_method` for details. Second, specifying limits
603-
#' along only one direction can affect the automatically generated limits along the
604-
#' other direction. Therefore, it is best to always specify limits for both x and y.
605-
#' Third, specifying limits via position scales or `xlim()`/`ylim()` is strongly
606-
#' discouraged, as it can result in data points being dropped from the plot even
607-
#' though they would be visible in the final plot region. Finally, specifying limits
608-
#' that cross the international date boundary is not possible with WGS84 as the default
609-
#' crs. All these issues can be avoided by working in projected coordinates,
610-
#' via `default_crs = NULL`, but at the cost of having to provide less intuitive
611-
#' numeric values for the limit parameters.
602+
#' systems are used as the default crs. First, different methods can be preferable
603+
#' under different conditions. See parameter `lims_method` for details. Second,
604+
#' specifying limits along only one direction can affect the automatically generated
605+
#' limits along the other direction. Therefore, it is best to always specify limits
606+
#' for both x and y. Third, specifying limits via position scales or `xlim()`/`ylim()`
607+
#' is strongly discouraged, as it can result in data points being dropped from the plot even
608+
#' though they would be visible in the final plot region.
612609
#' @param lims_method Method specifying how scale limits are converted into
613-
#' limits on the plot region. For a very non-linear CRS (e.g., a perspective centered
610+
#' limits on the plot region. Has no effect when `default_crs = NULL`.
611+
#' For a very non-linear CRS (e.g., a perspective centered
614612
#' around the North pole), the available methods yield widely differing results, and
615613
#' you may want to try various options. Methods currently implemented include `"cross"`
616614
#' (the default), `"box"`, `"orthogonal"`, and `"geometry_bbox"`. For method `"cross"`,
@@ -655,7 +653,7 @@ calc_limits_bbox <- function(method, xlim, ylim, crs, default_crs) {
655653
#' @export
656654
#' @rdname ggsf
657655
coord_sf <- function(xlim = NULL, ylim = NULL, expand = TRUE,
658-
crs = NULL, default_crs = sf::st_crs(4326),
656+
crs = NULL, default_crs = NULL,
659657
datum = sf::st_crs(4326),
660658
label_graticule = waiver(),
661659
label_axes = waiver(), lims_method = c("cross", "box", "orthogonal", "geometry_bbox"),

R/geom-sf.R

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#'
2525
#' @section CRS:
2626
#' `coord_sf()` ensures that all layers use a common CRS. You can
27-
#' either specify it using the `CRS` param, or `coord_sf()` will
27+
#' either specify it using the `crs` param, or `coord_sf()` will
2828
#' take it from the first layer that defines a CRS.
2929
#'
3030
#' @section Combining sf layers and regular geoms:
@@ -33,21 +33,24 @@
3333
#' when using these geoms, two problems arise. First, what CRS should be used
3434
#' for the x and y coordinates used by these non-sf geoms? The CRS applied to
3535
#' non-sf geoms is set by the `default_crs` parameter, and it defaults to
36-
#' the World Geodetic System 1984 (WGS84). This means that x and y
37-
#' positions are interpreted as longitude and latitude, respectively. You can
38-
#' also specify any other valid CRS as the default CRS for non-sf geoms. Moreover,
39-
#' if you set `default_crs = NULL`, then positions for non-sf geoms are
40-
#' interpreted as projected coordinates. This setting allows you complete control
41-
#' over where exactly items are placed on the plot canvas.
36+
#' `NULL`, which means positions for non-sf geoms are interpreted as projected
37+
#' coordinates in the coordinate system set by the `crs` parameter. This setting
38+
#' allows you complete control over where exactly items are placed on the plot
39+
#' canvas, but it may require some understanding of how projections work and how
40+
#' to generate data in projected coordinates. As an alternative, you can set
41+
#' `default_crs = sf::st_crs(4326)`, the World Geodetic System 1984 (WGS84).
42+
#' This means that x and y positions are interpreted as longitude and latitude,
43+
#' respectively. You can also specify any other valid CRS as the default CRS for
44+
#' non-sf geoms.
4245
#'
4346
#' The second problem that arises for non-sf geoms is how straight lines
44-
#' should be interpreted in projected space. The approach `coord_sf()` takes is
45-
#' to break straight lines into small pieces (i.e., segmentize them) and
46-
#' then transform the pieces into projected coordinates. For the default setting
47-
#' where x and y are interpreted as longitude and latitude, this approach means
48-
#' that horizontal lines follow the parallels and vertical lines follow the
49-
#' meridians. If you need a different approach to handling straight lines, then
50-
#' you should manually segmentize and project coordinates and generate the plot
47+
#' should be interpreted in projected space when `default_crs` is not set to `NULL`.
48+
#' The approach `coord_sf()` takes is to break straight lines into small pieces
49+
#' (i.e., segmentize them) and then transform the pieces into projected coordinates.
50+
#' For the default setting where x and y are interpreted as longitude and latitude,
51+
#' this approach means that horizontal lines follow the parallels and vertical lines
52+
#' follow the meridians. If you need a different approach to handling straight lines,
53+
#' then you should manually segmentize and project coordinates and generate the plot
5154
#' in projected coordinates.
5255
#'
5356
#' @param show.legend logical. Should this layer be included in the legends?
@@ -78,11 +81,12 @@
7881
#' geom_sf(colour = "white") +
7982
#' geom_sf(aes(geometry = mid, size = AREA), show.legend = "point")
8083
#'
81-
#' # You can also use layers with x and y aesthetics: these are
82-
#' # assumed to already be in the common CRS.
83-
#' ggplot(nc) +
84+
#' # You can also use layers with x and y aesthetics. To have these interpreted
85+
#' # as longitude/latitude you need to set the default CRS in coord_sf()
86+
#' ggplot(nc_3857) +
8487
#' geom_sf() +
85-
#' annotate("point", x = -80, y = 35, colour = "red", size = 4)
88+
#' annotate("point", x = -80, y = 35, colour = "red", size = 4) +
89+
#' coord_sf(default_crs = sf::st_crs(4326))
8690
#'
8791
#' # Thanks to the power of sf, a geom_sf nicely handles varying projections
8892
#' # setting the aspect ratio correctly.

man/annotation_map.Rd

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/ggsf.Rd

Lines changed: 39 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/figs/coord-sf/default-crs-turned-off.svg renamed to tests/figs/coord-sf/non-sf-geoms-using-long-lat.svg

Lines changed: 1 addition & 1 deletion
Loading

0 commit comments

Comments
 (0)