From ea43364ec7092ec6519c5e2d95f891b997c93c95 Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:01:58 +0100 Subject: [PATCH 1/7] Add york_minimal, copied from york example as starting point --- examples/york_minimal/README.md | 1 + examples/york_minimal/README.qmd | 3 ++ examples/york_minimal/config.json | 22 +++++++++++ examples/york_minimal/cost.py | 26 +++++++++++++ examples/york_minimal/lts.py | 17 ++++++++ examples/york_minimal/setup.py | 64 +++++++++++++++++++++++++++++++ examples/york_minimal/utils.py | 1 + 7 files changed, 134 insertions(+) create mode 100644 examples/york_minimal/README.md create mode 100644 examples/york_minimal/README.qmd create mode 100644 examples/york_minimal/config.json create mode 100644 examples/york_minimal/cost.py create mode 100644 examples/york_minimal/lts.py create mode 100644 examples/york_minimal/setup.py create mode 120000 examples/york_minimal/utils.py diff --git a/examples/york_minimal/README.md b/examples/york_minimal/README.md new file mode 100644 index 0000000..cbc215e --- /dev/null +++ b/examples/york_minimal/README.md @@ -0,0 +1 @@ +This is an example of an OD pattern where the origins are zones and the destinations are individual points. diff --git a/examples/york_minimal/README.qmd b/examples/york_minimal/README.qmd new file mode 100644 index 0000000..f8aef7a --- /dev/null +++ b/examples/york_minimal/README.qmd @@ -0,0 +1,3 @@ +--- +format: gfm +--- \ No newline at end of file diff --git a/examples/york_minimal/config.json b/examples/york_minimal/config.json new file mode 100644 index 0000000..99c24b1 --- /dev/null +++ b/examples/york_minimal/config.json @@ -0,0 +1,22 @@ +{ + "requests": { + "description": "Manually drawn zones and flows to a few named destination points", + "pattern": { + "ZoneToPoint": { + "zones_path": "zones.geojson", + "destinations_path": "destinations.geojson", + "csv_path": "od.csv", + "origin_zone_centroid_fallback": false + } + }, + "origins_path": "buildings.geojson", + "destinations_path": "destinations.geojson" + }, + "uptake": "Identity", + "cost": { + "ExternalCommand": "python3 cost.py" + }, + "lts": { + "ExternalCommand": "python3 lts.py" + } +} diff --git a/examples/york_minimal/cost.py b/examples/york_minimal/cost.py new file mode 100644 index 0000000..79b55b1 --- /dev/null +++ b/examples/york_minimal/cost.py @@ -0,0 +1,26 @@ +import json +import sys + +# Output a numeric edge cost +def calculate(edge): + tags = edge["osm_tags"] + length_meters = edge["length_meters"] + lts = edge["lts"] + nearby_amenities = edge["nearby_amenities"] + slope = edge["slope"] + + # Return None to not use the edge at all + + if tags["highway"] == "residential": + return [round(length_meters), round(length_meters)] + else: + # Strongly avoid non-residential roads + return [round(10 * length_meters), round(10 * length_meters)] + + +# Read an array of JSON dictionaries from STDIN +input_batch = json.loads(sys.stdin.read()) +# Calculate an edge cost for each one +results = list(map(calculate, input_batch)) +# Write a JSON array of the resulting numbers +print(json.dumps(results)) diff --git a/examples/york_minimal/lts.py b/examples/york_minimal/lts.py new file mode 100644 index 0000000..af7b79f --- /dev/null +++ b/examples/york_minimal/lts.py @@ -0,0 +1,17 @@ +import json +import sys + +# Output 0 (not allowed), 1 (suitable for children), 2 (low stress), 3 (low stress), or 4 (high stress) +def calculate(tags): + if tags["highway"] == "residential": + return 2 + else: + return 4 + + +# Read an array of JSON dictionaries from STDIN +tags_batch = json.loads(sys.stdin.read()) +# Calculate LTS for each one +lts_results = list(map(calculate, tags_batch)) +# Write a JSON array of the resulting numbers +print(json.dumps(lts_results)) diff --git a/examples/york_minimal/setup.py b/examples/york_minimal/setup.py new file mode 100644 index 0000000..cefebe1 --- /dev/null +++ b/examples/york_minimal/setup.py @@ -0,0 +1,64 @@ +from utils import * + + +def makeOSM(): + download( + url="http://download.geofabrik.de/europe/great-britain/england/north-yorkshire-latest.osm.pbf", + outputFilename="input/north-yorkshire-latest.osm.pbf", + ) + # Clip to York + run( + [ + "osmium", + "extract", + "-b", + # http://bboxfinder.com for the win + "-1.18,53.90,-0.98,54.01", + "input/north-yorkshire-latest.osm.pbf", + "-o", + "input/input.osm.pbf", + ] + ) + + +def makeOrigins(): + extractCentroids( + osmInput="input/input.osm.pbf", geojsonOutput="input/buildings.geojson" + ) + + +def makeDestinations(): + writeFixedOutputFile( + "input/destinations.geojson", + """{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"poppleton"},"geometry":{"coordinates":[-2.141025,53.988014],"type":"Point"}},{"type":"Feature","properties":{"name":"corndogs"},"geometry":{"coordinates":[-1.080074,53.959366],"type":"Point"}}]}""", + ) + + +def makeZones(): + writeFixedOutputFile( + "input/zones.geojson", + """{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"center"},"geometry":{"coordinates":[[[-1.08285,53.970735],[-1.096017,53.958917],[-1.075591,53.947693],[-1.057528,53.967309],[-1.08285,53.970735]]],"type":"Polygon"}},{"type":"Feature","properties":{"name":"north"},"geometry":{"coordinates":[[[-1.094806,53.998733],[-1.068685,53.977605],[-1.025942,53.9965],[-1.056812,54.010736],[-1.094806,53.998733]]],"type":"Polygon"}},{"type":"Feature","properties":{"name":"south"},"geometry":{"coordinates":[[[-1.146752,53.957545],[-1.139312,53.924745],[-1.091661,53.9281],[-1.1067,53.956427],[-1.146752,53.957545]]],"type":"Polygon"}}]}""", + ) + + +def makeOD(): + writeFixedOutputFile( + "input/od.csv", + """from,to,count +south,poppleton,500 +center,poppleton,100 +north,poppleton,200 +south,corndogs,800 +center,corndogs,300 +north,corndogs,600""", + ) + + +if __name__ == "__main__": + checkDependencies() + run(["mkdir", "-p", "input"]) + makeOSM() + makeOrigins() + makeDestinations() + makeZones() + makeOD() diff --git a/examples/york_minimal/utils.py b/examples/york_minimal/utils.py new file mode 120000 index 0000000..50fbc6d --- /dev/null +++ b/examples/york_minimal/utils.py @@ -0,0 +1 @@ +../utils.py \ No newline at end of file From 0112bfe68b2e826c0a46aff580d738d2c61c8960 Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:14:36 +0100 Subject: [PATCH 2/7] Visualise basic inputs (hide output files) --- examples/york_minimal/README.md | 23 ++++++++++++++++++++++- examples/york_minimal/README.qmd | 21 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/examples/york_minimal/README.md b/examples/york_minimal/README.md index cbc215e..afe9c09 100644 --- a/examples/york_minimal/README.md +++ b/examples/york_minimal/README.md @@ -1 +1,22 @@ -This is an example of an OD pattern where the origins are zones and the destinations are individual points. + + +The setup information is contained within the `setup.py` file, which +generates minimal input files. + +``` {bash} +python setup.py +``` + +We can visualise these as follows: + +``` python +import geopandas as gpd +import pandas as pd +zones = gpd.read_file("input/zones.geojson") +destinations = gpd.read_file("input/destinations.geojson") +od = pd.read_csv("input/od.csv") +ax = zones.plot() +destinations.plot(ax=ax, color='red') +``` + +![](README_files/figure-commonmark/cell-2-output-1.png) diff --git a/examples/york_minimal/README.qmd b/examples/york_minimal/README.qmd index f8aef7a..f0fe56d 100644 --- a/examples/york_minimal/README.qmd +++ b/examples/york_minimal/README.qmd @@ -1,3 +1,22 @@ --- format: gfm ---- \ No newline at end of file +--- + +The setup information is contained within the `setup.py` file, which generates minimal input files. + +```{bash} +python setup.py +``` + +We can visualise these as follows: + + +```{python} +import geopandas as gpd +import pandas as pd +zones = gpd.read_file("input/zones.geojson") +destinations = gpd.read_file("input/destinations.geojson") +od = pd.read_csv("input/od.csv") +ax = zones.plot() +destinations.plot(ax=ax, color='red') +``` \ No newline at end of file From 5b0b80ab005e536e71fbdd941ae9614b6be37dfb Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:47:39 +0100 Subject: [PATCH 3/7] Ignore outputs for now --- examples/york_minimal/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/york_minimal/.gitignore diff --git a/examples/york_minimal/.gitignore b/examples/york_minimal/.gitignore new file mode 100644 index 0000000..b21bc4b --- /dev/null +++ b/examples/york_minimal/.gitignore @@ -0,0 +1 @@ +README_files/ From b4b5a4b93f7c8ebca21395f6d85703f73e57acb1 Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:47:56 +0100 Subject: [PATCH 4/7] Add weighted subpoints for #77 --- examples/york_minimal/README.md | 85 +++++++++++++++++++++++++++++++- examples/york_minimal/README.qmd | 36 +++++++++++++- examples/york_minimal/setup.py | 19 +++---- 3 files changed, 124 insertions(+), 16 deletions(-) diff --git a/examples/york_minimal/README.md b/examples/york_minimal/README.md index afe9c09..065b69c 100644 --- a/examples/york_minimal/README.md +++ b/examples/york_minimal/README.md @@ -3,10 +3,88 @@ The setup information is contained within the `setup.py` file, which generates minimal input files. -``` {bash} +``` bash python setup.py ``` +We’ll get a sample of 2 schools in York (York High School and Huntington +School) using the `osmextract` package. + +``` r +library(osmextract) +``` + + Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright. + Check the package website, https://docs.ropensci.org/osmextract/, for more details. + +``` r +q = "SELECT * FROM multipolygons WHERE amenity='school'" +schools_york = osmextract::oe_get("York", query = q, extra_tags = "amenity") +``` + + No exact match found for place = York and provider = geofabrik. Best match is Corse. + Checking the other providers. + + No exact match found in any OSM provider data. Searching for the location online. + + The input place was matched with North Yorkshire. + + The chosen file was already detected in the download directory. Skip downloading. + + The corresponding gpkg file was already detected. Skip vectortranslate operations. + + Reading query `SELECT * FROM multipolygons WHERE amenity='school'' + from data source `/home/robin/data/osm/geofabrik_north-yorkshire-latest.gpkg' + using driver `GPKG' + Simple feature collection with 603 features and 25 fields + Geometry type: MULTIPOLYGON + Dimension: XY + Bounding box: xmin: -2.546044 ymin: 53.6425 xmax: -0.2912398 ymax: 54.61681 + Geodetic CRS: WGS 84 + +``` r +# schools_york$name +schools_york_minimal = dplyr::filter( + schools_york, + name %in% c("York High School", "Huntington School") +) +schools_york_minimal$name +``` + + [1] "York High School" "Huntington School" + +``` r +# Remove columns that only contain NA: +schools_york_minimal = schools_york_minimal[, colSums(is.na(schools_york_minimal)) < nrow(schools_york_minimal)] +sf::write_sf(schools_york_minimal, "input/destinations.geojson", delete_dsn = TRUE) +``` + +We’ll also create a sample of subpoints in York, taking 3 random points +from each zone. + +``` r +zones = sf::st_read("input/zones.geojson") +``` + + Reading layer `zones' from data source + `/home/robin/github/Urban-Analytics-Technology-Platform/od2net/examples/york_minimal/input/zones.geojson' + using driver `GeoJSON' + Simple feature collection with 3 features and 1 field + Geometry type: POLYGON + Dimension: XY + Bounding box: xmin: -1.146752 ymin: 53.92474 xmax: -1.025942 ymax: 54.01074 + Geodetic CRS: WGS 84 + +``` r +set.seed(123) +subpoints = sf::st_sample(zones, size = rep(3, nrow(zones))) |> + sf::st_sf() +# Let's add provide the subpoints with values representing their importance: +subpoints$size = runif(nrow(subpoints), 1, 10) |> + round(1) +sf::write_sf(subpoints, "input/subpoints.geojson", delete_dsn = TRUE) +``` + We can visualise these as follows: ``` python @@ -14,9 +92,12 @@ import geopandas as gpd import pandas as pd zones = gpd.read_file("input/zones.geojson") destinations = gpd.read_file("input/destinations.geojson") +subpoints = gpd.read_file("input/subpoints.geojson") od = pd.read_csv("input/od.csv") ax = zones.plot() destinations.plot(ax=ax, color='red') +subpoints.plot(ax=ax, color='blue', markersize=subpoints['size'] * 3) +ax.set_title("Origins and Destinations") ``` -![](README_files/figure-commonmark/cell-2-output-1.png) +![](README_files/figure-commonmark/origins_destinations_plot-1.png) diff --git a/examples/york_minimal/README.qmd b/examples/york_minimal/README.qmd index f0fe56d..1564455 100644 --- a/examples/york_minimal/README.qmd +++ b/examples/york_minimal/README.qmd @@ -5,18 +5,52 @@ format: gfm The setup information is contained within the `setup.py` file, which generates minimal input files. ```{bash} +#| eval: false python setup.py ``` -We can visualise these as follows: +We'll get a sample of 2 schools in York (York High School and Huntington School) using the `osmextract` package. + +```{r} +library(osmextract) +q = "SELECT * FROM multipolygons WHERE amenity='school'" +schools_york = osmextract::oe_get("York", query = q, extra_tags = "amenity") +# schools_york$name +schools_york_minimal = dplyr::filter( + schools_york, + name %in% c("York High School", "Huntington School") +) +schools_york_minimal$name +# Remove columns that only contain NA: +schools_york_minimal = schools_york_minimal[, colSums(is.na(schools_york_minimal)) < nrow(schools_york_minimal)] +sf::write_sf(schools_york_minimal, "input/destinations.geojson", delete_dsn = TRUE) +``` + +We'll also create a sample of subpoints in York, taking 3 random points from each zone. +```{r} +zones = sf::st_read("input/zones.geojson") +set.seed(123) +subpoints = sf::st_sample(zones, size = rep(3, nrow(zones))) |> + sf::st_sf() +# Let's add provide the subpoints with values representing their importance: +subpoints$size = runif(nrow(subpoints), 1, 10) |> + round(1) +sf::write_sf(subpoints, "input/subpoints.geojson", delete_dsn = TRUE) +``` + +We can visualise these as follows: ```{python} +#| label: origins_destinations_plot import geopandas as gpd import pandas as pd zones = gpd.read_file("input/zones.geojson") destinations = gpd.read_file("input/destinations.geojson") +subpoints = gpd.read_file("input/subpoints.geojson") od = pd.read_csv("input/od.csv") ax = zones.plot() destinations.plot(ax=ax, color='red') +subpoints.plot(ax=ax, color='blue', markersize=subpoints['size'] * 3) +ax.set_title("Origins and Destinations") ``` \ No newline at end of file diff --git a/examples/york_minimal/setup.py b/examples/york_minimal/setup.py index cefebe1..168ed37 100644 --- a/examples/york_minimal/setup.py +++ b/examples/york_minimal/setup.py @@ -27,13 +27,6 @@ def makeOrigins(): ) -def makeDestinations(): - writeFixedOutputFile( - "input/destinations.geojson", - """{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"poppleton"},"geometry":{"coordinates":[-2.141025,53.988014],"type":"Point"}},{"type":"Feature","properties":{"name":"corndogs"},"geometry":{"coordinates":[-1.080074,53.959366],"type":"Point"}}]}""", - ) - - def makeZones(): writeFixedOutputFile( "input/zones.geojson", @@ -45,12 +38,12 @@ def makeOD(): writeFixedOutputFile( "input/od.csv", """from,to,count -south,poppleton,500 -center,poppleton,100 -north,poppleton,200 -south,corndogs,800 -center,corndogs,300 -north,corndogs,600""", +south,York High School,500 +center,York High School,100 +north,York High School,200 +south,Huntington School,800 +center,Huntington School,300 +north,Huntington School,600""", ) From ab8c1f365d10e6511d1a00f29fb91940a76f5aa0 Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:51:15 +0100 Subject: [PATCH 5/7] Update config --- examples/york_minimal/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/york_minimal/config.json b/examples/york_minimal/config.json index 99c24b1..54e9168 100644 --- a/examples/york_minimal/config.json +++ b/examples/york_minimal/config.json @@ -1,6 +1,6 @@ { "requests": { - "description": "Manually drawn zones and flows to a few named destination points", + "description": "Manually drawn zones and flows to schools, demonstrating weighted subpoints", "pattern": { "ZoneToPoint": { "zones_path": "zones.geojson", @@ -9,7 +9,7 @@ "origin_zone_centroid_fallback": false } }, - "origins_path": "buildings.geojson", + "origins_path": "subpoints.geojson", "destinations_path": "destinations.geojson" }, "uptake": "Identity", From 80ca8e8800d85c50d794b6d47087faa724c6dcbf Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 16:54:09 +0100 Subject: [PATCH 6/7] Add docker run command --- examples/york_minimal/README.qmd | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/york_minimal/README.qmd b/examples/york_minimal/README.qmd index 1564455..91c4014 100644 --- a/examples/york_minimal/README.qmd +++ b/examples/york_minimal/README.qmd @@ -53,4 +53,12 @@ ax = zones.plot() destinations.plot(ax=ax, color='red') subpoints.plot(ax=ax, color='blue', markersize=subpoints['size'] * 3) ax.set_title("Origins and Destinations") +``` + +We can then run the od2net command as follows: + + +```{bash} +#| eval: false +docker run -v $(pwd):/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json ``` \ No newline at end of file From 4b53b3304f8b437ddbeb83c168ce27da0f08e771 Mon Sep 17 00:00:00 2001 From: robinlovelace Date: Tue, 24 Sep 2024 17:30:28 +0100 Subject: [PATCH 7/7] Add inputs, save having to run R code Update to make destinations points --- examples/york_minimal/.gitignore | 2 + examples/york_minimal/README.md | 57 +++++++++++++++++-- examples/york_minimal/README.qmd | 42 ++++++++++++-- .../york_minimal/input/destinations.geojson | 9 +++ examples/york_minimal/input/od.csv | 7 +++ examples/york_minimal/input/subpoints.geojson | 16 ++++++ examples/york_minimal/input/zones.geojson | 1 + examples/york_minimal/setup.py | 10 +--- 8 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 examples/york_minimal/input/destinations.geojson create mode 100644 examples/york_minimal/input/od.csv create mode 100644 examples/york_minimal/input/subpoints.geojson create mode 100644 examples/york_minimal/input/zones.geojson diff --git a/examples/york_minimal/.gitignore b/examples/york_minimal/.gitignore index b21bc4b..8bae4a5 100644 --- a/examples/york_minimal/.gitignore +++ b/examples/york_minimal/.gitignore @@ -1 +1,3 @@ README_files/ +input/north-yorkshire-latest.osm.pbf +input/inputs.html diff --git a/examples/york_minimal/README.md b/examples/york_minimal/README.md index 065b69c..fec25fe 100644 --- a/examples/york_minimal/README.md +++ b/examples/york_minimal/README.md @@ -44,19 +44,26 @@ schools_york = osmextract::oe_get("York", query = q, extra_tags = "amenity") ``` r # schools_york$name -schools_york_minimal = dplyr::filter( +destinations = dplyr::filter( schools_york, name %in% c("York High School", "Huntington School") -) -schools_york_minimal$name +) |> + dplyr::select(name, everything()) +destinations$name ``` [1] "York High School" "Huntington School" ``` r # Remove columns that only contain NA: -schools_york_minimal = schools_york_minimal[, colSums(is.na(schools_york_minimal)) < nrow(schools_york_minimal)] -sf::write_sf(schools_york_minimal, "input/destinations.geojson", delete_dsn = TRUE) +destinations = destinations[, colSums(is.na(destinations)) < nrow(destinations)] +destinations = sf::st_centroid(destinations) +``` + + Warning: st_centroid assumes attributes are constant over geometries + +``` r +sf::write_sf(destinations, "input/destinations.geojson", delete_dsn = TRUE) ``` We’ll also create a sample of subpoints in York, taking 3 random points @@ -101,3 +108,43 @@ ax.set_title("Origins and Destinations") ``` ![](README_files/figure-commonmark/origins_destinations_plot-1.png) + +Let’s visualise the flows between the origins and destinations: + +``` r +library(ggplot2) +od = readr::read_csv("input/od.csv") +``` + + Rows: 6 Columns: 3 + ── Column specification ──────────────────────────────────────────────────────── + Delimiter: "," + chr (2): from, to + dbl (1): count + + ℹ Use `spec()` to retrieve the full column specification for this data. + ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message. + +``` r +od_geo = od::od_to_sf(od, zones, destinations) +``` + + 0 origins with no match in zone ids + 0 destinations with no match in zone ids + points not in od data removed. + +``` r +ggplot() + + geom_sf(data = zones, fill = "grey") + + geom_sf(data = subpoints, aes(size = size), color = "blue") + + geom_sf(data = destinations, color = "red") + + geom_sf(data = od_geo, aes(size = count), color = "black") +``` + +![](README_files/figure-commonmark/flows_plot-3.png) + +We can then run the od2net command as follows: + +``` bash +docker run -v $(pwd):/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json +``` diff --git a/examples/york_minimal/README.qmd b/examples/york_minimal/README.qmd index 91c4014..0f92bf9 100644 --- a/examples/york_minimal/README.qmd +++ b/examples/york_minimal/README.qmd @@ -16,14 +16,16 @@ library(osmextract) q = "SELECT * FROM multipolygons WHERE amenity='school'" schools_york = osmextract::oe_get("York", query = q, extra_tags = "amenity") # schools_york$name -schools_york_minimal = dplyr::filter( +destinations = dplyr::filter( schools_york, name %in% c("York High School", "Huntington School") -) -schools_york_minimal$name +) |> + dplyr::select(name, everything()) +destinations$name # Remove columns that only contain NA: -schools_york_minimal = schools_york_minimal[, colSums(is.na(schools_york_minimal)) < nrow(schools_york_minimal)] -sf::write_sf(schools_york_minimal, "input/destinations.geojson", delete_dsn = TRUE) +destinations = destinations[, colSums(is.na(destinations)) < nrow(destinations)] +destinations = sf::st_centroid(destinations) +sf::write_sf(destinations, "input/destinations.geojson", delete_dsn = TRUE) ``` We'll also create a sample of subpoints in York, taking 3 random points from each zone. @@ -55,6 +57,36 @@ subpoints.plot(ax=ax, color='blue', markersize=subpoints['size'] * 3) ax.set_title("Origins and Destinations") ``` +Let's visualise the flows between the origins and destinations: + +```{r} +#| label: flows_plot +library(ggplot2) +od = readr::read_csv("input/od.csv") +od_geo = od::od_to_sf(od, zones, destinations) +ggplot() + + geom_sf(data = zones, fill = "grey") + + geom_sf(data = subpoints, aes(size = size), color = "blue") + + geom_sf(data = destinations, color = "red") + + geom_sf(data = od_geo, aes(size = count), color = "black") +``` + +```{r} +#| eval: false +#| echo: false +library(tmap) +tmap_mode("view") +m = qtm(zones) + + tm_shape(subpoints) + + tm_dots(size = "size", col = "blue") + + tm_shape(destinations) + + tm_dots(fill = "red", size = 5) + + tm_shape(od_geo) + + tm_lines(lwd = "count", col = "black", scale = 9) +tmap_save(m, "input/inputs.html") +browseURL("input/inputs.html") +``` + We can then run the od2net command as follows: diff --git a/examples/york_minimal/input/destinations.geojson b/examples/york_minimal/input/destinations.geojson new file mode 100644 index 0000000..890c75b --- /dev/null +++ b/examples/york_minimal/input/destinations.geojson @@ -0,0 +1,9 @@ +{ +"type": "FeatureCollection", +"name": "destinations", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "name": "York High School", "osm_way_id": "29110900", "amenity": "school", "other_tags": "\"addr:city\"=>\"York\",\"addr:country\"=>\"GB\",\"addr:postcode\"=>\"YO24 3WZ\",\"addr:street\"=>\"Cornlands Road\",\"addr:suburb\"=>\"Acomb\",\"capacity\"=>\"991\",\"email\"=>\"reception@yorkhigh.southbank.academy\",\"isced:level\"=>\"2\",\"max_age\"=>\"16\",\"min_age\"=>\"11\",\"phone\"=>\"+44 1904 555500\",\"ref:GB:uprn\"=>\"100052163540\",\"ref:edubase\"=>\"144652\",\"ref:edubase:group\"=>\"16073\",\"school:trust\"=>\"yes\",\"school:trust:name\"=>\"South Bank Multi Academy Trust\",\"school:trust:type\"=>\"multi_academy\",\"school:type\"=>\"academy\",\"website\"=>\"https://www.yorkhighschool.co.uk/\",\"wikidata\"=>\"Q8055461\",\"wikipedia\"=>\"en:York High School, York\"" }, "geometry": { "type": "Point", "coordinates": [ -1.128900930965928, 53.947613356147485 ] } }, +{ "type": "Feature", "properties": { "name": "Huntington School", "osm_way_id": "122135723", "amenity": "school", "other_tags": "\"addr:country\"=>\"GB\",\"addr:postcode\"=>\"YO32 9WT\",\"addr:street\"=>\"Huntington Road\",\"capacity\"=>\"1545\",\"email\"=>\"mail@huntington-ed.org.uk\",\"isced:level\"=>\"2;3\",\"max_age\"=>\"18\",\"min_age\"=>\"11\",\"phone\"=>\"+44 1904 752100\",\"ref:GB:uprn\"=>\"100052170371\",\"ref:edubase\"=>\"121673\",\"school:trust\"=>\"no\",\"school:type\"=>\"community\",\"website\"=>\"https://huntingtonschool.co.uk/\"" }, "geometry": { "type": "Point", "coordinates": [ -1.063642017028779, 53.990093958328686 ] } } +] +} diff --git a/examples/york_minimal/input/od.csv b/examples/york_minimal/input/od.csv new file mode 100644 index 0000000..f63567a --- /dev/null +++ b/examples/york_minimal/input/od.csv @@ -0,0 +1,7 @@ +from,to,count +south,York High School,500 +center,York High School,100 +north,York High School,200 +south,Huntington School,800 +center,Huntington School,300 +north,Huntington School,600 \ No newline at end of file diff --git a/examples/york_minimal/input/subpoints.geojson b/examples/york_minimal/input/subpoints.geojson new file mode 100644 index 0000000..07fbe54 --- /dev/null +++ b/examples/york_minimal/input/subpoints.geojson @@ -0,0 +1,16 @@ +{ +"type": "FeatureCollection", +"name": "subpoints", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "size": 7.2 }, "geometry": { "type": "Point", "coordinates": [ -1.084948428827924, 53.959860019753116 ] } }, +{ "type": "Feature", "properties": { "size": 8.2 }, "geometry": { "type": "Point", "coordinates": [ -1.065675923641903, 53.968255508127534 ] } }, +{ "type": "Feature", "properties": { "size": 1.2 }, "geometry": { "type": "Point", "coordinates": [ -1.08027588725639, 53.960397590493173 ] } }, +{ "type": "Feature", "properties": { "size": 5.3 }, "geometry": { "type": "Point", "coordinates": [ -1.048145775760174, 53.988466436780065 ] } }, +{ "type": "Feature", "properties": { "size": 7.8 }, "geometry": { "type": "Point", "coordinates": [ -1.055372173407674, 54.009228087733909 ] } }, +{ "type": "Feature", "properties": { "size": 2.9 }, "geometry": { "type": "Point", "coordinates": [ -1.077859414261401, 53.998822595720604 ] } }, +{ "type": "Feature", "properties": { "size": 3.9 }, "geometry": { "type": "Point", "coordinates": [ -1.11062851182091, 53.93422678953317 ] } }, +{ "type": "Feature", "properties": { "size": 3.1 }, "geometry": { "type": "Point", "coordinates": [ -1.107718347978171, 53.929568710302227 ] } }, +{ "type": "Feature", "properties": { "size": 2.3 }, "geometry": { "type": "Point", "coordinates": [ -1.116778858632627, 53.956331735484653 ] } } +] +} diff --git a/examples/york_minimal/input/zones.geojson b/examples/york_minimal/input/zones.geojson new file mode 100644 index 0000000..105ded4 --- /dev/null +++ b/examples/york_minimal/input/zones.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"center"},"geometry":{"coordinates":[[[-1.08285,53.970735],[-1.096017,53.958917],[-1.075591,53.947693],[-1.057528,53.967309],[-1.08285,53.970735]]],"type":"Polygon"}},{"type":"Feature","properties":{"name":"north"},"geometry":{"coordinates":[[[-1.094806,53.998733],[-1.068685,53.977605],[-1.025942,53.9965],[-1.056812,54.010736],[-1.094806,53.998733]]],"type":"Polygon"}},{"type":"Feature","properties":{"name":"south"},"geometry":{"coordinates":[[[-1.146752,53.957545],[-1.139312,53.924745],[-1.091661,53.9281],[-1.1067,53.956427],[-1.146752,53.957545]]],"type":"Polygon"}}]} \ No newline at end of file diff --git a/examples/york_minimal/setup.py b/examples/york_minimal/setup.py index 168ed37..ff9efa8 100644 --- a/examples/york_minimal/setup.py +++ b/examples/york_minimal/setup.py @@ -17,16 +17,10 @@ def makeOSM(): "input/north-yorkshire-latest.osm.pbf", "-o", "input/input.osm.pbf", + "--overwrite", ] ) - -def makeOrigins(): - extractCentroids( - osmInput="input/input.osm.pbf", geojsonOutput="input/buildings.geojson" - ) - - def makeZones(): writeFixedOutputFile( "input/zones.geojson", @@ -51,7 +45,5 @@ def makeOD(): checkDependencies() run(["mkdir", "-p", "input"]) makeOSM() - makeOrigins() - makeDestinations() makeZones() makeOD()