Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sf: Write Lat/Long from geometry into separate column and keep ID column

Tags:

r

sf

I have a df with polygon ID's from a shapefile and their centre-points in a geometry column:

# A tibble: 3 x 2
     ID     geometry
  <dbl> <POINT [°]>
1     1 (117.2 31.8)
2     2 (116.4 40.1)
3     4   (117.9 26)

I want to put the latitude/longitude values into separate columns, so I do:

library(sf)
centres<- as.data.frame(st_coordinates(df))

This new 'centres' dataframe has the lat&long values, but misses the ID column. How can I preserve it, or is there another way to get the lat&long values into separate columns from the geometry column whilst keeping the ID in the same df?

dput for the dataframe is:

df <- structure(list(ID = c(1, 2, 4), 
      geometry = structure(list(structure(c(117.2, 31.8), 
      class = c("XY", "POINT", "sfg")), structure(c(116.4, 40.1), 
      class = c("XY", "POINT", "sfg")), structure(c(117.9, 26.0), 
      class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT", "sfc"), 
      precision = 0, bbox = structure(c(xmin = 116.4, ymin = 26.0, xmax = 117.9, ymax = 40.1), 
      class = "bbox"), crs = structure(list(epsg = 4326L, 
      proj4string = "+proj=longlat +datum=WGS84 +no_defs"), class = "crs"), n_empty = 0L)), 
      row.names = c(NA, -3L), class = c("sf", "tbl_df", "tbl", "data.frame"), 
      sf_column = "geometry", agr = structure(c(ID = NA_integer_), 
      class = "factor", .Label = c("constant", "aggregate", "identity")))
like image 905
Jorrit G Avatar asked Feb 17 '19 15:02

Jorrit G


3 Answers

Solution using unlist + map()

library(tidyverse)

separated_coord <- df %>%
    mutate(lat = unlist(map(df$geometry,1)),
           long = unlist(map(df$geometry,2)))

separated_coord
like image 105
Henry Cyranka Avatar answered Sep 19 '22 02:09

Henry Cyranka


st_geometry can be used with dplyr::mutate:

library(magrittr) #for the pipe
df <- df %>%
  dplyr::mutate(lon = sf::st_coordinates(.)[,1],
                lat = sf::st_coordinates(.)[,2])

df
Simple feature collection with 3 features and 3 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: 116.4 ymin: 26 xmax: 117.9 ymax: 40.1
CRS:            EPSG:4326
# A tibble: 3 x 4
     ID     geometry   lon   lat
* <dbl>  <POINT [°]> <dbl> <dbl>
1     1 (117.2 31.8)  117.  31.8
2     2 (116.4 40.1)  116.  40.1
3     4   (117.9 26)  118.  26 

And if you no longer care about geometry, transform in a standard dataframe using df %>% sf::st_set_geometry(NULL)

like image 43
linog Avatar answered Sep 17 '22 02:09

linog


A possible approach is to unlist it.

setNames(data.frame(df[[1]], 
                    matrix(unlist(df[2]), ncol=2, byrow=TRUE)), 
         c("ID", "lon", "lat"))

#   ID   lon  lat
# 1  1 117.2 31.8
# 2  2 116.4 40.1
# 3  4 117.9 26.0

Explanation

Data structure check with str(df) shows, that a variable - geometry - is in list format, which can be unhandy. A way to solve this is to unlist() it, transform it into a 2-column matrix, and reassemble it with the first column. With setNames() we are able to assign new column names in one step.

like image 41
jay.sf Avatar answered Sep 18 '22 02:09

jay.sf