This markdown walks through the generation of different versions of the polygon dividedness measure with the NHPN highway data. First it walks through different ways to setup/subset the NHPN highway data, and then shows how these affect the number of polygon subdivisions generated by the measure.
Load region + division boundaries to begin:
# load & setup NHPN hwy data
# https://catalog.data.gov/dataset/national-highway-planning-network-nhpn
shp.dir <- "~/R/shapefiles/"
hwys <- st_read(paste0(shp.dir, "National_Highway_Planning_Network-shp/National_Highway_Planning_Network.shp"))## Reading layer `National_Highway_Planning_Network' from data source `C:\Users\kiram\OneDrive\Documents\R\shapefiles\National_Highway_Planning_Network-shp\National_Highway_Planning_Network.shp' using driver `ESRI Shapefile'
## replacing null geometries with empty geometries
## Simple feature collection with 626366 features and 46 fields (with 10 geometries empty)
## geometry type: LINESTRING
## dimension: XY
## bbox: xmin: -166.3656 ymin: 18.91474 xmax: -66.98005 ymax: 71.32026
## geographic CRS: WGS 84
# get czs from my data storage pkg
czs <- divDat::czs
# make uniform metered crs -----------------------------------------------
czs <- czs %>% conic.transform()
hwys <- hwys %>% conic.transform()There are many different ways to subset hwys within a region for generating the measures:
# get sample area & trim hwys
(phl <- czs[grepl("Philadelphia",czs$cz_name),] %>% divM::region.reorg("cz")) ## Simple feature collection with 1 feature and 3 fields
## geometry type: POLYGON
## dimension: XY
## bbox: xmin: 1177577 ymin: 4706815 xmax: 1342598 ymax: 4902574
## CRS: +proj=lcc +lon_0=-90 +lat_1=33 +lat_2=45
## # A tibble: 1 x 4
## region.id region.name region.type geometry
## <chr> <chr> <chr> <POLYGON [m]>
## 1 19700 Philadelphia cz ((1326289 4770204, 1326012 4769725, 132542~
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
# use FCLASS to create a hwy subset
lac <- hwys %>% filter(FCLASS %in% divM::lac_codes |
SIGNT1 == "I") # all limited-access
# spatial group hwy data
hwys <- hwys %>% denode.lines(group.cols = c("SIGNT1", "SIGN1"))
lac <- lac %>% denode.lines(group.cols = c("SIGNT1", "SIGN1"))
# Get hwy subsets for philadelphia: ----
# all hwys
all <- subset.polys.divs(region = phl,
div.sf = hwys)## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
# all interstates
int <- subset.polys.divs(phl, hwys,
div.identifier.column = "SIGNT1",
always.include = "I",
include.intersecting = F) ## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
# all interstates and hwys that intersect interstates
tint <- subset.polys.divs(phl,
hwys,
div.identifier.column = "SIGNT1",
always.include = "I",
include.intersecting = T)## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
Sometimes a hwy has a minuscule break. Often the hwy classification changes for an interchange or a short stretch. For example, I676 in Camden.
I run a helper fcn to fill these before generating polygons. The logic of the function is: If a line segment has an endpoint within x threshold of another segment, and they have the same hwy identifiers, I connect the segments.
Default threshold for filling gap is 200 meters. The argument threshold can be passed to any wrapper function that fills gaps to change this.
Below are the 3 interstates in Philadelphia CZ that have these gaps.
# filling gaps in Philly interstates:
viz.fix <- Fix.all.hwys(int, return.gap.map = T, verbose = T)
viz.fix$I676To continue creating the polygon measures, create versions of the above hwy subsets that have their gaps filled. Suffix names with ‘.c’
From here, creating the polygon measure is pretty straightforward. Fcn polygonal.div does the work; it takes linear division data and a polygon representing study area.
Let’s see how it looks based on the different hwy subsets and whether or not the gaps are filled. I use CZ as boundary.
The other core parameter for generating these measures is the area floor— the minimum size of each polygon subdivisions. If a polygon is formed that is below this area, it is filtered out and not counted towards the total. By default this floor is 1/2 square km.
# Summary table:
Summary.table <-
tibble( gaps_filled = c(FALSE, TRUE)
,interstates_only = c(polygonal.div(phl, int)$n.polys,
polygonal.div(phl, int.c)$n.polys)
,interstates_intersecting = c(polygonal.div(phl, tint)$n.polys,
polygonal.div(phl, tint.c)$n.polys)
,limited_access = c(polygonal.div(phl, lac)$n.polys,
polygonal.div(phl, lac.c)$n.polys)
)
knitr::kable(Summary.table)| gaps_filled | interstates_only | interstates_intersecting | limited_access |
|---|---|---|---|
| FALSE | 11 | 126 | 33 |
| TRUE | 12 | 128 | 34 |
# to view the polygons as map, ask the same function to return.sf to map
polygonal.div(phl, lac.c, return.sf = T) %>%
select("id") %>%
plot(main = "LAC polygons in philly")To end on a pun, a single function, Polys.wrapper, can replicate this whole workflow: of subsetting the hwys, filling the gaps, and generating the polygons. It will pass on any arguments to its wrapped fcns. See full options with ?Polys.wrapper.
## subsetting done
## gaps filled
## # A tibble: 1 x 4
## region.id region.type region.name n.polys
## <chr> <chr> <chr> <int>
## 1 19700 cz Philadelphia 34