将字符线串转换为 sf 中的几何图形

convert character linestring to geometry in sf

基本问题,如何将 character LINESTRING 类型的变量转换为 sf 中的 geometry 类型,然后分别将两个坐标分成不同的变量。例如

library(tidyverse)
library(sf)
df <- structure(list(geometry = c("LINESTRING (-85.76 38.34, -85.72 38.38)", 
                            "LINESTRING (-85.46 38.76, -85.42 38.76)", 
                            "LINESTRING (-85.89 38.31, -85.85 38.32)"
), var1 = c(4, 5, 6
), var2 = c(1, 2, 3
)), row.names = c(NA, -3L), class = c("tbl_df", "tbl", "data.frame"
))
df
# # A tibble: 3 x 3
#   geometry                                 var1  var2
#   <chr>                                   <dbl> <dbl>
# 1 LINESTRING (-85.76 38.34, -85.72 38.38)     4     1
# 2 LINESTRING (-85.46 38.76, -85.42 38.76)     5     2
# 3 LINESTRING (-85.89 38.31, -85.85 38.32)     6     3

期望的输出:

final
#                     geometry   start_lon start_lat end_lon end_lat var1 var2
# -85.76, -85.72, 38.34, 38.38      -85.76     38.34  -85.72   38.38    4    1
# -85.46, -85.42, 38.76, 38.76      -85.46     38.76  -85.42   38.76    5    2
# -85.89, -85.85, 38.31, 38.32      -85.89     38.31  -85.85   38.32    6    3


#so I can quickly plot lines between points
plot(final[, "var1"])

我认为像 final <- st_as_sf(df) %>% st_geometry(geometry) 这样的组合可以转换它,但我想不通。也许 sfheaders 在这里有用?

编辑

我想要一个 sf 类型的解决方案,而不是手动提取坐标。

有什么建议吗? 谢谢

我不熟悉提到的包,但使用正则表达式我们可以做类似的事情

gsub("[^0-9\.\s-]", "", df$geometry, perl= TRUE)

对于所需的输出,我们可以使用

df <- cbind.data.frame(df, do.call("rbind.data.frame", lapply(strsplit(gsub("[^0-9\.\s-]", "", df$geometry, perl= TRUE), " "), function(i) as.numeric(i[2:length(i)]))))
df <- df[ , c(1, 4:7, 2, 3)]
names(df) <- c("geometry", "start_lon", "start_lat", "end_lon", "end_lat", "var1", "var2")

它的作用:gsub提取你感兴趣的字符,strsplit在每个space之后拆分字符串,lapply中的部分是删除每个首先 space 并转换为数字, do.call 将所有内容绑定到数据框。最后,我们更改列顺序并命名列。

library(sf) 可以直接读取知名文本,如果你告诉它使用 wkt = 参数。这为您提供了 sf 对象。

sf <- sf::st_as_sf( df, wkt = "geometry" )
sf
# Simple feature collection with 3 features and 2 fields
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: -85.89 ymin: 38.31 xmax: -85.42 ymax: 38.76
# CRS:            NA
#                         geometry var1 var2
# 1 LINESTRING (-85.76 38.34, -...    4    1
# 2 LINESTRING (-85.46 38.76, -...    5    2
# 3 LINESTRING (-85.89 38.31, -...    6    3

然后有很多方法可以获取坐标并重新整形。在这里,我使用 sfheaders 将 sf 对象转换为长 data.frame,然后使用 library(data.table) 对其进行整形。

library(sfheaders)
library(data.table)

dt <- sfheaders::sf_to_df( sf, fill = TRUE )
setDT( dt )

## In this example, every 2nd row is to be made into new columns

odds <- 1:nrow(dt) %% 2 == 1
evens <- !odds

dt <- dt[odds][
  dt[evens, .(end_lon = x, end_lat = y, linestring_id)]
  , on = "linestring_id"
]

setnames( dt, c("x","y"), c("start_lon", "start_lat"))

dt
#    var1 var2 sfg_id linestring_id start_lon start_lat end_lon end_lat
# 1:    4    1      1             1    -85.76     38.34  -85.72   38.38
# 2:    5    2      2             2    -85.46     38.76  -85.42   38.76
# 3:    6    3      3             3    -85.89     38.31  -85.85   38.32