Description
The recent issue #3653 prompted me to think a little deeper about mixing sf and non-sf layers. Currently, we can mix these layers if the non-sf layers are properly projected.
library(ggplot2)
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
df <- data.frame(
lat = 35.76667,
long = -78.63333,
name = "Raleigh"
)
# works, crs is longlat
ggplot(df, aes(x = long, y = lat)) +
geom_sf(data = nc, size = 0.1, fill = "white", inherit.aes = FALSE) +
geom_point() +
geom_text(aes(label = name), hjust = -.1, vjust = 1.1)
# doesn't work, non-sf layers are not transformed
ggplot(df, aes(x = long, y = lat)) +
geom_sf(data = nc, size = 0.1, fill = "white", inherit.aes = FALSE) +
geom_point() +
geom_text(aes(label = name), hjust = -.1, vjust = 1.1) +
coord_sf(crs = 2264)
# manually transforming coordinates works
df_trans <- data.frame(
lat = 734165.51156997,
long = 2108774.28357641,
name = "Raleigh"
)
ggplot(df_trans, aes(x = long, y = lat)) +
geom_sf(data = nc, size = 0.1, fill = "white", inherit.aes = FALSE) +
geom_point() +
geom_text(aes(label = name), hjust = -.1, vjust = 1.1) +
coord_sf(crs = 2264)
Created on 2019-12-04 by the reprex package (v0.3.0)
It would be great (and make life easier in many ways) if non-sf layers could also be transformed by coord_sf()
. However, this poses a problem: The sf layers carry information about their crs, and therefore coord_sf()
can figure out if and how they should be transformed. The non-sf layers don't carry that information, and thus whatever coord_sf()
does will be wrong in some cases. We could add a crs
argument to all layers, but that seems ugly since it breaks orthogonality between different parts of the API.
The recent shader experiments by @thomasp85 got me thinking that maybe the right approach is to modify layers, as he does there. What if we added a with_sf()
function that can take any ordinary layer and turn it into one whose coordinates get transformed by coord_sf()
? The API would be something like this:
ggplot(df, aes(x = long, y = lat)) +
geom_sf(data = nc, size = 0.1, fill = "white", inherit.aes = FALSE) +
with_sf(geom_point()) +
with_sf(geom_text(aes(label = name), hjust = -.1, vjust = 1.1)) +
coord_sf(crs = 2264)
We could also enable the following:
ggplot(df, aes(x = long, y = lat)) +
geom_sf(data = nc, size = 0.1, fill = "white", inherit.aes = FALSE) +
with_sf(
geom_point(),
geom_text(aes(label = name), hjust = -.1, vjust = 1.1)
) +
coord_sf(crs = 2264)