r-spatial / sf

Simple Features for R
https://r-spatial.github.io/sf/
Other
1.33k stars 293 forks source link

Coerce a tbl in 'sf' format into an sf object? #385

Closed cboettig closed 7 years ago

cboettig commented 7 years ago

If a user constructs a data.frame that has a geometry list-column of type sfc, is there any way to make the whole table into an sf object? Currently looks like there's no method for this coercion.

Simply assigning the class seems to run into issues; perhaps that is only because my table is not created correctly. There's probably an easier way to do what I'm doing: but consider the case of a data frame with coordinates and additional information in other rows:

df <- data.frame(feature = 1:10, X = rnorm(10), Y = rnorm(10) )

Not sure what the recommended way in sf is to convert this to an sf object, so I try a naive construction:

sf <-
df %>%
  rowwise() %>%
  mutate(geometry = st_geometry(st_point(c(X, Y)))) %>% 
  select(-X, -Y) %>%
  ungroup() # remove rowwise class

(using dplyr 0.7.0 so that mutate returns a list-column without getting upset).

I believe this should basically be a valid sf object, but it doesn't seem to be the case (e.g. I cannot use st_crs even after setting the class manually to include sf). What did I miss? And surely there's a more natural way to do the above (without having to fall back on sp functions). Thanks much!

ateucher commented 7 years ago

You can use st_as_sf.

If you just have two columns with coordinates as you do in df, you can do:

df <- data.frame(feature = 1:10, X = rnorm(10), Y = rnorm(10) )
st_as_sf(df, coords = c("X", "Y"))

If you already have an sfc list-column in the data frame (which I think is the main thrust of your question), use the sf_column_name argument in st_as_sf:

sf <-
df %>%
  rowwise() %>%
  mutate(geometry = st_geometry(st_point(c(X, Y)))) %>% 
  select(-X, -Y) %>%
  ungroup()

st_as_sf(sf, sf_column_name = "geometry")
cboettig commented 7 years ago

Thanks @ateucher , that's brilliant and makes so much sense. Don't know how I missed the data.frame method for st_as_sf with those super convenient arguments.

dmi3kno commented 7 years ago

Thank you, @ateucher for the useful tip. The following code adds a geometry column to the tibble for me:

data.frame(feature = 1:10, X = rnorm(10), Y = rnorm(10) ) %>% 
    st_as_sf(coords = c("X", "Y"))

I understand that after this operation my tibble has changed the class to sf and see the logic. However, given that tibbles can store lists, one could think of a mutate-compatible method like this:

data.frame(feature = 1:10, X = rnorm(10), Y = rnorm(10) ) %>% 
    mutate(geometry=st_geometry(X, Y))

Here st_geometry(df, x, y) is effectively a vectorized tidyeval wrapper around st_point, which takes a data frame and two quosures and outputs a list of geometries.