sf icon indicating copy to clipboard operation
sf copied to clipboard

Loop 0 is not valid: Edge x has duplicate vertex with edge y.

Open andybeet opened this issue 3 years ago • 3 comments

This is an error that never used to arise. Is is due to an sf update or something else? Not sure how to trouble shoot this.

shapefile (strata.shp) is located: url <- "https://github.com/NOAA-EDAB/survdat/tree/master/inst/extdata/"

areaPolygon <- sf::st_read(dsn = system.file("extdata", "strata.shp",package = "survdat"), quiet = T)
sf::st_area(areaPolygon)
#> Error in s2_geography_from_wkb(x, oriented = oriented, check = check): Evaluation error: Found 3 features with invalid spherical geometry.
#> [145] Loop 0 is not valid: Edge 520 has duplicate vertex with edge 661
#> [159] Loop 0 is not valid: Edge 804 has duplicate vertex with edge 824
#> [276] Loop 0 is not valid: Edge 470 has duplicate vertex with edge 482.

Created on 2021-08-17 by the reprex package (v2.0.1)

library(sf)
#> Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1

Created on 2021-08-17 by the reprex package (v2.0.1)

Session Info
  • Session info -------------------------------------------------------------------------- setting value
    version R version 4.0.5 (2021-03-31) os Windows 10 x64
    system x86_64, mingw32
    ui RStudio
    language (EN)
    collate English_United States.1252
    ctype English_United States.1252
    tz America/New_York
    date 2021-08-17

  • Packages ------------------------------------------------------------------------------ package * version date lib source
    assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.0.3) class 7.3-19 2021-05-03 [1] CRAN (R 4.0.5) classInt 0.4-3 2020-04-07 [1] CRAN (R 4.0.3) cli 3.0.1 2021-07-17 [1] CRAN (R 4.0.5) clipr 0.7.1 2020-10-08 [1] CRAN (R 4.0.3) crayon 1.4.1 2021-02-08 [1] CRAN (R 4.0.4) data.table 1.14.0 2021-02-21 [1] CRAN (R 4.0.4) DBI 1.1.1 2021-01-15 [1] CRAN (R 4.0.3) dplyr 1.0.7 2021-06-18 [1] CRAN (R 4.0.5) e1071 1.7-8 2021-07-28 [1] CRAN (R 4.0.5) ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.0.5) fansi 0.5.0 2021-05-25 [1] CRAN (R 4.0.5) generics 0.1.0 2020-10-31 [1] CRAN (R 4.0.3) glue 1.4.2 2020-08-27 [1] CRAN (R 4.0.3) KernSmooth 2.23-20 2021-05-03 [1] CRAN (R 4.0.5) lifecycle 1.0.0 2021-02-15 [1] CRAN (R 4.0.4) magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.0.3) pillar 1.6.2 2021-07-29 [1] CRAN (R 4.0.5) pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.0.3) proxy 0.4-26 2021-06-07 [1] CRAN (R 4.0.5) purrr 0.3.4 2020-04-17 [1] CRAN (R 4.0.3) R6 2.5.0 2020-10-28 [1] CRAN (R 4.0.3) Rcpp 1.0.7 2021-07-07 [1] CRAN (R 4.0.5) rlang 0.4.10 2020-12-30 [1] CRAN (R 4.0.3) rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.0.3) s2 1.0.6 2021-06-17 [1] CRAN (R 4.0.5) sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.0.3) sf 1.0-2 2021-07-26 [1] CRAN (R 4.0.5) survdat 1.0 2021-07-16 [1] local
    tibble 3.1.3 2021-07-23 [1] CRAN (R 4.0.5) tidyselect 1.1.1 2021-04-30 [1] CRAN (R 4.0.5) units 0.7-2 2021-06-08 [1] CRAN (R 4.0.5) utf8 1.2.2 2021-07-24 [1] CRAN (R 4.0.5) vctrs 0.3.8 2021-04-29 [1] CRAN (R 4.0.5) withr 2.4.2 2021-04-18 [1] CRAN (R 4.0.5) wk 0.5.0 2021-07-13 [1] CRAN (R 4.0.5)

