-
Notifications
You must be signed in to change notification settings - Fork 32
New isochrone implementation using grids #518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Hi @mattwigway , thanks for this PR. On a quick look, this sounds really promising! I'm currently on a vacation trip, so I will only have time to have a closer look at this when I return in October. ps. did you see this error message from CMD check ?
|
That's interesting as it works locally, I'll take a look. Enjoy your vacation! |
I think the R CMD check error is due to the JAR not being rebuilt in the repo. I thought that was supposed to happen automatically, but it seems like it didn't in this case. |
This is a first implementation of the isochrone generation process discussed in #495. In a nutshell, the current isochrone generation code works by taking a random sample of points from the network (by default 80%), computing travel times to those points, and then taking a concave hull of the reachable subset of those points. This has several drawbacks:
In this pull request, I switch to computing travel times to a regular grid of points across the network (specifically a grid of Web Mercator pixels). Then I use the marching squares algorithm (as provided by the {isoband} package) to get the isochrones. This is the same approach taken by Conveyal.
Marching squares will ensure the isochrone line is always between a cell that is reachable and one that is not, so holes, tentacles, etc. will all be properly handled. For instance, here's a comparison of the isochrone generated by the current implementation and the new implementation, starting from the central bus station in Raleigh, NC (new/marching squares in blue, current/concave hull in yellow):
The current isochrone fills in a lot of unreachable areas between bus lines, whereas the new isochrone correctly gathers that these areas are inaccessible. It's a lot faster too; the current isochrone takes 41 seconds, whereas the new one takes 6.3 seconds for the first isochrone computed and 0.3s/isochrone after that (R5 caches the regular grid definition and linkage to the network after the first isochrone).
The new algorithm has one parameter, zoom, that controls the level of detail of the isochrones at the expense of computation. The zoom parameter can be set from 9 to 12 and controls the size of the regular grid; details are here. I have set the default to zoom 10. In my test network, R5 refuses to use zoom 12 because the area is too large. Currently the algorithm assumes the isochrone may reach to the full extent of the network; we could allow the user to specify a smaller maximum extent and thus use a finer grid over a smaller area. Isochrones from three of the zoom levels are below:
I'm creating this as a draft pull request so folks can start to give feedback on whether this is a desirable change and how to go about it. It needs a lot more testing as this ended up touching a lot of r5r code. Since the travel time grid process needs to return a matrix rather than an RDataFrame, I made R5Process a generic type so subclasses can return any value, and then have an extending R5DataFrameProcess that contains dataframe-specific features - which means that the codepath for every single analysis function has changed somewhat. I've also completely replaced the polygon isochrone generation code (though retained the line isochrone code)—I think it's desirable to do a complete replacement but a parallel implementation could also be considered.