`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.

```
sfnetwork(
nodes,
edges = NULL,
directed = TRUE,
node_key = "name",
edges_as_lines = NULL,
length_as_weight = FALSE,
force = FALSE,
...
)
```

- nodes
The nodes of the network. Should be an object of class

`sf`

, or directly convertible to it using`st_as_sf`

. All features should have an associated geometry of type`POINT`

.- edges
The edges of the network. May be an object of class

`sf`

, with all features having an associated geometry of type`LINESTRING`

. It may also be a regular`data.frame`

or`tbl_df`

object. In any case, the nodes at the ends of each edge must either be encoded in a`to`

and`from`

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 encoded in the column referred to in the`node_key`

argument. Setting edges to`NULL`

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`

and`from`

columns should be matched against. If`NA`

, the first column is always chosen. This setting has no effect if`to`

and`from`

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? If`NULL`

, this will be automatically defined, by setting the argument to`TRUE`

when the edges are given as an object of class`sf`

, and`FALSE`

otherwise. Defaults to`NULL`

.- length_as_weight
Should the length of the edges be stored in a column named

`weight`

? If set to`TRUE`

, this will calculate the length of the linestring geometry of the edge in the case of spatially explicit edges, and the straight-line distance between the source and target node in the case of spatially implicit edges. If there is already a column named`weight`

, it will be overwritten. Defaults to`FALSE`

.- 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 have`POINT`

geometries. In the case of spatially explicit edges, it is also checked that all edges have`LINESTRING`

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.- ...
Arguments passed on to

`st_as_sf`

, if nodes need to be converted into an`sf`

object during construction.

An object of class `sfnetwork`

.

```
library(sf, quietly = TRUE)
## Create sfnetwork from sf objects
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 if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # A directed acyclic simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 × 1 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> x
#> <POINT [°]>
#> 1 (7 51)
#> 2 (7 52)
#> 3 (8 52)
#> #
#> # Edge Data: 3 × 3
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> 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 if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # An undirected simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 × 1 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> x
#> <POINT [°]>
#> 1 (7 51)
#> 2 (7 52)
#> 3 (8 52)
#> #
#> # Edge Data: 3 × 3
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> 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 if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # A directed acyclic simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 × 2 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> 2 (7 52) village
#> 3 (8 52) farm
#> #
#> # Edge Data: 3 × 3
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> 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 if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # A directed acyclic simple graph with 1 component with spatially implicit edges
#> #
#> # Node Data: 3 × 2 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> 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 weight column.
sfnetwork(nodes, edges, length_as_weight = TRUE)
#> Checking if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # A directed acyclic simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 × 2 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> 2 (7 52) village
#> 3 (8 52) farm
#> #
#> # Edge Data: 3 × 4
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> from to x weight
#> <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.
# Adjust the number of features printed by active and inactive components
oldoptions = options(sfn_max_print_active = 1, sfn_max_print_inactive = 2)
sfnetwork(nodes, edges)
#> Checking if spatial network structure is valid...
#> Spatial network structure is valid
#> # A sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # A directed acyclic simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 × 2 (active)
#> # Geometry type: POINT
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> x name
#> <POINT [°]> <chr>
#> 1 (7 51) city
#> # … with 2 more rows
#> #
#> # Edge Data: 3 × 3
#> # Geometry type: LINESTRING
#> # Dimension: XY
#> # Bounding box: xmin: 7 ymin: 51 xmax: 8 ymax: 52
#> from to x
#> <int> <int> <LINESTRING [°]>
#> 1 1 2 (7 51, 7 52)
#> 2 1 3 (7 51, 8 52)
#> # … with 1 more row
options(oldoptions)
```