[1] C:/~/R/win-library/4.0 [2] C:/Program Files/R/R-4.0.5/library

andybeet avatar Aug 17 '21 19:08 andybeet

It would be great if you could provide the data set that generated this, if needed off-line (email), to help us understand what causes this.

The solution to this is to first set

sf_use_s2(FALSE)

edzer avatar Aug 17 '21 19:08 edzer

edited: added a useful reprex. apologies. And thanks for the fix.

andybeet avatar Aug 17 '21 19:08 andybeet

Also appears with rworldmap

library(rworldmap)
data(countryExData)
p <- st_sf(geometry= st_sfc(st_polygon(list(matrix(c(
  3, 40, 
  3,  51, 
  25, 51, 
  25, 40, 
  3, 40),5,2, byrow=T)))), crs="+proj=latlong +datum=WGS84")
cntr <- st_intersection(st_as_sf(countriesLow), p)

But the workaround helps.

mkschneider avatar Dec 09 '21 08:12 mkschneider

In case it's useful there's another example posted at http://www.math.mcmaster.ca/bolker/misc/wwf_terr_ecos.shp

library(spdep)
shp <- as(sf::st_read("wwf_terr_ecos.shp"), "Spatial")
## sf_use_s2(FALSE)
p <- poly2nb(shp)

If this is a problem with the data set, could you point me to ways of diagnosing/fixing it ...?

bbolker avatar Oct 11 '22 16:10 bbolker

@bbolker please contribute the whole set of *.shp, *.shx, *.dbf at least, probably also *.prj. Four files are needed if the position data have a CRS. Note that spdep::poly2nb() has accepted sf objects for years. The shapefile is large, probably old, probably therefore poorly specified, and subject to all the manifold drawbacks of a deprecated format.

rsbivand avatar Oct 11 '22 17:10 rsbivand

Will do, thanks. I got it second-hand, but getting the latest (??) version from here: https://www.sciencebase.gov/catalog/item/508fece8e4b0a1b43c29ca22 (and the version from https://www.worldwildlife.org/publications/terrestrial-ecoregions-of-the-world) still throws the same error.

 shp <- sf::st_read("wwf2/wwf_terr_ecos.shp")
 p <- poly2nb(shp)

bbolker avatar Oct 11 '22 17:10 bbolker

Thanks! As an alternative you might try

p <- poly2nb(st_make_valid(shp))

if you want to stay on a round rather than a flat Earth. We explain here why many polygons cannot be valid on S2 and R2 simultaneously.

edzer avatar Oct 11 '22 17:10 edzer

> shp <- sf::st_read("official/wwf_terr_ecos.shp")
Reading layer `wwf_terr_ecos' from data source 
  `/home/rsb/tmp/bigshape/official/wwf_terr_ecos.shp' using driver `ESRI Shapefile'
