riatelab/osrm

Is snaping coordinates to the street network possible when mapping isochrones?

aTnT opened this issue · 4 comments

aTnT commented

Hello,

First of all thanks for developing this amazing package!

I obtain the map below as the result of running:

  example_isochrone <-
    osrm::osrmIsochrone(
      loc = c(5.653536, 53.019535),
      breaks = seq(0, 30, 5),
      osrm.profile = "car",
      res = 100
    )

image

As you can see the iscochrones have plenty of "small polygon islands", i.e. areas with larger travel times than the surrounding. I believe this is because the random points are in agricultural fields away from the street network leading to larger travel times.

In my workflow i need to do a spatial join between these isochrones and other geospatial vector data, but because of these "small polygon islands" i get plenty of nonsensical results. I need to filter out these small islands.

I have noticed the osrm::osrmNearest() function that snaps a coordinate to the street network, but is it possible to call it as part of the osrm::osrmIsochrone() function call in order to force the sample points to be on the road network and hence remove these small islands? Or any hints on how i could filter out these islands?

Thanks for reading.

aTnT commented

I have tried to add a nearest = TRUE option to osrmIsochrone by adding a rgrid_nearest function to utils.R to force the grid points to snap to the road network. However while running

example_isochrone_nearest <-
  osrm::osrmIsochrone(
    loc = c(5.653536, 53.019535),
    breaks = seq(0, 30, 5),
    osrm.profile = "car",
    res = 50,
    nearest = TRUE
  )

i get an Error: It seems that 'x' is not a regular grid. and cannot find where this error occurs. Any hints on next steps?

See my mofifications in this branch:

master...aTnT:osrm:osrmIsochrone_with_optional_osrmNearest

In fact osrmIsochrone() already use snapped points.

1- We create a regular square grid centered on loc. The resolution of the grid is res x res, its size is defined by how far you could go in any direction at 120km/h in a straight line (for the car profile)

2- We compute a table of durations from loc to the grid points with osrmTable().

3- osrmTable() returns durations and the points actually used ("destinations", points snapped on the road network) to compute durations. We use these snapped points to assign duration values to the original grid cells/points.

4- We assign the value max(breaks) + 1 to any point that has a NA value (points that are not reachable)

5- We apply the isoband algorithm through mapiso to create isochrones.

6- it creates the small unreachable islands

I've created a small package with a different algo : https://github.com/rCarto/isochrone

1, 2 and 3 are the same steps

4- we transform the grid to a raster

5- we apply a focal moving window to the raster. It produces a smoothed version of the ratser and it fills the NA cells with smoothed values

6- We apply the isoband algorithm through mapiso to create isochrones.

7- it creates a lot less small unreachable islands

image

aTnT commented

Thanks for this, the focal filtering is a great feature, adding it to osrm would be nice but i can understand that you don't want to add the terra dependency. I also able to reproduce the results with terra_1.7-71 if someone is running previous with versions of terra you might be faced with an error Error: [focal] with "na.rm=TRUE" and weights other than 0, 1, or NA, only fun="sum" is allowed. In this case just upgrade to terra >= 1.7-71 and errors are gone.

Thanks for testing. I may add the smooth option to osrmIsochrone(), putting terra in "Suggests" and testing its install in the function (something like that https://github.com/riatelab/mapsf/blob/b05f7e85b4f6a549af2f178f5b547f2cd3dca241/R/mf_raster.R#L106)