I'm experimenting with using the sfnetworks
package to query river networks. Specifically, I'd like to subset upstream portions of a river network relative to any given site.
I have a small river network dataset (available here) that I can convert into an sfnetwork
, which is defined by the package as a rooted tree with spatially explicit edges. The resulting network is a directed acyclical graph (see the ggraph
plot below).
library(sf)
library(sfnetworks)
library(ggraph)
library(cowplot)
ss <- st_read(file.path("stream_network_subsetS_KNIG.gpkg")) # subset small network (Lull Creek)
#' create sfnetwork object from river network
#' https://github.com/luukvdmeer/sfnetworks/discussions/143
n.ss <- as_sfnetwork(st_cast(ss, "LINESTRING"))
n.ss
plot(n.ss)
#' visualize directness of network
ggraph(n.ss, layout = "tree") +
geom_node_point(size = 1) +
geom_edge_link(arrow = arrow(length = unit(2, 'mm'), ends = "first"),
end_cap = circle(2, 'mm'),
start_cap = circle(2, 'mm')) +
theme_graph()
What I'd like to do is subset/filter the network that is upstream of any given node that I specify. Since sfnetworks
use igraph
for the underlying network data structure, I tried using igraph::shortest_paths
to obtain the upstream nodes:
#' this node is on the lower main stem of the network
node <- 50
#' query the nodes/vertices with a path to the node (warning issued)
x <- unique(unlist(igraph::shortest_paths(n.ss, from = node, to = igraph::V(n.ss), mode = "in")[[1]]))
#' select upstream nodes from spatial network
up.ss <- rep(FALSE, nrow(st_as_sf(n.ss, "nodes")))
up.ss[x] <- TRUE
n.ss.up <- n.ss |>
activate("nodes") |>
filter(up.ss)
#' plot upstream nodes
plot_grid(autoplot(n.ss), autoplot(n.ss.up))
Strangely, shortest_paths
only returns nodes along the main stem of the river network. I'm aware of sfnetworks::st_network_paths
, but I'm not sure if its suitable for what I'm trying to do. My question is, how would I use sfnetworks
to select the river network (i.e., vertices/nodes and edges) that is upstream of the node I've specified?
I'm also aware that sfnetworks
has a routing tutorial routing tutorial), but it clearly emphasizes street network routing.
Using dput
on the example data produces an unwieldy output, so I've uploaded the dataset to Google Drive here (if anyone can point out a better solution for sharing a ~50MB file, I'll go ahead and use that in the interests of reproducibility). Thank you!
You're so close! you're code is looking for all river segments that can be reached downstream rather than upstream. This is probably just an artifact of how the links in your river dataset are encoded.
change this line of your code:
and I hope you'll see the upstream links highlighted as shown below: