Skip to content

Commit

Permalink
Add minimal R package (Urban-Analytics-Technology-Platform#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
Robinlovelace committed Sep 4, 2024
1 parent 3d6437f commit e3c1df1
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 0 deletions.
1 change: 1 addition & 0 deletions r/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.quarto/
23 changes: 23 additions & 0 deletions r/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Package: od2net
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R:
person("First", "Last", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph).
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Imports:
dplyr,
osmextract,
R.utils,
readr,
sf
Suggests:
simodels (>= 0.1.0)
Depends:
R (>= 2.10)
LazyData: true
URL: https://acteng.github.io/od2net/
2 changes: 2 additions & 0 deletions r/NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Generated by roxygen2: do not edit by hand

90 changes: 90 additions & 0 deletions r/R/setup.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Aim: generate input data for od2net with R

#' Generate a 'zones.geojson' file
#'
#' This function requires a zones file, e.g.
#' "https://raw.githubusercontent.com/nptscot/npt/main/data-raw/zones_edinburgh.geojson"
#' or a file on your computer.
#' It will generate a file in the input/ folder
#'
#' @param file Location or URL of zones file
make_zones = function(file) {
zones = sf::read_sf(file)[1]
names(zones)[1] = "name"
sf::write_sf(zones, "input/zones.geojson", delete_dsn = TRUE)
}

getbbox_from_zones = function() {
zones = sf::st_read("input/zones.geojson")
bbox = sf::st_bbox(zones)
paste0(bbox, collapse = ",")
}

make_osm = function(force_download = FALSE) {
zones = sf::read_sf("input/zones.geojson")
zones_union = sf::st_union(zones)
osmextract_match = osmextract::oe_match(place = zones_union)
osmextract::oe_download(file_url = osmextract_match$url, download_directory = "input", force_download = force_download)
input_pbf = list.files(path = "input", pattern = basename(osmextract_match$url), full.names = TRUE)
bb = getbbox_from_zones()
msg = paste0("osmium extract -b ", bb, " ", input_pbf, " -o input/input.osm.pbf --overwrite")
system(msg)
}

#' Get elevation data
#'
#' This function downloads elevation data from a source such as
#' https://play.abstreet.org/dev/data/input/shared/elevation/UK-dem-50m-4326.tif.gz
#' or https://assets.od2net.org/input/LisboaIST_10m_4326.tif
#'
#' @param url Full URL of the elevation dataset if available
#' @param file File name if hosted on a known site
#' @param base_url Base URL associated with the 'file' argument
#'
make_elevation = function(
url = NULL,
file = "UK-dem-50m-4326.tif.gz",
base_url = "https://play.abstreet.org/dev/data/input/shared/elevation/"
) {
if (is.null(url)) {
url = paste0(base_url, file)
}
is_gzip = grepl(pattern = "gz", url)
# Download the file
if (!file.exists("input/elevation.tif") && is_gzip) {
download.file(
url = url,
destfile = "input/elevation.tif.gz"
)
R.utils::gunzip("input/elevation.tif.gz", destname = "input/elevation.tif")
} else {
download.file(
url = url,
destfile = "input/elevation.tif"
)
}
}

make_origins = function() {
buildings = sf::read_sf("input/input.osm.pbf", query = "SELECT osm_id FROM multipolygons WHERE building IS NOT NULL")
use_sf = sf::sf_use_s2(FALSE)
centroids = sf::st_centroid(buildings)
sf::sf_use_s2(use_sf)
sf::write_sf(centroids, "input/buildings.geojson", delete_dsn = TRUE)
}

make_od = function() {
od = readr::read_csv("https://raw.githubusercontent.com/nptscot/npt/main/data-raw/od_subset.csv")
od = od |>
dplyr::transmute(from = geo_code1, to = geo_code2, count = bicycle)
readr::write_csv(od, "input/od.csv")
}

main = function() {
dir.create("input", showWarnings = FALSE)
make_zones()
make_osm()
# make_elevation()
make_origins()
make_od()
}
65 changes: 65 additions & 0 deletions r/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Preparing OD data for network generation with od2net


This R package provides functions to prepare OD data for network
generation with the `od2net` tool, as illustrated in the example below.

``` r
source("R/setup.R")
dir.create("input", showWarnings = FALSE)
make_zones("https://github.com/acteng/netgen/raw/main/input/zones_york.geojson")
make_osm()
make_origins()
make_elevation()
destinations = destinations_york # Provided in the R package
names(destinations)[1] = "name"
destinations = destinations[1]
class(destinations$name) = "character"
sf::write_sf(destinations, "https://github.com/acteng/netgen/raw/main/input/destinations.geojson", delete_dsn = TRUE)
# Save the OD dataset:
od = od_geo |>
sf::st_drop_geometry() |>
transmute(from = O, to = as.character(D), count = round(trips_modelled))
readr::write_csv(od, "input/od.csv", quote = "all")
```

Then create a config.json file, e.g. with the following content:

``` json
{
"requests": {
"description": "Test data for SchoolRoutes project.",
"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"
},
"cost": "Distance",
"uptake": "Identity",
"lts": "BikeOttawa",
"elevation_geotiff": "elevation.tif"
}
```

Then run the following code to generate the network:

Run the tool with Docker as follows:

``` bash
# On Linux:
sudo docker run -v $(pwd):/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json
# or in Windows:
sudo docker run -v ${pwd}:/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json
```

After that you should see the following in the output folder:

``` r
fs::dir_tree("output")
```
84 changes: 84 additions & 0 deletions r/README.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Preparing OD data for network generation with od2net
#| eval: false
#| echo: false
format: gfm
execute:
message: false
warning: false
---

This R package provides functions to prepare OD data for network generation with the `od2net` tool, as illustrated in the example below.


```{r}
#| eval: false
source("R/setup.R")
dir.create("input", showWarnings = FALSE)
make_zones("https://github.com/acteng/netgen/raw/main/input/zones_york.geojson")
make_osm()
make_origins()
make_elevation()
destinations = destinations_york # Provided in the R package
names(destinations)[1] = "name"
destinations = destinations[1]
class(destinations$name) = "character"
sf::write_sf(destinations, "https://github.com/acteng/netgen/raw/main/input/destinations.geojson", delete_dsn = TRUE)
# Save the OD dataset:
od = od_geo |>
sf::st_drop_geometry() |>
transmute(from = O, to = as.character(D), count = round(trips_modelled))
readr::write_csv(od, "input/od.csv", quote = "all")
```

Then create a config.json file, e.g. with the following content:

```json
{
"requests": {
"description": "Test data for SchoolRoutes project.",
"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"
},
"cost": "Distance",
"uptake": "Identity",
"lts": "BikeOttawa",
"elevation_geotiff": "elevation.tif"
}
```

Then run the following code to generate the network:

Run the tool with Docker as follows:


```{bash}
#| eval: false
# On Linux:
sudo docker run -v $(pwd):/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json
# or in Windows:
sudo docker run -v ${pwd}:/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json
```

```{r}
#| eval: false
#| echo: false
system("docker run -v $(pwd):/app ghcr.io/urban-analytics-technology-platform/od2net:main /app/config.json")
```

After that you should see the following in the output folder:

```{r}
#| eval: false
fs::dir_tree("output")
```


24 changes: 24 additions & 0 deletions r/man/make_elevation.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions r/man/make_zones.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e3c1df1

Please sign in to comment.