r-sftidygraphsfnetwork

Adding spatially explicit edges to sfnetwork


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?


Solution

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