Section 8.1 Constructing and storing a spatial linear network
The first difficulty one encounters when wanting to do analysis along spatial networks is to get the data for such geographical element in the proper shape. It is fairly straightforward to get files with the administrative boundaries for census geographies, as we have seen in previous chapters. This kind of geographical data is widely available in official and open repositories (see also Appendix C: sourcing geographical data for crime analysis). Getting data for spatial networks used to be a little bit trickier, although it is getting better. One could, for example, use the
osmdata package to access Open Street Map data for a road network (we also discuss this in greater detail in Appendix C). Or, if you analyse data from the United States, you could use the tigris package to extract geometries which represent road networks.
Below we show how to obtain this data for Kensington, a popular neighbourhood in Toronto city centre through
osmdata and for Manhattan using tigris. As we’re querying data from Open Street Map, first we draw a bounding box around the area we are interested in, then select "highways" as the feature to extract (see Appendix C for details on building OSM queries). As discussed by [Abad et al. (2019)], the osmdata package turns streets that form loops into polygons; to ensure we end up with lines we use osm_poly2line.
# using osm data
highways_heswall <- opq("Heswall, UK") %>%
add_osm_feature(key = "highway") %>%
osmdata_sf()
heswall_lines <- highways_heswall$osm_lines
Now let’s use the
tigris package to get TIGER/Line shapefiles from the United States Census Bureau. The roads() function returns the content of all road shapefiles — which includes primary roads, secondary roads, local neighbourhood roads, rural roads, city streets, vehicular trails (4WD), ramps, service drives, walkways, stairways, alleys, and private roads. It returns these as an sf object.
# using tigris
manhattan_roads <- roads("NY", "New York")
We can now plot these two side-by-side.
# plot results
plot_1 <- ggplot(heswall_lines) + geom_sf() + theme_void()
plot_2 <- ggplot(manhattan_roads) + geom_sf() + theme_void()
figure_1 <- ggarrange(plot_1, plot_2, labels = c("Heswall", "Manhattan"),
ncol = 2, nrow = 1)
figure_1

What we have is two
sf objects containing linestrings. Linear networks indeed can be represented in R by simple features with sf as here, or with the class SpatialLines of package sp. However, for us to be able to do a particular kind of analysis and some geospatial operations on this network we often will need a clear topology: we will need the data to be stored as a network graph. In other words, we need to move from linestrings to a linear graphical network representation, with edges (for example, representing street segments) and nodes (vertices indicating where they start and end).
This can be done by virtue of manual editing, which in large networks may be prohibitive, fully automatized, or automatized with manual edits just to correct errors. Explaining how to do this in detail with R would require space we do not have. Luckily, there are some good tutorials out there that you can consult for this data pre-processing work.
-
[Abad et al. (2019)] explain how to use the packages
rgrass7andlink2GIfor this purpose. These packages bridge R to GRASS GIS software. So for this approach to work, you would require this software to be installed in your machine. Fortunately, GRASS GIS is freely available. -
The vignettes for
sfnetworksalso cover how to turn a linestringsfobject into a network. The functionas_sfnetwork()provides the basic functionality for this. This package also includes several additional functions for cleaning the resulting network, and there is a specific vignette documenting these ([van der Meer et al., 2021]). -
[Briz-Redón et al. (2019a)] developed the
SpNetPrep("Spatial Network Preprocessing"). This package will open a Shiny application in RStudio that will allow for network creation and edition, network direction endowment and point pattern revision and modification. The key aim of this package is to allow for manual edits of the constructed network to correct for errors.
We quickly show below the
as_sfnetwork() function with the road network in Kensington (which will generate an object of class sfnetwork) so that you get a sense for the look of a spatial network. But for further details on network construction and pre-processing, it is important you see the documentation, as well as the other materials cited above.
heswall_ntwk <- as_sfnetwork(heswall_lines)
plot(heswall_ntwk)

Once you have a spatial network that has been properly cleaned and prepared as discussed in the references above, there are a number of things you can do with it. You can apply geospatial operations, such as blending points into the edges, segmenting the edges, running spatial filters, etc. You can also apply standard social network analysis techniques and measures (such as centrality, measuring shortest path). Illustrations of these applications are available in the vignettes for
sfnetworks ([van der Meer et al., 2021]) and in [Abad et al. (2019)].
Another format for linear networks in R is
linnet used by the package spatstat. When what we want is to do analysis not of the network itself, but of the location of points (such as crime events) along the network, spatstat is the way to go, and so we would need to ensure we store the data in formats that are required by this package. Statistical analysis of events along these networks is of key interest for crime analysts. In the next section we will explain how to perform density estimation along networks.
