Closed Robinlovelace closed 3 years ago
Search for: Workplace Zones (WPZ)
FYI the documentation for journey time statistics outlines where to get at a lot of these
Do you have a link to this documentation @mem48 ?
I've uploaded an OD file of homes and workplaces at the MSOA level for the 4 Leeds sites. Workplaces are obtained using the MSOA the site lies within. We could use more than one MSOA / OA, but this is a starting point. @si-the-pie
Do you have a link to this documentation @mem48 ?
See page 10-12 for data sources eg for town centres
In terms of routing do you have the input data needed to generate routes for Leeds @mvl22 and @si-the-pie ?
As a starter for 10, here's reproducible code to get routes for the first 9 of the OD pairs provided by @joeytalbot:
# Aim: test routing for actdev project
remotes::install_github("ropensci/stplanr")
remotes::install_github("robinlovelace/cyclestreets")
library(sf)
library(cyclestreets)
u = "https://github.com/cyipt/actdev/releases/download/0.1.1/od-flows-leeds.csv"
od_data = readr::read_csv(u)
l = stplanr::od_coords2line(odc = od_data)
l$length = sf::st_length(l)
summary(l$length)
r1 = journey(from = c(od_data$ox[1], od_data$oy[1]), to = c(od_data$dx[1], od_data$dy[1]))
mapview::mapview(r1["gradient_smooth"])
mapview::mapview(l)
od_linestrings = stplanr::route(l = l[1:9, ], route_fun = journey)
od_linestrings
mapview::mapview(od_linestrings["provisionName"])
Results look good to me:
In terms of routing do you have the input data needed to generate routes for Leeds @mvl22 and @si-the-pie ?
I think this is pending the POIs stuff?
I think this is pending the POIs stuff?
No, the data in https://github.com/cyipt/actdev/releases/download/0.1.1/od-flows-leeds.csv is ready to go. Happy to do the routing here in Leeds but thought it may be quicker/easier for CycleStreets to do - by fastest, quietest and balanced profiles if possible.
Renaming this as it's about deciding which desire lines to route to. Then we can do the routing which in some ways is the easy part.
I've been reading the pdf that Joey sent and looking at the marvellous R code that Robin splashed and decided to have a play with the data.
The csv
that Joey kindly provided was processed as follows:
-- PhpMyAdmin was used to import the CSV which generates this table structure:
Create Table: CREATE TABLE `TBL_NAME` (
`COL 1` varchar(19) DEFAULT NULL,
`COL 2` varchar(18) DEFAULT NULL,
`COL 3` varchar(19) DEFAULT NULL,
`COL 4` varchar(18) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- This is copied to a local table as follows:
drop table if exists originDestination;
create table originDestination (
id int unsigned not null auto_increment primary key,
waypoints varchar(255) not null comment "In a format suitable for sending to CycleStreets Journey Planner API"
) engine=myisam;
-- Fill, setting the waypoints field
insert originDestination (waypoints)
select concat(`COL 1`, ',', `COL 2`, '|', `COL 3`, ',', `COL 4`)
from CSV_DB.TBL_NAME;
This rendering of straight lines between the coordinates of each row from looks identical to the second image that Robin produced:
This was produced by this unglamourous sql which collates all the geometries into a FeatureCollection
:
-- The outer query makes the FeatureCollection from the component geometries as Features
select concat('{"type":"FeatureCollection","features":[',
group_concat('{"type":"Feature","properties":{"id":', id, '},"geometry":', geojson, '}'),
']}') FeatureCollection
from
-- The subquery collates the origin destinations from the waypoint strings as geometries and converts to geojson
(select id, st_asgeojson(st_geomfromtext(concat('linestring(',replace(replace(waypoints,',',' '), '|', ','),')'),0))geojson
from originDestination)x;
The existing batch routing system in CycleStreets expects a set of points. Routes are generated between each pair of points.
But the data provided here is a origins and destinations, one per row of the table. So the following function was written to process each of the routes in turn and place the result in the table. This is an edited highlight of the actual code:
private function originsDestinations ()
{
// Routing
$parameters = array ();
$parameters['key'] = $this->settings['internalApikey'];
$parameters['plans'] = 'balanced';
// Journey Planner api call
$journeyPlanUrl = $this->settings['apiV2Url'] . 'journey.plan?' . http_build_query ($parameters);
// Iterate
$errors = 0;
$updated = 0;
foreach ($od_data as $od_datum) {
// Set the waypoints
$parameters['waypoints'] = $od_datum['waypoints'];
// Journey Planner api call url
$journeyPlanUrl = $this->settings['apiV2Url'] . 'journey.plan?' . http_build_query ($parameters);
// Get the route
$geojsonTxt = file_get_contents ($journeyPlanUrl);
if (!$geojsonTxt) {continue;}
// Check for error
if (substr ($geojsonTxt, 0, 9) == '{"error":') {$errors++;}
// Unpack the route
if (!$routeData = json_decode ($geojsonTxt, $assoc = true)) {return $this->abandonHtml ("Error decoding the json.");}
// Save to the database table
$data = array ('journey' => $geojsonTxt);
$conditions = array ('id' => $od_datum['id']);
$result = $this->databaseConnection->update ($this->settings['database'], $table, $data, $conditions);
if ($result) {$updated++;}
// Extract the geometry from the route and add that to another table column
$routeGeojson = json_encode ($routeData['features'][2]['geometry']);
$query = "update {$table} set geometry = st_geomfromgeojson('{$routeGeojson}') where id={$od_datum['id']}";
$result = $this->databaseConnection->execute ($query);
if ($result) {$updated++;}
}
}
Similar unglamourous sql was used to collate the route geometries, into a single geojson file (7.3MB), with the result as follows:
The main issue that I have learned is that the batch routing system in CycleStreets has a different expectation about the origins and destinations as in the ACTDEV project.
In ACTDEV (as I understand it), origins and destinations are distinct sets. No route will ever need to be planned between one origin and another origin, and no route will ever be needed betweed two destinations. So for instance there will never be the need to plan a route between a Primary School and a GP surgery.
In the CycleStreets batch routing system, there is essentially no distinction between origins and destinations. They are all provided as a single set of points. Routes are generated between each pair of points. So currently it would plan a route between a Primary School and a GP surgery.
This has not happened in the current example as a table of origins and destinations has been provided, and instead of the batch routing a simple iteration has been performed.
But it is desirable to use the batch routing system because that can scale up. So therefore it needs augmenting with a way of distinguishing origins from destinations.
Thanks for testing this @si-the-pie. Indeed, the OD data in which the set of destinations is different from the set of origins poses a challenge for batch routing, including Google's Distance Matrix API: https://developers.google.com/maps/documentation/distance-matrix/overview
I suggest that for the purposes of this project we forge ahead using the R interface to cyclestreets, which can calculate in the order of 10 routes per second. One question for @si-the-pie, could you reproduce the code listed here? https://github.com/cyipt/actdev/issues/10#issuecomment-744539260
You may need to install a recent version of R for that to work and set-up an environment variable with an API key, happy to help with that.
In terms of the results, can you share the resulting data file that represents all the generated routes?
In terms of next steps my first impressions are that a good plan to update the batch routing API but I think we can get sufficiently detailed route data for the 4 study areas, and even the yet-to-be-generated list of ~1000 sites using the existing approach for the purposes of this project. This raises other questions about what next steps are and the best use of valuable combined ~150 days of full time work that we have on the project but suggest we save that until after Christmas holidays. Have a great break Simon and catch up in the NY!
@Robinlovelace: Errors appeared when cutting and pasting some of your code into the version of R Studio that we installed during the March 2020 hackathon. It probably needs updating as you suggest, and your help would be very welcome.
The testing has helped get familiar with the data, terminology and some of the issues involved so has been a useful exercise.
The data file is 7.3MB, but only 789K when compressed, and is just a geojson FeaturesCollection. Presumably it should be added to https://github.com/cyipt/actdev/releases/ but how is that done?
Presumably it should be added to https://github.com/cyipt/actdev/releases/ but how is that done?
You should be able to upload it by editing the release. Even easier is attaching the file to this issue, you can click on the "Attach files" text at the bottom of the issue text box. Will try adding a .zip file here to test...
utils::zip("/home/robin/other-repos/sfnetworks/data/roxel.rda", zipfile = "/tmp/test.zip")
In terms of getting R working, could you try following the instructions and links here @si-the-pie ?
https://itsleeds.github.io/rrsrr/introduction.html#installing-r-and-rstudio
Sure we can get it working!
Ah, yes, of course! Here it is: routes.json.gz
By the way all co-ordinates are rounded to five places of decimals, which is metre-level precision.
Thanks for the instructions for R.
Heads-up everyone: after good discussion with @joeytalbot I'm working on getting the supermarkets nationally. We can simply use the closest to the site as a destination. Please provide an update on what you're working on Joey - I think we may be able to close this issue by the end of the day based on the updated checklist above.
Thanks - it’s been on my todo list for a while to get back to the POIs stuff, but I’ve no doubt you’d solve it more efficiently than I would! The new library seems great - use of extracts is far better than the Overpass API approach.
I'm working at getting a list of town centre locations (using the same dataset as the jts) and routing from sites using these as destinations.
Heads-up everyone: after good discussion with @joeytalbot I'm working on getting the supermarkets nationally. We can simply use the closest to the site as a destination. Please provide an update on what you're working on Joey - I think we may be able to close this issue by the end of the day based on the updated checklist above.
Finding the number of supermarkets within a given distance would give us a better idea of whether a place has lots of shops nearby, or simply one giant supermarket complex.
Finding the number of supermarkets within a given distance would give us a better idea of whether a place has lots of shops nearby, or simply one giant supermarket complex.
True that - I think as a starter for 10 on the Phase 1 prototype the nearest is good. Worth opening an issue and labeling as a stretch issue like these?
Don't forget about the OSM landuse
areas tag:
https://wiki.openstreetmap.org/wiki/Key:landuse
This will probably not have widespread coverage in less good OSM areas though.
Heads-up @mvl22 and @joeytalbot I've done my part of the issue. The result can be found here: https://github.com/cyipt/actdev/releases/download/0.1.2/supermarket-points-england.geojson
Gratuitous reprex, because reproducibility is important + fun:
u = "https://github.com/cyipt/actdev/releases/download/0.1.2/supermarket-points-england.geojson"
pois = sf::read_sf(u)
mapview::mapview(pois)
Created on 2021-02-02 by the reprex package (v1.0.0)
Now running for all GB.
Update: job done on supermarkets. Keep us updated on the towns data @joeytalbot, and look forward to seeing routes to these important destinations!
u = "https://github.com/cyipt/actdev/releases/download/0.1.2/supermarket-points-gb.geojson"
pois = sf::read_sf(u)
mapview::mapview(pois)
Created on 2021-02-02 by the reprex package (v1.0.0)
If that's all of the supermarkets it must be missing a lot. Look at Cumbria, big towns like Penrith have nothing at all.
I've created routes and desire lines from Great Kneighton and Chapelford to their nearest town centre centroid.
eg https://github.com/cyipt/actdev/blob/main/data-small/great-kneighton/route_fast_town.geojson
The town centre dataset is also not perfect, it's from 2004 and in Leeds it includes places like Headingley, Yeadon, Guiseley, Crossgates, Harehills, Armley but misses Horsforth and Chapeltown/Chapel Allerton which should definitely be there.
If that's all of the supermarkets it must be missing a lot. Look at Cumbria, big towns like Penrith have nothing at all.
Good point. Probably one for Phase II.
[x] Destinations of work
[ ] Nearest supermarkets (start simple)
Nearest school[x] Town centre
StationsOther categories from Journey Time Statistics?Stretch target: spatial interaction model
Output format: GeoJSON a bit like this: (add example dataset)
Add each of these raw datasets and the resulting routing dataset as new Github releases.