简体   繁体   中英

find all permutations of non-overlapping polygons in R (sp or sf objects)

I have a spatial object (say a Multipolygon in sf or a SpatialPolygons in sp ) and I want to find all the possible permutations of non-overlapping features. Here are some diagrams that illustrate what I am after. Let's say I have the following polygons.

library(sf)

# points
a <- st_as_sf(data.frame(lon = c(1,2,3.5,3,6), lat = c(0,1,0,1.5,-3)), coords = c('lon', 'lat'))

# circles
b <- st_buffer(a, 1)

# colors
cols = c('grey', 'red', 'green', 'yellow', 'blue')
cols = adjustcolor(cols, alpha.f = .5)

# plot
plot(b, col = cols)

在此处输入图片说明

I am after a routine that would create the following 3 objects whose plots would look like:

a. 一种

b. 在此处输入图片说明

c. 在此处输入图片说明

Ideally, the routine would also allow for a threshold on the intersection of polygons.

I think whatever routine I could write myself would take prohibitively long even for moderate-sized objects (say, 150 polygons, yielding lots of possible combinations). I was hoping that someone have already figured this problem out.

M <- st_overlaps(b, sparse = FALSE) * 1
(M <- 1 - M)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    0    1    1    1
# [2,]    0    1    0    0    1
# [3,]    1    0    1    0    1
# [4,]    1    0    0    1    1
# [5,]    1    1    1    1    1
colnames(M) <- c('grey', 'red', 'green', 'yellow', 'blue')

library(igraph)
A <- graph_from_adjacency_matrix(M)
max_cliques(A)
# [[1]]
# + 2/5 vertices, named, from dae1f9f:
# [1] red  blue
#
# [[2]]
# + 3/5 vertices, named, from dae1f9f:
# [1] grey   blue   yellow
#
# [[3]]
# + 3/5 vertices, named, from dae1f9f:
# [1] grey  blue  green
cliques(A)
# ... 
# Omitted, 13 cliques in total

First we use st_overlaps to get a kind of adjacency matrix, M , where two polygons are adjacent in this graph if they overlap in your data. But actually we are going to need 1 - M , where two polygons are adjacent in this new graph if they don't overlap. That's useful because what you are looking for then corresponds to (maximal) cliques in this graph:

cliques find all complete subgraphs in the input graph, obeying the size limitations given in the min and max arguments.

max_cliques finds all maximal cliques in the input graph. A clique in maximal if it cannot be extended to a larger clique. The largest cliques are always maximal, but a maximal clique is not neccessarily the largest.

In this case cliques are sets of polygons where none of the polygons overlap with any of the rest.

Also, as to apply this to sp objects, you only need to compute a corresponding M . I believe that over helps with that.

Bonus

As to add the possibility for thresholds, we just need to recompute M .

aux <- function(x) if (length(x) == 1) x else 0
M <- matrix(1, nrow(a), nrow(a))
for(i in 1:nrow(a))
  for(j in 1:nrow(a))
    M[i, j] <- aux(st_area(st_intersection(b[i, 1], b[j, 1])))
diag(M) <- 0

Then, for instance, if we count two polygons as intersecting only if the intersection area is greater than 0.2, we run

M <- 1 * (M > 0.2) # Getting threshold-overlaps
M <- 1 - M # The needed adjacency matrix

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM