r-spatial / sf

Simple Features for R
https://r-spatial.github.io/sf/
Other
1.34k stars 298 forks source link

Finding neighboring polygons #234

Closed tiernanmartin closed 7 years ago

tiernanmartin commented 7 years ago

I use spdep::poly2nb to identify neighboring polygons, but this necessitates a conversion back to sp - is there a way to do this without that conversion?

rsbivand commented 7 years ago

Checks cleanly here (two different Fedora machines). This looks like about line 269: try(NY8_sf_old_1_sgbp <- st_queen(NY8_sf_old)), the cited line numbers don't seem relevant. This has to be on the MULTIPOLYGON object, it can't be on the POINT object.

Can you run it with spdep from CRAN free-standing? I'll try ... success. The error message is shown as:

Error in CPL_geos_binop(st_geometry(x), st_geometry(y), op, par, pattern,  : 
  Evaluation error: TopologyException: side location conflict at 411447.38362785219 4768469.9111850867.

in chunk 31. I've added ", silent = TRUE" to the try lines to remove the verbatim error message from the output, but R CMD build worked for me anyway when it was there.

edzer commented 7 years ago

The error came from RANN not being installed; it now runs.

rsbivand commented 7 years ago

Will now run without RANN too.

rsbivand commented 7 years ago

spdep now on r-spatial on github, 0.7-2 submitted to CRAN

rikudoukarthik commented 1 year ago

This is fantastic! I've tested and it works. By extension, to get queen's case neighbors as well you can do:

st_queen <- function(a, b = a) st_relate(a, b, pattern = "F***T****")
nc %>% mutate(NB_QUEEN = st_queen(.))

which constitutes an improvement on using st_intersects for that purpose as it eliminates self-intersections.

For anyone coming across this, the Wikipedia page for DE-9IM strings is quite helpful: https://en.wikipedia.org/wiki/DE-9IM.

I created a grid using st_make_grid() and converted to an sf object. Now I am trying to create neighbours using the abovementioned st_rook() and st_queen() but I am getting the following error:

Error in xj[i, , drop = FALSE] : incorrect number of dimensions

I am not sure what exactly is the issue here. Am I inputting the wrong spatial object here? Or is it because the number of cells in X direction is not the same as that in Y direction? I also tried looking at the code of st_relate() to see if I could gather anything, but failed.

I wonder if you all have some obvious solution to my issue. If not, I can share a reprex for the same.

Edit: sharing reprex The necessary shapefiles can be found here

library(tidyverse)
library(sf)

country_path <- "data/in_2011/"
country_file <- "India_2011"
grid_sizes_km <- c(25, 50, 100, 200)
grid_sizes_deg <- grid_sizes_km*1000/111111

india_sf <- st_read(dsn = country_path, layer = country_file) %>% mutate(DISTRICT = NULL) %>% 
  st_set_crs("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")

# creating grid
g1_sf <- india_sf %>% 
  st_make_grid(cellsize = grid_sizes_deg[1],
               n = (c(diff(st_bbox(india_sf)[c(1, 3)]), diff(st_bbox(india_sf)[c(2, 4)]))/grid_sizes_deg[1]) %>% 
                 ceiling()) %>% 
  st_as_sf() %>% 
  rename(geometry = x)

# neighbours
st_rook <- function(a, b = a) st_relate(a, b, pattern = "F***1****")
st_queen <- function(a, b = a) st_relate(a, b, pattern = "F***T****")

g1_sf %>% mutate(NB_ROOK = st_rook(.),
                 NB_QUEEN = st_queen(.))
# returns error
rsbivand commented 1 year ago

Always minimal reprex. Note that this is a very old issue, and that spdep fully supports most sf objects.

rikudoukarthik commented 1 year ago

Always minimal reprex. Note that this is a very old issue, and that spdep fully supports most sf objects.

Thanks for the very quick response. I've updated my post with a reprex. Like the OP, I would like to find a way to achieve this using only sf, without having to convert to and from sp.

rsbivand commented 1 year ago

Please avoid any tidyverse and pipes in all reprex, as they prevent access to intermediate objects, in which misunderstandings typically occur. Do not use the st_rook() etc. functions, use functions in spdep.

rsbivand commented 1 year ago

Do not use +towgs84 ever. Do not expect spherical geometries as planar. Consider reading https://rsbivand.github.io/csds_jan23/csds_crs_workshop_230119.html if this seems hard to grasp. s2 does not behave like GEOS. See what happens in your (corrected) reprex with sf_use_s2(FALSE).

rsbivand commented 1 year ago

@rikudoukarthik there is no problem at all in the example:

library(sf)
country_file <- "India_2011.shp"
india_sf <- st_read(country_file)
st_crs(india_sf) <- "OGC:CRS84"
grid_sizes_km <- c(25, 50, 100, 200)
grid_sizes_deg <- grid_sizes_km*1000/111111
n <- ceiling(c(diff(st_bbox(india_sf)[c(1, 3)]), diff(st_bbox(india_sf)[c(2, 4)]))/grid_sizes_deg[1])
g1_sf <- st_make_grid(india_sf, cellsize = grid_sizes_deg[1],  n = n)
g1_sf
st_rook <- function(a, b = a) st_relate(a, b, pattern = "F***1****")
system.time(NB_ROOK <-  st_rook(g1_sf))
library(spdep)
system.time(NB_ROOK1 <- poly2nb(g1_sf, queen=FALSE))
all.equal(NB_ROOK1, NB_ROOK, check.attributes=FALSE)
st_queen <- function(a, b = a) st_relate(a, b, pattern = "F***T****")
system.time(NB_QUEEN <- st_queen(g1_sf))
system.time(NB_QUEEN1 <- poly2nb(g1_sf))
all.equal(NB_QUEEN1, NB_QUEEN, check.attributes=FALSE)

spdep does a lot more checking (in particular for no-neighbour entities) and prepares the output object for use in spatial analysis. It does not use sp objects.

rikudoukarthik commented 1 year ago

there is no problem at all in the example:

Thanks @rsbivand for the detailed responses. I now understand the issue with using +towgs84, and have changed it as you have suggested. However, I am still facing an issue in the example. NB_ROOK <- st_rook(g1_sf) runs with no error message, but when I try to view it head(NB_ROOK) the same error I referenced in my first post pops up again (incorrect dimensions). This does not happen when using the spdep approach.

Would you be able to shed light on what is happening here? I figure it might have to do with the fact that st_relate() assumes planar coordinates, which brings back the original issue. I thought sf now has shifted to using S2 methods in these functions, but maybe not, considering some of the discussion here. In this case, does spdep also use S2 methods or not? If not, although it does not return an error it can potentially cause issues, can it not?

rsbivand commented 1 year ago

Only c("intersects", "contains", "within", "covers", "covered_by", "disjoint", "equals", "touches") are handled by s2, even if spherical, c("relate_pattern", "relate") go through GEOS, not s2.

Simply stop using st_rook() or st_queen(), they have been abandoned. spdep uses s2 for spherical data.