The abstr
package was originally developed as part of the ActDev project, which involved the development of a prototype web application that provides evidence on active travel provision and potential in and around planned and proposed development sites, as outlined in a paper describing the tool. The ActDev website demonstrates the potential for new developments to support walking and cycling by visualising data generated using reproducible R code. A key challenge was to create a simulation for each of the case study sites based on the input origin-destination datasets. To overcome this challenge, A/B Street developers were commissioned to extend the ActDev tool to enable real time simulation of scenarios of change. At the time there was no way to get the OD data we had in the R world into the A/B Street world. This was motivation for creating the abstr
R package. As outlined in the package’s README, the package’s main job is to take origin-destination data from .csv
files (and other tabular file types) and outputs .json
files that can be imported and visualised in A/B Street.
Given you have all of the above, you are ready to start transforming data-frames into simulations! So lets set an aim for the vignette
####
####
#### AIM: Use PCT data to create scenario of change where commuting cycling levels increase and car journeys decrease which can be imported
#### into A/B Street city simulation software. This method should be fully reproducible for all other pct_regions.
####
####
While the PCT is a powerful and popular tool for strategic cycleway planning it has some key limitations that are addressed by A/B Street:
This vignette aims to demonstrate how data from the PCT, which provides evidence-based visions of how cycling could become the natural choice for urban travel, can be visualised in A/B Street to overcome the limitations outlined above. The first stage is to install the necessary packages (see the abstr
vignette for a detailed introduction to software requirements).
To begin with, you need to install and load the necessary packages for this vignette.
#### INSTALL PACKAGES ####
= c("abstr", "pct", "osmextract", "sf", "tidyverse")
cran_pkgs ::install_cran(cran_pkgs)
remotes#### LOAD PACKAGES ####
library(abstr)
library(pct)
library(osmextract)
library(sf)
library(dplyr)
Data in the PCT for England and Wales is divided into regions, which can be seen below.
$region_name pct_regions
To run the example below, replace devon
with a different region from the list above (warning, this may not work for large regions).
= "devon" region_name
You can select a specific local authority of interest from those available in the region of interest. You can check which are available in your region of interest as follows:
= pct::pct_regions_lookup
lookup table(lookup$lad16nm[lookup$region_name == region_name])
For the purposes of this article we will use Exeter as the case study:
= "Exeter" lad_name
Next you want to fetch two types of PCT data. Firstly, zone data, which is gathered using the get_pct_zones()
function and is filtered to only include a local authority of choice, in this example we use Exeter. Secondly, commute data, which is gathered using the get_pct_lines()
function and is also filtered to only include trips within the local authority.
#### READ DATA ####
= get_pct_zones(region = region_name, geography = "msoa") # get zone data
devon_zones # filter for exeter
= devon_zones %>% filter(lad_name == lad_name) %>%
exeter_zones select(geo_code)
# get commute od data
= get_pct_lines(region = region_name, geography = "msoa") %>%
exeter_commute_od filter(lad_name1 == lad_name & lad_name2 == lad_name) # filter for exeter
Now you have your data, its time to clean and transform it. In fact, you only need to transform the exeter_commute_od
dataframe as the exeter_zones
is already in abstr
format. The first step in cleaning the data requires renaming variables so that we can clearly see the difference between the base scenario and the scenario of change. Next, you calculate the scenario of change, in this example we use the uptake_pct_godutch_2020()
function which takes two arguments of distance
and gradient
in its model calculation. The results from this PCT function allow you to calculate the mode shift from driving to cycling. Finally, we subset the data to only include the columns which are needed to progress.
= exeter_commute_od %>%
exeter_commute_od mutate(cycle_base = bicycle) %>%
mutate(walk_base = foot) %>%
mutate(transit_base = bus + train_tube) %>% # bunch of renaming -_-
mutate(drive_base = car_driver + car_passenger + motorbike + taxi_other) %>%
mutate(all_base = all) %>%
mutate(
# create new columns
pcycle_godutch_uptake = uptake_pct_godutch_2020(distance = rf_dist_km, gradient = rf_avslope_perc),
cycle_godutch_additional = pcycle_godutch_uptake * drive_base,
cycle_godutch = cycle_base + cycle_godutch_additional,
pcycle_godutch = cycle_godutch / all_base,
drive__godutch = drive_base - cycle_godutch_additional,
across(c(drive__godutch, cycle_godutch), round, 0),
all_go_dutch = drive__godutch + cycle_godutch + transit_base + walk_base
%>%
) select(
# select variables for new df
geo_code1,
geo_code2,
cycle_base,
drive_base,
walk_base,
transit_base,
all_base,
all_go_dutch,
drive__godutch,
cycle_godutch,
cycle_godutch_additional,
pcycle_godutch )
As a quick sanity check we can make sure our model has not generated any new commutes and we still have the same base number of commuters as before.
# sanity check: ensure total remains the same
# (this is not a dynamic model where population change is factored in)
identical(exeter_commute_od$all_base, exeter_commute_od$all_go_dutch)
Now, you need to download OSM building data to populate the AB Street simulation map. In this example we use the osmextract
package to fetch a PBF (protocolbuffer binary format) file hosted on GeoFabrik. You then need to filter the contents of the PBF file to only include the defined building types and subset the data to only include osm_way_id, name, building
columns. Following this, you should ensure you only include valid sf buildings and then aggregate the building data against the zone boundary.
#### DOWNLOAD OSM BUILDING DATA ####
= osmextract::oe_read(
osm_polygons "https://download.geofabrik.de/europe/great-britain/england/devon-latest.osm.pbf",
# download osm buildings for region using geofabrik
layer = "multipolygons"
)
= c(
building_types "yes",
"house",
"detached",
"residential",
"apartments",
"commercial",
"retail",
"school",
"industrial",
"semidetached_house",
"church",
"hangar",
"mobile_home",
"warehouse",
"office",
"college",
"university",
"public",
"garages",
"cabin",
"hospital",
"dormitory",
"hotel",
"service",
"parking",
"manufactured",
"civic",
"farm",
"manufacturing",
"floating_home",
"government",
"bungalow",
"transportation",
"motel",
"manufacture",
"kindergarten",
"house_boat",
"sports_centre"
)= osm_polygons %>%
osm_buildings filter(building %in% building_types) %>%
select(osm_way_id, name, building)
= osm_buildings[sf::st_is_valid(osm_buildings), ]
osm_buildings_valid
= osm_buildings_valid[exeter_zones, ] exeter_osm_buildings_all
Subsequently, you can join the OSM buildings data with the exeter_zones
geography in order to create the complete building table. This table is filtered to not include any NA's
and is aggregated to only include
#### JOIN OSM BUILDINGS WITH ZONE DATA ####
= exeter_osm_buildings_all %>%
exeter_osm_buildings_all_joined ::st_join(exeter_zones)
sf
= exeter_osm_buildings_all_joined %>%
exeter_osm_buildings_sample filter(!is.na(osm_way_id))
= exeter_osm_buildings_all %>%
exeter_osm_buildings_tbl filter(osm_way_id %in% exeter_osm_buildings_sample$osm_way_id)
You now have everything in place to generate AB Street scenarios for both our base commute rate and our go_active commute rate. However, abstr
takes a strict column name definition as to adhere to the AB street documentation. This means you need to rename mode columns for scenario generation. In order to make things easy, we can create a simple logic gate that renames our mode columns depending on the boolean value go_active
.
set.seed(2021) # for reproducible builds
#### LOGIC GATE ####
# Logic gate for go_dutch scenario of change, where cycling levels increase to a proportion reflecting the Netherlands.
# Switch to FALSE if you want census commuting OD
= TRUE
go_dutch if (go_dutch == TRUE) {
= exeter_commute_od %>%
exeter_od mutate(All = all_go_dutch) %>%
mutate(Bike = cycle_godutch) %>%
mutate(Transit = transit_base) %>%
mutate(Drive = drive_base) %>%
mutate(Walk = walk_base) %>%
select(geo_code1, geo_code2, All, Bike, Transit, Drive, Walk,geometry)
else {
} = exeter_commute_od %>%
exeter_od mutate(All = all_base) %>%
mutate(Bike = cycle_base) %>%
mutate(Drive = drive_base) %>%
mutate(Transit = transit_base) %>%
mutate(Walk = walk_base) %>%
select(geo_code1, geo_code2, All, Bike, Transit, Drive, Walk, geometry)
}
Voila, you are ready to generate simulation files from your data-frames. Lets start by using the ab_scenario()
function with our exeter_od
, exeter_zones
and exeter_osm_buildings_tbl
data-frames.
#### GENERATE A/B STREET SCENARIO ####
= ab_scenario(
output_sf od = exeter_od,
zones = exeter_zones,
zones_d = NULL,
origin_buildings = exeter_osm_buildings_tbl,
destination_buildings = exeter_osm_buildings_tbl,
pop_var = 3,
time_fun = ab_time_normal,
output = "sf",
modes = c("Walk", "Bike", "Drive", "Transit")
)
To conclude you will need to generate a JSON
format using the ab_json()
function and then save the json file to your local machine using the ab_save()
function. (You can download this file from the repo’s releases.)
#### SAVE JSON FILE ####
= ab_json(output_sf, time_fun = ab_time_normal, scenario_name = "Go Dutch")
output_json ab_save(output_json, f = "dutch.json")
# Upload the json file for future reference
::pb_upload("dutch.json")
piggyback::pb_download_url("dutch.json") piggyback
Now that you’ve generated a scenario, you can simulate it. First install the latest build of A/B Street for your platform. Run the software, and choose “Sandbox” on the title screen.
You can then change the default map to other cities across the world. A/B Street contains over 40 sites in England from the ActDev project. If the local authority you have generated a scenario for is not included, you can also import a new city from the user interface.
After loading the correct map, change the traffic scenario from the default “weekday” or “none” pattern. Choose “import JSON scenario,” then select your dutch
file.
After selecting your scenario, you should see something like this, a Go Dutch scenario of cycling taking place before your eyes, making the OD data frames come to life in a real time simulation!