luukvdmeer / sfnetworks

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

Add my own nodes to the network #271

Open ratnanil opened 1 month ago

ratnanil commented 1 month ago

Describe the bug

I would like to use my own nodes to create my network.

Reproducible example

library(sfnetworks)
suppressPackageStartupMessages(library(sf))

# transform to projected crs, so I can sample on the line
roxel <- st_transform(roxel, 3034)

nodes_extra <- roxel |> 
  st_line_sample(density = 1/100)

nodes_extra <- st_cast(nodes_extra[!st_is_empty(nodes_extra)], "POINT")

nodes <- st_cast(roxel, "POINT", warn = FALSE) |> st_geometry()

nodes <- c(nodes, nodes_extra)

# this works
roxel_net <- as_sfnetwork(roxel)

# this doesn't
sfnetwork(nodes = nodes, edges = roxel)
#> Error in (function (edges, n = max(edges), directed = TRUE) : At rinterface_extra.c:82 : The value nan is not representable as an integer. Invalid value

# this doesn't either
bind_nodes(roxel_net, nodes)
#> Error in bind_nodes(roxel_net, nodes): could not find function "bind_nodes"

plot(roxel_net)

plot(nodes_extra, add = TRUE,  col = "blue", pch = 16)

Created on 2024-07-12 with reprex v2.1.0 Expected behavior

I would have expected that I can provide the network with my own nodes in the function sfnetwork. This does not seem to be the case.

R Session Info

R version 4.3.1 (2023-06-16) Platform: x86_64-pc-linux-gnu (64-bit) Running under: Ubuntu 23.10 Matrix products: default BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.11.0 LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.11.0 locale: [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C [3] LC_TIME=en_GB.UTF-8 LC_COLLATE=en_US.UTF-8 [5] LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_US.UTF-8 [7] LC_PAPER=en_GB.UTF-8 LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C time zone: Europe/Zurich tzcode source: system (glibc) attached base packages: [1] stats graphics grDevices utils datasets methods [7] base other attached packages: [1] tidyr_1.3.1 terra_1.7-78 purrr_1.0.2 [4] tidygraph_1.3.1 tmap_3.3-4 dplyr_1.1.4 [7] sfnetworks_0.6.4 ggplot2_3.5.1 sf_1.0-17 loaded via a namespace (and not attached): [1] gtable_0.3.4 xfun_0.45 [3] raster_3.6-26 htmlwidgets_1.6.4 [5] processx_3.8.3 lattice_0.21-8 [7] callr_3.7.5 ps_1.7.6 [9] vctrs_0.6.5 tools_4.3.1 [11] crosstalk_1.2.1 generics_0.1.3 [13] parallel_4.3.1 tibble_3.2.1 [15] proxy_0.4-27 fansi_1.0.6 [17] R.oo_1.26.0 pkgconfig_2.0.3 [19] sfheaders_0.4.4 KernSmooth_2.23-22 [21] RColorBrewer_1.1-3 leaflet_2.2.2 [23] R.cache_0.16.0 lifecycle_1.0.4 [25] compiler_4.3.1 microbenchmark_1.4.10 [27] munsell_0.5.1 codetools_0.2-19 [29] leafsync_0.1.0 stars_0.6-5 [31] htmltools_0.5.8.1 class_7.3-22 [33] yaml_2.3.8 pillar_1.9.0 [35] crayon_1.5.3 R.utils_2.12.3 [37] classInt_0.4-10 lwgeom_0.2-14 [39] wk_0.9.1 abind_1.4-5 [41] styler_1.10.2 tidyselect_1.2.1 [43] digest_0.6.35 fastmap_1.2.0 [45] grid_4.3.1 colorspace_2.1-0 [47] cli_3.6.3 magrittr_2.0.3 [49] base64enc_0.1-3 dichromat_2.0-0.1 [51] XML_3.99-0.16.1 cols4all_0.7-1 [53] utf8_1.2.4 leafem_0.2.3 [55] e1071_1.7-14 clipr_0.8.0 [57] withr_3.0.0 scales_1.3.0 [59] sp_2.1-4 rmarkdown_2.27 [61] igraph_2.0.3 R.methodsS3_1.8.2 [63] png_0.1-8 evaluate_0.24.0 [65] knitr_1.47 tmaptools_3.1-1 [67] viridisLite_0.4.2 s2_1.1.6 [69] rlang_1.1.4 Rcpp_1.0.12 [71] glue_1.7.0 DBI_1.2.3 [73] reprex_2.1.0 rstudioapi_0.16.0 [75] R6_2.5.1 spacesXYZ_1.3-0 [77] fs_1.6.4 units_0.8-5
ratnanil commented 1 month ago

related to #49, #29?

agila5 commented 1 month ago

Hi @ratnanil and thanks for your question. As described in the introductory vignette,

The most basic way to construct a sfnetwork with spatially explicit edges is by providing the sfnetwork construction function one sf object containing the nodes, and another sf object containing the edges. This edges table should include a from and to column referring to the node indices of the edge endpoints.

Unfortunately, the raw roxel object does not contain those from and to columns and, therefore, the sfnetwork function cannot build a proper sfnetwork object. Nevertheless, I think we may provide a better error message.

On the other hand, as_sfnetwork(roxel) works using a simple heuristic which is described here.

ratnanil commented 1 month ago

Ah ok, thank you for this explanation, which makes sense. So I could either provide the edges with the from and to columns or (as I just realized), split the lines using my explicit nodes and continue as usual:

roxel_split <- lwgeom::st_split(roxel, nodes) |> 
  st_collection_extract("LINESTRING")

roxel_net <- sfnetworks::as_sfnetwork(roxel_split)

(EDIT: I'll let you close this yourself, after implementing #272)