luukvdmeer / sfnetworks

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

Apply to_spatial_smooth without merging different fields #124

Closed agila5 closed 2 years ago

agila5 commented 3 years ago

Is your feature request related to a problem? Please describe. I'd like applying the to_spatial_smooth morpher taking into account the value of one or more fields in the edges table. I think this is useful for statistical models with OSM data since, usually, I'd like removing the pseudo nodes (to simplify the network structure) without merging road segments with different highway types. I'm not 100% sure but I think that this "feature" was already discussed but, at the moment, I cannot find the proper reference.

Describe the solution you'd like For example:

# packages
library(sf)
library(sfnetworks)
library(tidygraph)

# fake data
fake_sf <- st_sf(
  data.frame(type = c("a", "b", "b")), 
  geometry = st_sfc(
    st_linestring(rbind(c(0, 0), c(1, 1))),
    st_linestring(rbind(c(1, 1), c(2, 2))), 
    st_linestring(rbind(c(2, 2), c(3, 3))),
    crs = 4326
  ) 
)

# spatial smoother
fake_sf %>% 
  as_sfnetwork(directed = FALSE) %>% 
  convert(to_spatial_smooth, .clean = TRUE)
#> # A sfnetwork with 2 nodes and 1 edges
#> #
#> # CRS:  EPSG:4326 
#> #
#> # An unrooted tree with spatially explicit edges
#> #
#> # Node Data:     2 x 1 (active)
#> # Geometry type: POINT
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 3 ymax: 3
#>      geometry
#>   <POINT [°]>
#> 1       (0 0)
#> 2       (3 3)
#> #
#> # Edge Data:     1 x 4
#> # Geometry type: LINESTRING
#> # Dimension:     XY
#> # Bounding box:  xmin: 0 ymin: 0 xmax: 3 ymax: 3
#>    from    to type              geometry
#>   <int> <int> <fct>     <LINESTRING [°]>
#> 1     1     2 <NA>  (0 0, 1 1, 2 2, 3 3)

Created on 2021-02-10 by the reprex package (v0.3.0)

The second and the third edges should be merged (since they have the same type), while the first edge should remain separated from the other ones.

luukvdmeer commented 3 years ago

Yes, I did implement it in an early function of to_spatial_smooth, but it was not working good and also very slow. Therefore it did not make it to master.

Is your request generalizable to "only consider a node to be a pseudo node when all attributes of its incident edges are equal?", or do you specifically want to select only a subset of attributes to compare?

Either way we should implement this when defining which nodes are pseudo nodes, i.e. here.

Now the definition is: a node is a pseudo node if it has one incoming and one outgoing edge (or simply two incident edges in the case of undirected network). That should in your case then be changed to: a node is a pseudo node if it has one incoming and one outgoing edge (or simply two incident edges in the case of undirected networks) and the attributes of these two edges are equal. Right? I am not sure however what the most efficient way is to check this equality of attributes.

agila5 commented 3 years ago

Hi @luukvdmeer and thanks for the answer.

Now the definition is: a node is a pseudo node if it has one incoming and one outgoing edge (or simply two incident edges in the case of undirected network). That should in your case then be changed to: a node is a pseudo node if it has one incoming and one outgoing edge (or simply two incident edges in the case of undirected networks) and the attributes of these two edges are equal. Right? I am not sure however what the most efficient way is to check this equality of attributes.

Yes, exactly. I'm not sure either, but I will try writing some code during the weekend (or sometimes next week)!

Is your request generalizable to "only consider a node to be a pseudo node when all attributes of its incident edges are equal?", or do you specifically want to select only a subset of attributes to compare?

I think that the best approach would be creating a new parameter for selecting a subset of fields that should be used for testing "equality" of the edges, but I'm ok with both scenarios.

LaurentBerder commented 2 years ago

What about the info we don't need for the merging of "pseudo-nodes", but that would be useful after the merge?

I see that with other types of morphs, such as to_spatial_simple for example, it's possible to use summarise_attributes to specify how to aggregate attributes.

Would it be possible to include that in to_spatial_smooth as well?

Anaphory commented 2 years ago

I really don't know how exception handling control flow works in R.

Would it be possible to add a summarise_attributes to to_spatial_simple and if that throws an exception, those two edges will not me merged?

It looks like that kind of implementation would play insanely badly with vectorized operations, but maybe it can serve as inspiration on how to solve both attributes_that_must_match and summarise_attributes in a similar manner?

luukvdmeer commented 2 years ago

Implemented in v0.6.0 through arugment require_equal, see https://luukvdmeer.github.io/sfnetworks/articles/sfn02_preprocess_clean.html#smooth-pseudo-nodes