Closed agila5 closed 4 years ago
The "sfnetworks answer" to close this issue:
library(sfnetworks)
library(igraph)
library(tidygraph)
library(sf)
library(ggplot2)
net = as_sfnetwork(roxel, directed = FALSE)
Regarding ggplot, you will still need to extract nodes and edges as sf objects. However, this is fairly easy now since you can do that without activating first, and instead provide "nodes" or "edges" as argument to st_as_sf.
st_as_sf(net, "nodes")
#> Simple feature collection with 701 features and 0 fields
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: 7.522622 ymin: 51.94151 xmax: 7.546705 ymax: 51.9612
#> CRS: EPSG:4326
#> # A tibble: 701 x 1
#> geometry
#> <POINT [°]>
#> 1 (7.533722 51.95556)
#> 2 (7.533461 51.95576)
#> 3 (7.532442 51.95422)
#> 4 (7.53209 51.95328)
#> 5 (7.532709 51.95209)
#> 6 (7.532869 51.95257)
#> 7 (7.540063 51.94468)
#> 8 (7.53822 51.94546)
#> 9 (7.537673 51.9475)
#> 10 (7.537614 51.94562)
#> # … with 691 more rows
st_as_sf(net, "edges")
#> Simple feature collection with 851 features and 4 fields
#> geometry type: LINESTRING
#> dimension: XY
#> bbox: xmin: 7.522594 ymin: 51.94151 xmax: 7.546705 ymax: 51.9612
#> CRS: EPSG:4326
#> # A tibble: 851 x 5
#> from to name type geometry
#> <int> <int> <fct> <fct> <LINESTRING [°]>
#> 1 1 2 Havixbecker… reside… (7.533722 51.95556, 7.533461 51.95576)
#> 2 3 4 Pienersallee second… (7.532442 51.95422, 7.53236 51.95377, 7.532…
#> 3 5 6 Schulte-Ber… reside… (7.532709 51.95209, 7.532823 51.95239, 7.53…
#> 4 7 8 <NA> path (7.540063 51.94468, 7.539696 51.94479, 7.53…
#> 5 9 10 Welsingheide reside… (7.537673 51.9475, 7.537614 51.94562)
#> 6 11 12 <NA> footway (7.543791 51.94733, 7.54369 51.94686, 7.543…
#> 7 13 14 <NA> footway (7.54012 51.94478, 7.539931 51.94514)
#> 8 8 10 <NA> path (7.53822 51.94546, 7.538131 51.94549, 7.538…
#> 9 7 15 <NA> track (7.540063 51.94468, 7.540338 51.94468, 7.54…
#> 10 16 17 <NA> track (7.5424 51.94599, 7.54205 51.94629, 7.54196…
#> # … with 841 more rows
Then plotting gets as easy as.
ggplot() +
geom_sf(data = st_as_sf(net, "edges")) +
geom_sf(data = st_as_sf(net, "nodes"))
The algorithms from igraph can be directly applied to the network.
head(igraph::edge_betweenness(net))
#> [1] 10406.362 12118.803 6837.847 4467.540 32124.052 674.000
igraph::is_connected(net)
#> [1] FALSE
Spatial filtering can be done with st_filter.
p1 = st_point(c(7.53173, 51.95662))
p2 = st_point(c(7.53173, 51.95190))
p3 = st_point(c(7.53778, 51.95190))
p4 = st_point(c(7.53778, 51.95662))
rect = st_multipoint(c(p1, p2, p3, p4)) %>%
st_cast('POLYGON') %>%
st_sfc(crs = 4326)
net_f = net %>%
st_filter(rect, .pred = st_intersects)
#> although coordinates are longitude/latitude, st_intersects assumes that they are planar
#> although coordinates are longitude/latitude, st_intersects assumes that they are planar
par(mar = c(1, 1, 1, 1))
plot(net, col = "grey")
plot(rect, border = "Red", lwd = 2, add = TRUE)
plot(net_f, add = TRUE)
Created on 2020-06-16 by the reprex package (v0.3.0)
This issue shows the problems with the current implementations of spatial and graph operations on a network.
The problem is illustrated using code from
stplanr
, the challenge will be to solve this problem in future versions of sfnetworks.We start this example by creating a spatial lines network object with the function SpatialLinesNetwork of the R package
stplanr
.First of all, it should be noted that, at the moment, the plotting of spatial lines network objects with ggplot2/tmap/leaflet is unnecessary complicated. For example, all the following approaches fail.
As we can see from the error messages, the user first has to extract the sf data and then plot it. For example,
The same idea can be applied to igraph functions, like
which work only if we extract the graph component from the spatial network object,
This separation between the spatial and the graph components of a spatial network is counterintuituve and complicated.
Moreover, we cannot apply to that network object any spatial or graph function that implies a modification of the spatial or graph structure. For example, if we create a buffer of 400m around Chapteltown, which is one of the neighborhoods in the center of the network object,
and filter all the edges inside the buffer, we get an error:
This example is even more problematic than the others, since, in this case, we cannot simply work on the sf component of the spatial lines network object. In fact, even if we modify it,
this does not change the graph component since they are not strictly linked:
This means that, after the spatial filtering, some edges in the graph component are linked to LINESTRINGS that do no exist in the spatial component. The same will happen if we modify the graph component. The only procedure that works is to filter the original sf data and, then, rebuild the network from scratch, i.e.
Created on 2019-10-13 by the reprex package (v0.3.0)