r - Create linestring from two points in same row in dataframe
We can loop through the rows, with pmap
and apply the st_linestring
on a matrix
created
library(tidyverse)
library(sf)
out <- pmap(df[-1], ~
c(...) %>%
matrix(., , ncol=2, byrow = TRUE) %>%
st_linestring) %>%
reduce(st_sfc) %>%
mutate(df, geometry = .)
out$geometry
#Geometry set for 2 features
#geometry type: LINESTRING
#dimension: XY
#bbox: xmin: 1 ymin: 3 xmax: 6 ymax: 8
#epsg (SRID): NA
#proj4string: NA
#LINESTRING (1 3, 5 7)
#LINESTRING (2 4, 6 8)
Update - 30th Jan 2021
The issue with my original answer is it doesn't correctly set the bounding box.
Today I would use this approach using sfheaders
and data.table
library(data.table)
library(sfheaders)
dt <- as.data.table(df)
## To use `sfheaders` the data needs to be in long form
dt1 <- dt[, .(id, lon = lon1, lat = lat1)]
dt2 <- dt[, .(id, lon = lon2, lat = lat2)]
## Add on a 'sequence' variable so we know which one comes first
dt1[, seq := 1L ]
dt2[, seq := 2L ]
## put back together
dt <- rbindlist(list(dt1, dt2), use.names = TRUE)
setorder(dt, id, seq)
sf <- sfheaders::sf_linestring(
obj = dt
, x = "lon"
, y = "lat"
, linestring_id = "id"
)
sf
# Simple feature collection with 2 features and 1 field
# geometry type: LINESTRING
# dimension: XY
# bbox: xmin: 1 ymin: 3 xmax: 6 ymax: 8
# CRS: NA
# id geometry
# 1 a LINESTRING (1 3, 5 7)
# 2 b LINESTRING (2 4, 6 8)
Original Answer
An alternative approach using data.table
require(data.table)
dt <- as.data.table(df)
sf <- dt[
, {
geometry <- sf::st_linestring(x = matrix(c(lon1, lon2, lat1, lat2), nrow = 2, ncol = 2))
geometry <- sf::st_sfc(geometry)
geometry <- sf::st_sf(geometry = geometry)
}
, by = id
]
sf::st_as_sf(sf)
# Simple feature collection with 2 features and 1 field
# geometry type: LINESTRING
# dimension: XY
# bbox: xmin: 1 ymin: 3 xmax: 5 ymax: 7
# epsg (SRID): NA
# proj4string: NA
# id geometry
# 1 a LINESTRING (1 3, 5 7)
# 2 b LINESTRING (2 4, 6 8)