sfnetwork
is a tidy data structure for geospatial networks. It
extends the tbl_graph
data structure for
relational data into the domain of geospatial networks, with nodes and
edges embedded in geographical space, and offers smooth integration with
sf
for spatial data analysis.
Usage
sfnetwork(
nodes,
edges = NULL,
directed = TRUE,
node_key = "name",
edges_as_lines = NULL,
compute_length = FALSE,
length_as_weight = deprecated(),
force = FALSE,
message = TRUE,
...
)
Arguments
- nodes
The nodes of the network. Should be an object of class
sf
, or directly convertible to it usingst_as_sf
. All features should have an associated geometry of typePOINT
.- edges
The edges of the network. May be an object of class
sf
, with all features having an associated geometry of typeLINESTRING
. It may also be a regulardata.frame
ortbl_df
object. In any case, the nodes at the ends of each edge must be referenced in ato
andfrom
column, as integers or characters. Integers should refer to the position of a node in the nodes table, while characters should refer to the name of a node stored in the column referred to in thenode_key
argument. Setting edges toNULL
will create a network without edges.- directed
Should the constructed network be directed? Defaults to
TRUE
.- node_key
The name of the column in the nodes table that character represented
to
andfrom
columns should be matched against. IfNA
, the first column is always chosen. This setting has no effect ifto
andfrom
are given as integers. Defaults to'name'
.- edges_as_lines
Should the edges be spatially explicit, i.e. have
LINESTRING
geometries stored in a geometry list column? IfNULL
, this will be automatically defined, by setting the argument toTRUE
when the edges are given as an object of classsf
, andFALSE
otherwise. Defaults toNULL
.- compute_length
Should the geographic length of the edges be stored in a column named
length
? Usesst_length
to compute the length of the edge geometries when edges are spatially explicit, andst_distance
to compute the distance between boundary nodes when edges are spatially implicit. If there is already a column namedlength
, it will be overwritten. Please note that the values in this column are not automatically recognized as edge weights. This needs to be specified explicitly when calling a function that uses edge weights. Defaults toFALSE
.- length_as_weight
Deprecated, use
compute_length
instead.- force
Should network validity checks be skipped? Defaults to
FALSE
, meaning that network validity checks are executed when constructing the network. These checks guarantee a valid spatial network structure. For the nodes, this means that they all should havePOINT
geometries. In the case of spatially explicit edges, it is also checked that all edges haveLINESTRING
geometries, nodes and edges have the same CRS and boundary points of edges match their corresponding node coordinates. These checks are important, but also time consuming. If you are already sure your input data meet the requirements, the checks are unnecessary and can be turned off to improve performance.- message
Should informational messages (those messages that are neither warnings nor errors) be printed when constructing the network? Defaults to
TRUE
.- ...
Arguments passed on to
st_as_sf
, if nodes need to be converted into ansf
object during construction.
Examples
library(sf, quietly = TRUE)
p1 = st_point(c(7, 51))
p2 = st_point(c(7, 52))
p3 = st_point(c(8, 52))
nodes = st_as_sf(st_sfc(p1, p2, p3, crs = 4326))
e1 = st_cast(st_union(p1, p2), "LINESTRING")
e2 = st_cast(st_union(p1, p3), "LINESTRING")
e3 = st_cast(st_union(p3, p2), "LINESTRING")
edges = st_as_sf(st_sfc(e1, e2, e3, crs = 4326))
edges$from = c(1, 1, 3)
edges$to = c(2, 3, 2)
# Default.
sfnetwork(nodes, edges)
#> → Checking node geometry types ...
#> ✔ All nodes have geometry type POINT
#> → Checking edge geometry types ...
#> ✔ All edges have geometry type LINESTRING
#> → Checking coordinate reference system equality ...
#> ✔ Nodes and edges have the same crs
#> → Checking coordinate precision equality ...
#> ✔ Nodes and edges have the same precision
#> → Checking if geometries match ...
#> ✔ Node locations match edge boundaries
#> ✔ Spatial network structure is valid
#> # A sfnetwork: 3 nodes and 3 edges
#> #
#> # A directed acyclic simple graph with 1 component and spatially explicit edges
#> #
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> # Geodetic CRS: WGS 84
#> #
#> # Node data: 3 × 1 (active)
#> x
#> <POINT [°]>
#> 1 (7 51)
#> 2 (7 52)
#> 3 (8 52)
#> #
#> # Edge data: 3 × 3
#> from to x
#> <int> <int> <LINESTRING [°]>
#> 1 1 2 (7 51, 7 52)
#> 2 1 3 (7 51, 8 52)
#> 3 3 2 (8 52, 7 52)
# Undirected network.
sfnetwork(nodes, edges, directed = FALSE)
#> → Checking node geometry types ...
#> ✔ All nodes have geometry type POINT
#> → Checking edge geometry types ...
#> ✔ All edges have geometry type LINESTRING
#> → Checking coordinate reference system equality ...
#> ✔ Nodes and edges have the same crs
#> → Checking coordinate precision equality ...
#> ✔ Nodes and edges have the same precision
#> → Checking if geometries match ...
#> ✔ Node locations match edge boundaries
#> ✔ Spatial network structure is valid
#> # A sfnetwork: 3 nodes and 3 edges
#> #
#> # An undirected simple graph with 1 component and spatially explicit edges
#> #
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> # Geodetic CRS: WGS 84
#> #
#> # Node data: 3 × 1 (active)
#> x
#> <POINT [°]>
#> 1 (7 51)
#> 2 (7 52)
#> 3 (8 52)
#> #
#> # Edge data: 3 × 3
#> from to x
#> <int> <int> <LINESTRING [°]>
#> 1 1 2 (7 51, 7 52)
#> 2 1 3 (7 51, 8 52)
#> 3 2 3 (8 52, 7 52)
# Using character encoded from and to columns.
nodes$name = c("city", "village", "farm")
edges$from = c("city", "city", "farm")
edges$to = c("village", "farm", "village")
sfnetwork(nodes, edges, node_key = "name")
#> → Checking node geometry types ...
#> ✔ All nodes have geometry type POINT
#> → Checking edge geometry types ...
#> ✔ All edges have geometry type LINESTRING
#> → Checking coordinate reference system equality ...
#> ✔ Nodes and edges have the same crs
#> → Checking coordinate precision equality ...
#> ✔ Nodes and edges have the same precision
#> → Checking if geometries match ...
#> ✔ Node locations match edge boundaries
#> ✔ Spatial network structure is valid
#> # A sfnetwork: 3 nodes and 3 edges
#> #
#> # A directed acyclic simple graph with 1 component and spatially explicit edges
#> #
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> # Geodetic CRS: WGS 84
#> #
#> # Node data: 3 × 2 (active)
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> 2 (7 52) village
#> 3 (8 52) farm
#> #
#> # Edge data: 3 × 3
#> from to x
#> <int> <int> <LINESTRING [°]>
#> 1 1 2 (7 51, 7 52)
#> 2 1 3 (7 51, 8 52)
#> 3 3 2 (8 52, 7 52)
# Spatially implicit edges.
sfnetwork(nodes, edges, edges_as_lines = FALSE)
#> → Checking node geometry types ...
#> ✔ All nodes have geometry type POINT
#> ✔ Spatial network structure is valid
#> # A sfnetwork: 3 nodes and 3 edges
#> #
#> # A directed acyclic simple graph with 1 component and spatially implicit edges
#> #
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> # Geodetic CRS: WGS 84
#> #
#> # Node data: 3 × 2 (active)
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> 2 (7 52) village
#> 3 (8 52) farm
#> #
#> # Edge data: 3 × 2
#> from to
#> <int> <int>
#> 1 1 2
#> 2 1 3
#> 3 3 2
# Store edge lenghts in a column named 'length'.
sfnetwork(nodes, edges, compute_length = TRUE)
#> → Checking node geometry types ...
#> ✔ All nodes have geometry type POINT
#> → Checking edge geometry types ...
#> ✔ All edges have geometry type LINESTRING
#> → Checking coordinate reference system equality ...
#> ✔ Nodes and edges have the same crs
#> → Checking coordinate precision equality ...
#> ✔ Nodes and edges have the same precision
#> → Checking if geometries match ...
#> ✔ Node locations match edge boundaries
#> ✔ Spatial network structure is valid
#> # A sfnetwork: 3 nodes and 3 edges
#> #
#> # A directed acyclic simple graph with 1 component and spatially explicit edges
#> #
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> # Geodetic CRS: WGS 84
#> #
#> # Node data: 3 × 2 (active)
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> 2 (7 52) village
#> 3 (8 52) farm
#> #
#> # Edge data: 3 × 4
#> from to x length
#> <int> <int> <LINESTRING [°]> [m]
#> 1 1 2 (7 51, 7 52) 111195.
#> 2 1 3 (7 51, 8 52) 130977.
#> 3 3 2 (8 52, 7 52) 68458.