rnetwork-programminggeospatialstplanr

Add new node to SpatialLinesNetwork in stplanr


How can one add a new node to a SpatialLinesNetwork?

context of my problem: I have a shapefile of a bus route and another shapefile of bus stops. I want to calculate the distance between stops along the bus route. Ideally, each stop would be a node and I would use stplanr::sum_network_routes() to calculate the distance between them. The problem is that when I convert the bus route into a SpatialLinesNetwork the network only has a few nodes that are far from each other and unrelated to bus stops locations.

reproducible dataset:

# load library and data
  library(stplanr)
  library(sf)

# get road data
  data(routes_fast)
  rnet <- overline(routes_fast, attrib = "length")

# convert to sf obj
  rnet <- st_as_sf(rnet)

# convert SpatialLinesDataFrame into  SpatialLinesNetwork
  sln <- SpatialLinesNetwork(rnet)

# identify nodes
 sln_nodes = sln2points(sln)

# Here is a bus stop which should be added as a node
 new_point_coordinates = c(-1.535, 53.809)
 p = sf::st_sf(geometry = sf::st_sfc(sf::st_point(new_point_coordinates)), crs = st_crs(rnet))


# plot
plot(sln, col = "gray")                 # network
plot(sln_nodes, col="red", add = TRUE)  # nodes
plot(p, add=T, col="blue")      # stop to be added as a new node

enter image description here


Solution

  • Thanks for the question, thanks to this question and subsequent collaboration with Andrea Gilardi, I'm happy to announce that it is now possible to add new nodes to sfNetwork objects with a new function, sln_add_node().

    See below and please try to test reproducible code that demonstrates how it works:

    devtools::install_github("ropensci/stplanr")
    #> Skipping install of 'stplanr' from a github remote, the SHA1 (33158a5b) has not changed since last install.
    #>   Use `force = TRUE` to force installation
    library(stplanr)
    #> Registered S3 method overwritten by 'R.oo':
    #>   method        from       
    #>   throw.default R.methodsS3
    #> Warning in fun(libname, pkgname): rgeos: versions of GEOS runtime 3.7.1-CAPI-1.11.1
    #> and GEOS at installation 3.7.0-CAPI-1.11.0differ
    
    sample_routes <- routes_fast_sf[2:6, NULL]
    sample_routes$value <- rep(1:3, length.out = 5)
    rnet <- overline2(sample_routes, attrib = "value")
    #> 2019-09-26 16:06:18 constructing segments
    #> 2019-09-26 16:06:18 building geometry
    #> 2019-09-26 16:06:18 simplifying geometry
    #> 2019-09-26 16:06:18 aggregating flows
    #> 2019-09-26 16:06:18 rejoining segments into linestrings
    plot(sample_routes["value"], lwd = sample_routes$value, main = "Routes")
    

    plot(rnet["value"], lwd = rnet$value, main = "Route network")
    

    sln <- SpatialLinesNetwork(rnet)
    #> Linking to GEOS 3.7.1, GDAL 2.4.0, PROJ 5.2.0
    
    new_point_coordinates <- c(-1.540, 53.826)
    crs <- sf::st_crs(rnet)
    p <- sf::st_sf(geometry = sf::st_sfc(sf::st_point(new_point_coordinates)), crs = crs)
    p_dest <- sln2points(sln)[9, ]
    
    # We can identify the nearest point on the network at this point
    # and use that to split the associated linestring:
    
    sln_new <- sln_add_node(sln = sln, p = p)
    #> although coordinates are longitude/latitude, st_nearest_feature assumes that they are planar
    route_new <- route_local(sln = sln_new, from = p, to = p_dest)
    plot(sln_new)
    plot(p, add = TRUE)
    plot(route_new, lwd = 5, add = TRUE)
    #> Warning in plot.sf(route_new, lwd = 5, add = TRUE): ignoring all but the
    #> first attribute
    

    Created on 2019-09-26 by the reprex package (v0.3.0)

    In case it's of use/interest, see the source code of the new small family of functions that support this new functionality here: https://github.com/ropensci/stplanr/blob/master/R/node-funs.R