Search code examples
rr-sf

How to make a data frame into a simple features data frame?


I've got a table with place references and x and y coordinates in a given coordinate reference system. I want to turn that into a simple feature data frame. How can I create that?

I thought it might be:

data_frame(place = "London", 
           lat = 51.5074, lon = 0.1278, 
           epsg = 4326) %>%
  group_by(place) %>%
  mutate(feature = st_point(c(lon, lat)))

But that leads to an error:

Error in mutate_impl(.data, dots) : Column feature must be length 1 (the group size), not 2

This is probably pretty simple to do, I'm just not seeing it readily discussed in the documentation. Most spatial analysts seem to demand better data by default :).

I also thought to try:

data_frame(place = "London", 
           lat = 51.5074, lon = 0.1278, 
           epsg = 4326) %>%
  group_by(place) %>%
  do(with(., {
    p <- st_point(c(lon, lat))
    pcol <- st_as_sfc(p)
    st_as_sf(data_frame(place = place,
                        point = pcol),
             crs = epsg)
  }))

At the end of the pipe, I want a simple features data frame that I can plot and manipulate like any other.

Another rub with what I'm trying to do is that I've got a data frame with a column for EPSG. I need to create this simple features data frame for each place and combine that all together into a larger simple features data frame.


Solution

  • UPDATE The answer from @Franz Plumpton is the correct solution with a single epsg. My answer below is only necessary when each row of a data.frame has a different epsg. Otherwise, this would be a duplicate (as pointed out by @Henrik above).

    library(sf)
    library(tibble)
    
    df <- data_frame(place = c("London", "Kalamazoo"), 
               lat = c(51.5074, 396088), lon = c(0.1278, 5452158),
               epsg = c(4326, 32610))
    
    l <- lapply(unique(df$place), function(x){
      df <- df[df$place == x,]
      epsg <- df$epsg[1]
      df  <-  st_as_sf(df, coords = c('lon', 'lat'), crs = epsg)
    }) 
    

    you could then transform all to the same epsg and combine into a single data.frame:

    do.call(rbind, lapply(l, function(x) x <- st_transform(x, 4326)))