Simple feature collection with 14458 features and 21 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -89.89197 xmax: 180 ymax: 83.62313
Geodetic CRS:  WGS 84
> p <- spdep::poly2nb(shp)
Error in wk_handle.wk_wkb(wkb, s2_geography_writer(oriented = oriented,  : 
  Loop 15 is not valid: Edge 0 has duplicate vertex with edge 4
> table(sf::st_is_valid(shp))

FALSE  TRUE 
    1 14457 
> shp[!sf::st_is_valid(shp),]
Simple feature collection with 1 feature and 21 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -63.00804 ymin: 1.112058 xmax: -50.96594 ymax: 8.663469
Geodetic CRS:  WGS 84
     OBJECTID     AREA PERIMETER              ECO_NAME REALM BIOME ECO_NUM
1526     1501 475923.6    75.484 Guianan moist forests    NT     1      25
     ECO_ID ECO_SYM GBL_STAT            G200_REGIO G200_NUM G200_BIOME
1526  60125      70        3 Guianan Moist Forests       42          1
     G200_STAT Shape_Leng Shape_Area area_km2 eco_code PER_area PER_area_1
1526         0   75.31988   38.78856   476136   NT0125        0          0
     PER_area_2                       geometry
1526          0 POLYGON ((-62.54998 7.93176...
> p <- spdep::poly2nb(sf::st_make_valid(shp))
> p
Neighbour list object:
Number of regions: 14458 
Number of nonzero links: 16076 
Percentage nonzero weights: 0.007690624 
Average number of links: 1.11191 
8601 regions with no links:
5 8 9 18 20 23 24 25 26 27 28 29 31 32 33 34 35 36 37 39 44 45 46 47 48
50 51 52 53 58 59 61 62 64 65 66 69 70 72 74 76 77 79 83 87 89 90 91 92
93 94 95 96 99 100 101 102 104 105 106 107 108 110 113 114 115 116 125
150 151 153 184 187 188 189 190 191 201 204 206 208 232 250 254 255 264
268 275 279 296 302 303 306 311 317 319 320 324 325 326 335 339 342 343
...

I assume that spdep::poly2nb() isn't the intended use. The polygons do not seem to be a tessellation. More than half have no neighbour for many values of snap=, possibly islands of course, but a bit meaningless, and some overlap.

rsbivand avatar Oct 11 '22 18:10 rsbivand

Thanks, that's very useful! I'm feeling my way around a bit with this (cargo-culting), will talk to my more spatially savvy collaborator. You've been immensely helpful.

bbolker avatar Oct 11 '22 18:10 bbolker

Dear Prof. @rsbivand @edzer , It seems that both "sf_use_s2(F)", and "st_make_valid(shp)" do not work for me. How can I fix the following errors?

Best wishes, Shunsen

county_shape2 <- read_sf("ssss.shp") nb2 <- poly2nb(county_shape2) Error in wk_handle.wk_wkb(wkb, s2_geography_writer(oriented = oriented, : Loop 0 is not valid: Edge 127 has duplicate vertex with edge 129 weight_matrix2 <- nb2listw(nb2, style = "W") Error in nb2listw(nb2, style = "W") : Empty neighbour sets found

st_is_longlat(county_shape2) [1] TRUE sf_use_s2() [1] TRUE sf_use_s2(F) Spherical geometry (s2) switched off nb2 <- poly2nb(county_shape2) although coordinates are longitude/latitude, st_intersects assumes that they are planar weight_matrix2 <- nb2listw(nb2, style = "W") Error in nb2listw(nb2, style = "W") : Empty neighbour sets found nb2 <- poly2nb(st_make_valid(county_shape2)) although coordinates are longitude/latitude, st_intersects assumes that they are planar There were 18 warnings (use warnings() to see them) warnings() warnings: 1: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 2: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 3: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 4: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 5: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 6: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 7: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 8: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 9: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 10: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 11: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 12: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 13: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 14: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 15: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 16: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 17: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained 18: In st_cast.GEOMETRYCOLLECTION(X[[i]], ...) : only first part of geometrycollection is retained weight_matrix2 <- nb2listw(nb2, style = "W") Error in nb2listw(nb2, style = "W") : Empty neighbour sets found

nb2 <- poly2nb(st_make_valid(county_shape2)) although coordinates are longitude/latitude, st_intersects assumes that they are planar There were 18 warnings (use warnings() to see them) weight_matrix2 <- nb2listw(nb2, style = "W") Error in nb2listw(nb2, style = "W") : Empty neighbour sets found sf_use_s2(T) Spherical geometry (s2) switched on nb2 <- poly2nb(st_make_valid(county_shape2)) Error in wk_handle.wk_wkb(wkb, s2_geography_writer(oriented = oriented, : Loop 0 is not valid: Edge 0 crosses edge 46 weight_matrix2 <- nb2listw(nb2, style = "W") Error in nb2listw(nb2, style = "W") : Empty neighbour sets found

Shunsenhuang-123 avatar Mar 15 '23 00:03 Shunsenhuang-123

Reproducible example needed. Did you examine the output nb object to check for no-neighbour observations? Did you try a different snap= value? This is not an sf issue.

rsbivand avatar Mar 15 '23 06:03 rsbivand

Dear Prof. @rsbivand , Thank your feedback.

I have tried the snap=value, and check for no-neighbour observations. here are the results, and I attached the reporducible example and the .shp file. So if it is not the sf issue, could it be the issue of the .shp file? if it is, how can I fix it? Because only using st_make_valid did not work well.

Best wishes,

code and data.zip

results:

county_shape2 <- read_sf("中华人民共和国.shp") #county_shape2 <- county_shape2[!is.na(county_shape2$name) ,] sf_use_s2() [1] TRUE eps <- sqrt(2.220446e-22) table(st_is_valid(county_shape2))

FALSE TRUE 20 15

county_shape_valid <- st_make_valid(county_shape2) table(st_is_valid(county_shape_valid))

FALSE TRUE 5 30

summary(county_shape_valid) adcode name center centroid
Min. :110000 Length:35 Min. : NA Min. : NA
1st Qu.:312500 Class :character 1st Qu.: NA 1st Qu.: NA
Median :425000 Mode :character Median : NA Median : NA
Mean :423235 Mean :NaN Mean :NaN
3rd Qu.:537500 3rd Qu.: NA 3rd Qu.: NA
Max. :820000 Max. : NA Max. : NA
NA's :1 NA's :35 NA's :35
childrenNu level parent subFeature
Min. : 0.00 Length:35 Min. : NA Min. : 0.00
1st Qu.:10.25 Class :character 1st Qu.: NA 1st Qu.: 8.25
Median :14.00 Mode :character Median : NA Median :16.50
Mean :13.97 Mean :NaN Mean :16.50
3rd Qu.:16.00 3rd Qu.: NA 3rd Qu.:24.75
Max. :38.00 Max. : NA Max. :33.00
NA's :1 NA's :35 NA's :1
acroutes adchar geometry Min. : NA Length:35 MULTIPOLYGON :35
1st Qu.: NA Class :character epsg:4326 : 0
Median : NA Mode :character +proj=long...: 0
Mean :NaN
3rd Qu.: NA
Max. : NA
NA's :35
nb2 <- poly2nb(county_shape2,snap = eps) Error in wk_handle.wk_wkb(wkb, s2_geography_writer(oriented = oriented, : Loop 0 is not valid: Edge 127 has duplicate vertex with edge 129 weight_matrix2 <- nb2listw(nb2, style = "W")

Reproducible example needed. Did you examine the output nb object to check for no-neighbour observations? Did you try a different snap= value? This is not an sf issue.

Shunsenhuang-123 avatar Mar 16 '23 05:03 Shunsenhuang-123

You only included a *.shp file. A shapefile is at least 3 files, *.shx, *.dbf, and preferably *.prj, and *.cpg if coming from a Windows codepage. For me, only UTF-8 is legible, so please change the basename of the files to ASCII. The single *.shp file can be supplemented by a guessed *.shx file by SHAPE_RESTORE_SHX=YES ogrinfo x.shp. On that basis:

library(sf)
x <- read_sf("x.shp")
st_crs(x) <- "EPSG:4326"
sf_use_s2(FALSE) # the input geometries are bad, and wrong spherically
x1 <- st_make_valid(x)
all(st_is_valid(x1))
library(spdep)
nb <- poly2nb(x1) # snap not required
nb
plot(st_geometry(x1), border="grey")
plot(nb, st_geometry(x1), add=TRUE)

image where the three entities without neighbours are islands, so do not share boundaries with other entities. Consider reporting back to the provider of the original shapefile that the polygons are not proper spherical geometries. See also https://r-spatial.org/book/04-Spherical.html.

rsbivand avatar Mar 16 '23 13:03 rsbivand

Moving this to #1771

edzer avatar Mar 27 '23 18:03 edzer