【问题标题】:How to do a "full" union with the R package sf如何与 R 包 sf 进行“完整”联合
【发布时间】:2019-02-15 13:39:09
【问题描述】:

我尝试使用sf::st_union 在三个多边形之间进行联合。在下图中显示了 ArcGIS "Overlay, Union, All" 的结果,我希望通过使用 R 中的 sf 包获得与 'OUTPUT' 中的五个不同多边形相似的结果。

library(sf)
a1 <- st_polygon(list(rbind(c(0, 10), c(45, 10), c(45, 90), c(0, 90), c(0, 10))))
a2 <- st_polygon(list(rbind(c(45, 10), c(90,10), c(90, 90), c(45, 90), c(45, 10))))
b <- st_polygon(list(rbind(c(15, 5), c(75, 5), c(75, 50), c(15, 50), c(15, 5))))
a <- st_sf(c(st_sfc(a1), st_sfc(a2)))
b <- st_sf(st_sfc(b))
a$station <- c(1, 2)
b$type <- "A"
ab_union <- st_union(a, b)

在这个简单的示例中,生成的 sf 对象“ab_union”将只包含两个多边形,而不是预期的五个。我可以通过使用sf包中的函数得到上图五个对象的想要的结果吗?

【问题讨论】:

    标签: r sf


    【解决方案1】:

    我没有找到可以一步完成所有事情的功能,但这是解决您的问题的一种方法:

    library(sf)
    #> Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
    library(tidyverse)
    
    a1 <- st_polygon(list(rbind(c(0, 10), c(45, 10), c(45, 90), c(0, 90), c(0, 10))))
    a2 <- st_polygon(list(rbind(c(45, 10), c(90,10), c(90, 90), c(45, 90), c(45, 10))))
    b1 <- st_polygon(list(rbind(c(15, 5), c(75, 5), c(75, 50), c(15, 50), c(15, 5))))
    
    a <- st_sf(station=c(1, 2), geometry=st_sfc(a1, a2))
    b <- st_sf(type="A",   geometry=st_sfc(b1))
    
    st_agr(a) = "constant" #to avoid warnings, but see https://github.com/r-spatial/sf/issues/406
    st_agr(b) = "constant"
    
    #Operations
    plot(st_geometry(st_union(a,b)))
    
    op1 <- st_difference(a,st_union(b)) #notice the use of st_union()
    plot(st_geometry(op1), border="red", add=TRUE)
    
    op2 <- st_difference(b, st_union(a)) #notice the order of b and a and st_union()
    plot(st_geometry(op2), border="green", add=TRUE)
    
    op3 <- st_intersection(b, a) #notice the order of b and a
    plot(st_geometry(op3), border="blue", add=TRUE)
    
    union <- rbind(op1, op2, op3) #Error because op1 (op2) doesn't have the column "type" ("station")
    #> Error in match.names(clabs, names(xi)): names do not match previous names
    
    op11 <- dplyr::mutate(op1, type=NA)
    op22 <- dplyr::mutate(op2, station=NA)
    
    union <- rbind(op11, op22, op3)
    (as.data.frame(union)) #The row names must be ordered.
    #>     station type                       geometry
    #> 1         1 <NA> POLYGON ((15 10, 0 10, 0 90...
    #> 2         2 <NA> POLYGON ((45 50, 45 90, 90 ...
    #> 3        NA    A POLYGON ((75 10, 75 5, 15 5...
    #> 11        1    A POLYGON ((15 10, 15 50, 45 ...
    #> 1.1       2    A POLYGON ((45 50, 75 50, 75 ...
    plot(union)
    
    
    #Other approach for avoid create the new columns would be:
    
    union2 <- dplyr::bind_rows(op1, op2, op3) #But see discusion here: https://github.com/r-spatial/sf/issues/49
    #> Warning in bind_rows_(x, .id): Vectorizing 'sfc_POLYGON' elements may not
    #> preserve their attributes
    
    #> Warning in bind_rows_(x, .id): Vectorizing 'sfc_POLYGON' elements may not
    #> preserve their attributes
    
    #> Warning in bind_rows_(x, .id): Vectorizing 'sfc_POLYGON' elements may not
    #> preserve their attributes
    

    reprex package (v0.2.1) 于 2019 年 4 月 6 日创建

    我参考的讨论:
    https://github.com/r-spatial/sf/issues/406

    https://github.com/r-spatial/sf/issues/49

    【讨论】:

    • 感谢您的出色解决方案!对于 op3,我认为不需要 a 或 b 的特定顺序,因为您只保留两者的相交区域。我很惊讶我还没有找到内置的解决方案?
    【解决方案2】:

    我也需要这样的功能,所以这是我的任意 sf 对象版本,避免显式添加缺失的列。它还需要“plyr”库(函数 rbind.fill):

    my_union <- function(a,b) {
       #
       # function doing a real GIS union operation such as in QGIS or ArcGIS
       #
       # a - the first sf
       # b - the second sf
       #
       st_agr(a) = "constant"
       st_agr(b) = "constant"
       op1 <- st_difference(a,st_union(b))
       op2 <- st_difference(b, st_union(a))
       op3 <- st_intersection(b, a)
       union <- rbind.fill(op1, op2, op3)
       return(st_as_sf(union))
    }
    

    【讨论】:

    • 感谢您的简化。但是我不能让它工作。运行代码后,我尝试查看生成的数据帧,但得到“CPL_get_z_range(obj, 2) 中的错误:z 错误 - 需要三列”。我使用版本 sf 1.0-2、plyr 1.8.6、R 4.1.1。
    • 我认为这是因为您的输入数据中至少有一些在坐标中具有 z 值。到目前为止,我只在 XY 数据上使用过这个。
    • 坐标中没有 z 值。我使用了最初帖子中的测试数据。这里的几何图形命名不正确。当使用用 CamiloEr 的代码创建的相同测试数据时,一切正常。
    猜你喜欢
    • 2017-10-03
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    相关资源
    最近更新 更多