Sam Koss
Sam Koss

Reputation: 171

How can I split / clip a polygon by lines in R?

I want to separate CO (a polygon) into sections (also polygons) that are not split by roads (linestrings). Which is to say I want the sections of smaller polygons to be bounded by roads or state borders, and not to contain any roads that enter and exit the polygon.

I was able to use lwgeom::st_split to generate a geometry collection, but I am not sure if that helps me; I am stuck with this solution because I am not sure how to extract the geometries in the collection and, for instance, assign them unique IDs.

My end goal is to make sure that my points (separate data) are not separated by roads. So if you have a solution to this that may be more direct I am all ears as well.

library(tidyverse)
library(tigris)
library(sf)
library(lwgeom)

co <- states(cb = T) %>% 
  filter(NAME == "Colorado")

roads <- primary_secondary_roads(state = 'Colorado') 

cosplit <- st_split(co,roads) 

Has anyone found or seen a solution to this?

Upvotes: 10

Views: 3411

Answers (2)

Bryce Miller
Bryce Miller

Reputation: 31

Minor note from using this to figure out my own issue. I found that a 'LINESTRING' would not split a polygon where 'MULTILINESTRING' would.

The result was also much cleaner in my test case when I first split the 'LINESTRING'by the polygon in question.

rb <- data.frame('lon' = c(10,10,20,20, 10), 
                 'lat' = c(5,10,10,5,5)) %>% 
  st_as_sf(coords = 1:2) %>% 
  st_set_crs(4326) %>% 
  concaveman()

sl <- data.frame('lon' = c(5,10,15,20,25), 
                 'lat' = c(7,7,7,7,7)) %>% 
  st_as_sf(coords = 1:2) %>% 
  st_set_crs(4326) %>% 
  st_union() %>% 
  st_cast('LINESTRING') %>% 
  st_sf()

ggplot() + 
  geom_sf(data = rb) + 
  geom_sf(data = sl)

sls <- sl %>% lwgeom::st_split(., rb) %>% st_collection_extract('LINESTRING')

slc <- sls %>% st_sample(size = round(sum(st_length(.)) / as_units(10000, 'm'),0) %>% as.numeric())

bool_inside <- st_within(slc, rb, sparse = F) %>% rowSums() > 0

nl <- sls[bool_inside,]

rbi <- rb %>% lwgeom::st_split(., sls %>% st_cast('MULTILINESTRING') %>% 
                                 st_union()) %>% st_collection_extract('POLYGON') %>% 
  mutate(id = row_number())

ggplot() + 
  geom_sf(data = rb) + 
  geom_sf(data = nl)

ggplot(rbi)+geom_sf(aes(fill = id))

Upvotes: 3

Sam Koss
Sam Koss

Reputation: 171

I think I figured it out...but I definitely would love to hear anyone elses ideas!!!

cosplitpoly <- cosplit %>% 
  st_collection_extract(c("POLYGON"))

Upvotes: 7

Related Questions