Skip to content

Enable crs transformations of non-sf layers #3654

Closed
@clauswilke

Description

@clauswilke

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions