luukvdmeer / sfnetworks

Tidy Geospatial Networks in R
https://luukvdmeer.github.io/sfnetworks/
Other
347 stars 20 forks source link

More 'tidy' output for spatial shortest path function #77

Closed luukvdmeer closed 3 years ago

luukvdmeer commented 4 years ago

Is your feature request related to a problem? Please describe. The current output of st_shortest_path is equal to the igraph output of igraph::shortest_path. This is a list with different elements, like vpath (the vertices in the path) and epath (the edges in the path). Such an output does fit nice into a tidy workflow with pipes.

Describe the solution you'd like An output format that fits better into a tidy workflow, like a tibble.

luukvdmeer commented 4 years ago

Note: after implementing this the to_spatial_shortest_paths morpher should be updated accordingly (@loreabad6)

luukvdmeer commented 3 years ago

Implemented by @loreabad6. Output is now a tibble which can be used smoothly within tidy pipelines. Reprex:

library(sfnetworks)
library(sf)
#> Linking to GEOS 3.7.1, GDAL 2.2.2, PROJ 4.9.2
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

paths = as_sfnetwork(roxel, directed = FALSE) %>%
  st_transform(3035) %>%
  st_shortest_paths(from = 1, to = c(9,10))

paths
#> # A tibble: 2 x 2
#>   node_paths edge_paths
#>   <list>     <list>    
#> 1 <int [17]> <int [16]>
#> 2 <int [18]> <int [17]>

paths %>%
  slice(1) %>%
  pull(node_paths) %>%
  unlist()
#>  [1]   1 644 579 260 164 208 426 424 533 657 512 506 111 524 292 167   9

Created on 2020-11-02 by the reprex package (v0.3.0)

loreabad6 commented 3 years ago

Thanks for the reprex! Some additional things that can be done, and that will be documented on the vignettes are:

library(sfnetworks)
library(sf)
library(dplyr)
library(purrr)

paths = as_sfnetwork(roxel, directed = FALSE) %>%
  st_transform(3035) %>%
  st_shortest_paths(from = 2, to = c(110:120))
#> Warning in (function (graph, from, to = V(graph), mode = c("out", "all", : At
#> structural_properties.c:745 :Couldn't reach some vertices

paths
#> # A tibble: 11 x 2
#>    node_paths edge_paths
#>    <list>     <list>    
#>  1 <int [20]> <int [19]>
#>  2 <int [14]> <int [13]>
#>  3 <int [10]> <int [9]> 
#>  4 <int [9]>  <int [8]> 
#>  5 <int [17]> <int [16]>
#>  6 <int [18]> <int [17]>
#>  7 <int [0]>  <int [0]> 
#>  8 <int [0]>  <int [0]> 
#>  9 <int [25]> <int [24]>
#> 10 <int [24]> <int [23]>
#> 11 <int [11]> <int [10]>

# Remove those pair of nodes that could not be reached
paths %>% 
  filter(!lengths(edge_paths)==0)
#> # A tibble: 9 x 2
#>   node_paths edge_paths
#>   <list>     <list>    
#> 1 <int [20]> <int [19]>
#> 2 <int [14]> <int [13]>
#> 3 <int [10]> <int [9]> 
#> 4 <int [9]>  <int [8]> 
#> 5 <int [17]> <int [16]>
#> 6 <int [18]> <int [17]>
#> 7 <int [25]> <int [24]>
#> 8 <int [24]> <int [23]>
#> 9 <int [11]> <int [10]>

# Add columns with the `to` and `from` node index
paths %>% 
  rowwise() %>% 
  mutate(
    node_from = first(node_paths),
    node_to = last(node_paths)
  )
#> # A tibble: 11 x 4
#> # Rowwise: 
#>    node_paths edge_paths node_from node_to
#>    <list>     <list>         <int>   <int>
#>  1 <int [20]> <int [19]>         2     110
#>  2 <int [14]> <int [13]>         2     111
#>  3 <int [10]> <int [9]>          2     112
#>  4 <int [9]>  <int [8]>          2     113
#>  5 <int [17]> <int [16]>         2     114
#>  6 <int [18]> <int [17]>         2     115
#>  7 <int [0]>  <int [0]>         NA      NA
#>  8 <int [0]>  <int [0]>         NA      NA
#>  9 <int [25]> <int [24]>         2     118
#> 10 <int [24]> <int [23]>         2     119
#> 11 <int [11]> <int [10]>         2     120

# Filter only those paths that pass through node 3
paths %>% 
  filter(map_lgl(node_paths, ~3 %in% .))
#> # A tibble: 6 x 2
#>   node_paths edge_paths
#>   <list>     <list>    
#> 1 <int [10]> <int [9]> 
#> 2 <int [9]>  <int [8]> 
#> 3 <int [17]> <int [16]>
#> 4 <int [18]> <int [17]>
#> 5 <int [25]> <int [24]>
#> 6 <int [24]> <int [23]>

Btw @luukvdmeer, is the reprex in your comment done with an updated, not-pushed version of st_shortest_paths? My reprex should be updated accordingly then.

Reprex is updated now!

luukvdmeer commented 3 years ago

This is now part of the new version. See the routing vignette and the function reference.