简体   繁体   中英

Create sf object from data frame with multiple coordinates | R sf

I want to create an sf object from a data frame that contains multiple coordinates under different columns for each row. In the repex below, each ID contains start and end coordinates for both latitude and longitude.

在此处输入图片说明

dfr <- structure(list(ID = c("1001A", "1002A", "1003A", "1004A", "1005A", 
"1006A", "1007A", "1008A", "1009A", "1010A"), StartLat = c(33.53418, 
33.60399, 33.40693, 33.64672, 33.57127, 33.42848, 33.54936, 33.49554, 
33.5056, 33.61696), StartLong = c(-112.09114, -111.92731, -112.02982, 
-111.92548, -112.04899, -112.0998, -112.09123, -111.9687, -112.05629, 
-111.98657), EndLat = c(33.53488, 33.60401, 33.40687, 33.64776, 
33.57125, 33.42853, 33.54893, 33.49647, 33.5056, 33.61654), EndLong = c(-112.09114, 
-111.93097, -112.03429, -111.93031, -112.04807, -112.09929, -112.09122, 
-111.97105, -112.0541, -111.98657)), row.names = c(3028L, 8618L, 
6322L, 1171L, 691L, 6590L, 2008L, 4552L, 2894L, 1909L), class = "data.frame")

I tried using the sf package's st_as_sf function, but it yields an error:

dfr_sf <- st_as_sf(dfr, coords = c(c("StartLong", "EndLong"), c("StartLat", "EndLat")),
                   crs = "+proj=longlat +datum=WGS84")
Error in points_rcpp(as.matrix(cc), dim) : 
  dim(pts)[2] == nchar(gdim) is not TRUE

The start and end coordinates in each row define a road segment. All the coordinates should go under the geometry column in the final sf object so that these can be plotted as polylines.

Please see if dfr_line is what you want. I think the idea is we need to create a point sf object first, and the convert it to linestring.

library(tidyverse)
library(sf)

dfr2 <- dfr %>%
  pivot_longer(cols = -ID, names_to = "Coord", values_to = "Value") %>%
  extract(Coord, into = c("Type", "Coord"), regex = "(Start|End)(Long|Lat)") %>%
  pivot_wider(names_from = "Coord", values_from = "Value")

dfr_point <- dfr2 %>%
  st_as_sf(coords = c("Long", "Lat"), crs = "+proj=longlat +datum=WGS84")

dfr_line <- dfr_point %>%
  select(-Type) %>%
  group_by(ID) %>%
  summarize() %>%
  st_cast("LINESTRING")

Please find an alternative solution with data.table and sf libraries. I hope I am not wrong: the lines appear in Arizona.

library(data.table)
library(sf)
library(dplyr)

# Reshape the data.table 'dfr' into long format
dfr2 <- melt(setDT(dfr), measure= patterns("Long", "Lat"), 
          value.name= c("Longitude", "Latitude"), na.rm=TRUE)[,variable:=NULL][]


# function 'rename_geom_col' to rename the geometry column of the 'sf' object
rename_geom_col <- function(x, new_name){
  current_name  <-  attr(x, "sf_column")
  names(x)[names(x)==current_name]  <- new_name
  st_geometry(x) <- new_name
  return(x)
}

# Convert the data.table 'dfr2' into the linestring 'sf' object 'results'
results <- dfr2 %>% 
  split(., by = "ID", keep.by = FALSE) %>% 
  lapply(., as.matrix) %>% 
  lapply(.,st_linestring) %>%
  st_as_sfc() %>% 
  st_as_sf %>% 
  st_set_crs(4326) %>% 
  mutate(ID = dfr2[1:(nrow(dfr2)/2),"ID"]) %>% 
  relocate(x, .after = last_col()) %>% 
  rename_geom_col(., "geom")


results
#> Simple feature collection with 10 features and 1 field
#> Geometry type: LINESTRING
#> Dimension:     XY
#> Bounding box:  xmin: -112.0998 ymin: 33.40687 xmax: -111.9255 ymax: 33.64776
#> Geodetic CRS:  WGS 84
#>       ID                           geom
#> 1  1001A LINESTRING (-112.0911 33.53...
#> 2  1002A LINESTRING (-111.9273 33.60...
#> 3  1003A LINESTRING (-112.0298 33.40...
#> 4  1004A LINESTRING (-111.9255 33.64...
#> 5  1005A LINESTRING (-112.049 33.571...
#> 6  1006A LINESTRING (-112.0998 33.42...
#> 7  1007A LINESTRING (-112.0912 33.54...
#> 8  1008A LINESTRING (-111.9687 33.49...
#> 9  1009A LINESTRING (-112.0563 33.50...
#> 10 1010A LINESTRING (-111.9866 33.61...

Created on 2021-11-16 by the reprex package (v2.0.1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM