luukvdmeer / sfnetworks

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

st_network_paths does not return named vectors when node_key is assigned #154

Closed loreabad6 closed 2 years ago

loreabad6 commented 3 years ago

Is your feature request related to a problem? Please describe.

Current behavior is that when we have an sfnetwork with a node column named name, the nodes will automatically take that name as identifier of the nodes.

library(sf)
library(sfnetworks)
library(tidyverse)
p1 = st_point(c(7, 51))
p2 = st_point(c(7, 52))
p3 = st_point(c(8, 52))
p4 = st_point(c(8, 51.5))

l1 = st_sfc(st_linestring(c(p1, p2)))
l2 = st_sfc(st_linestring(c(p1, p4, p3)))
l3 = st_sfc(st_linestring(c(p3, p2)))

edges = st_as_sf(c(l1, l2, l3), crs = 4326)
nodes = st_as_sf(c(st_sfc(p1), st_sfc(p2), st_sfc(p3)), crs = 4326)

edges$from = c(1, 1, 3)
edges$to = c(2, 3, 2)

nodes$name = c("city", "village", "farm")
edges$from = c("city", "city", "farm")
edges$to = c("village", "farm", "village")

net = sfnetwork(nodes, edges)
#> Checking if spatial network structure is valid...
#> Spatial network structure is valid

This behavior can be used in st_network_cost() and st_network_paths(). For st_network_cost() this returns a named cost matrix, which can come in handy when interpreting the results.

st_network_cost(net)
#>             city   village      farm
#> city         0.0 111257.83 144899.77
#> village 111257.8      0.00  68677.47
#> farm    144899.8  68677.47      0.00

However, these names are lost when calling st_network_paths().

st_network_paths(net, "city", "farm") %>%
  pull(node_paths)
#> [[1]]
#> [1] 1 3

These works when calling igraph::shortest_paths()

igraph::shortest_paths(net, "city", "farm", output = "both")$vpath
#> [[1]]
#> + 2/3 vertices, named, from 4667a9e:
#> [1] city farm

This happens because inside st_network_paths(), this function is called:

get_shortest_paths = function(x, from, to, weights, ...) {
  # Set weights.
  weights = set_path_weights(x, weights)
  # Call igraph function.
  paths = shortest_paths(x, from, to, weights = weights, output = "both", ...)
  # Extract paths of node indices and edge indices.
  npaths = lapply(paths[[1]], as.integer)
  epaths = lapply(paths[[2]], as.integer)
  # Return as columns in a tibble.
  as_tibble(do.call(cbind, list(node_paths = npaths, edge_paths = epaths)))
}

Which converts the igraph result into integers.

Describe the solution you’d like

It would be nice if we could return a named vector within the output of st_network_paths().

luukvdmeer commented 2 years ago

Should it be the default to return names whenever a name column is present in the nodes table? Or should it only do that e.g. when you would set use_names = TRUE?

agila5 commented 2 years ago

Should it be the default to return names whenever a name column is present in the nodes table?

IMO yes.

luukvdmeer commented 2 years ago

Implemented in v0.6.0