I have an sfnetwork in R with spatially implicit edges. I would like to plot it using tmap, and therefore I would like to make the edges spatially explicit, by just turning them into lines.
I created this monstrosity to do it
edges <- activate(graph, "edges") %>% as_tibble() %>%
inner_join(activate(graph, "nodes") %>% as_tibble(), by=c("from"="node_id")) %>%
inner_join(activate(graph, "nodes") %>% as_tibble(), by=c("to"="node_id")) %>%
mutate(geometry = purrr::pmap(list(geometry.x, geometry.y), st_union)) %>%
st_as_sf() %>%
st_cast("MULTIPOINT") %>%
st_cast("LINESTRING")
The MULTIPOINT cast may have been needed because there were self-loops in the graph, which I assume got turned into POINTs, not MULTIPOINTs, under st_union, to the dismay of the LINESTRING cast.
This seems really awkward, and it creates a separate object which I cannot glue back to the sfnetwork.
How should I do it instead?
I think the following code could work to create an sfnetwork
object with spatial explicit edges starting from an sfnetwork
object with spatial implicit edges.
First, load packages
library(sfnetworks)
library(tmap)
Create some fake data. The example is taken from ?sfnetwork
p1 = sf::st_point(c(7, 51))
p2 = sf::st_point(c(7, 52))
p3 = sf::st_point(c(8, 52))
nodes = sf::st_as_sf(sf::st_sfc(p1, p2, p3, crs = 4326))
e1 = sf::st_cast(sf::st_union(p1,p2), "LINESTRING")
e2 = sf::st_cast(sf::st_union(p1,p3), "LINESTRING")
e3 = sf::st_cast(sf::st_union(p2,p3), "LINESTRING")
edges = sf::st_as_sf(sf::st_sfc(e1, e2, e3, crs = 4326))
edges$from = c(1, 1, 2)
edges$to = c(2, 3, 3)
Create network with spatially implicit edges
(my_sfnetwork <- sfnetwork(nodes, edges, directed = FALSE, edges_as_lines = FALSE))
#> # An sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # An undirected simple graph with 1 component with spatially implicit edges
#> #
#> # Node Data: 3 x 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 x 2
#> from to
#> <int> <int>
#> 1 1 2
#> 2 1 3
#> 3 2 3
Make edges spatially explicit
(my_sfnetwork <- tidygraph::convert(
my_sfnetwork,
to_spatial_explicit_edges,
.clean = TRUE
))
#> # An sfnetwork with 3 nodes and 3 edges
#> #
#> # CRS: EPSG:4326
#> #
#> # An undirected simple graph with 1 component with spatially explicit edges
#> #
#> # Node Data: 3 x 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 x 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 (7 52, 8 52)
Created on 2020-10-27 by the reprex package (v0.3.0)
Check here, ?tidygraph::convert
and ?to_spatial_explicit_edges
for more details.