# Dissolve only overlapping polygons in R using sf

I extracted information from open street map that contains many polygons, some of them overlapping. I want to union all polygons that overlap with other polygons. This question has been asked before here: Dissolve only overlapping polygons in R but I am looking for an approach that uses the sf package.

Here is a reproducible example:

``````sq = function(pt, sz = 1) st_polygon(list(rbind(c(pt - sz), c(pt + sz, pt - sz), c(pt + sz), c(pt - sz, pt + sz), c(pt - sz))))
x = st_sf(box = 1:6, st_sfc(sq(c(4.2,4.2)), sq(c(0,0)), sq(c(1, -0.8)), sq(c(0.5, 1.7)), sq(c(3,3)), sq(c(-3, -3))))
plot(x)
st_overlaps(x)
``````

What I am looking for is an appproach that unions the 2 rectangles that show overlap and the 3 rectangles that have overlap. Problem is that I do not know how to identify the 3 clusters of rectangles that I have in my example. With this information, I can run group_by %>% summarize() on the result and solve my problem.

Here's my sample data:

``````> plot(bdf)
`````` If you only care about whether polygons overlap and how they form clusters, then use `st_intersects`:

``````> st_intersects(bdf,bdf)
Sparse geometry binary predicate list of length 6, where the predicate was `intersects'
1: 1
2: 2, 3, 4
3: 2, 3, 4
4: 2, 3, 4
5: 5, 6
6: 5, 6
``````

That gets you some of the way. The output above can be used to form an adjacency matrix of overlaps, which you can then feed into the `igraph` package to create a graph, and then you can get the disconnected subgraphs.

``````> library(igraph)
> g = st_intersects(bdf,bdf)
`````` Find the connected components with `components`:

``````> G = graph_from_adj_list(g)
> components(G)
\$membership
 1 2 2 2 3 3

\$csize
 1 3 2

\$no
 3
``````

The `\$membership` element of that list is telling you which cluster each of the six original features is a member of, in order.

Alternatively if you do want to construct the geometry of the clusters, use `st_union`:

``````> parts = st_cast(st_union(bdf),"POLYGON")
``````

The output of `st_union` is a `"MULTIPOLYGON"` of three, so I split it into its `"POLYGON"` parts and then test intersection with the original features:

``````> st_intersects(bdf, parts)
Sparse geometry binary predicate list of length 6, where the predicate was `intersects'
1: 1
2: 3
3: 3
4: 3
5: 2
6: 2
``````

which tells me that original feature 1 is in cluster 1, features 2 to 4 are in cluster 3, and features 5 and 6 form cluster 2.

Note the order is different from the `igraph` example - the ordering of the polygons from the `st_union` is not the same as the ordering of the connected components in the `igraph` example. From lower-left to upper right `st_union` has indexed the clusters 1,3,2 and `igraph` has indexed them 1,2,3. This ordering is arbitrary (but don't mix them up).

These are great solutions. I used your second approach to solve my question above using the example I provide below. I determine the clusters, join them with the data and use group_by to union the polygons in the three clusters. Also added a paste statement to keep the names of the original polygons, something I need for my application:

``````sq = function(pt, sz = 1) st_polygon(list(rbind(c(pt - sz), c(pt + sz, pt - sz), c(pt + sz), c(pt - sz, pt + sz), c(pt - sz))))
x = st_sf(box = 1:6, st_sfc(sq(c(4.2,4.2)), sq(c(0,0)), sq(c(1, -0.8)), sq(c(0.5, 1.7)), sq(c(3,3)), sq(c(-3, -3))))
plot(x)

parts <- st_cast(st_union(x),"POLYGON")
plot(parts)

clust <- unlist(st_intersects(x, parts))

diss <- cbind(x, clust) %>%
group_by(clust) %>%
summarize(box = paste(box, collapse = ", "))

plot(diss)
`````` Unfortunately, it seems that my actual data from Open Street Map is more messy than the example. When I use st_intersects to determine the links between the features and the clusters it appears that features can be related to two (or more) clusters. I do not understand how this is possible as then these two clusters should be regarded as one cluster.

The data can be found here. Perhaps you can have a look?

https://www.dropbox.com/s/4n259yhh5swqgf2/osm_data.rds?dl=0