vignettes/im_get.Rmd
im_get.Rmd
The purpose of the inclusive_mobility_get
function is to
recategorize OSM data based on the recent Inclusive Mobility (IM) guide
UK. The goal behind this is to encourage the use of crowd-sourced open
data in the inclusive infrastructure planning. Indeed, the function has
been written to encourage discussions around the applicability of open
data and act as a starting point.
It has to be noted that this function is a simplification of all the
requirements outlined in the guide. There are a couple of reasons for
this. First, while there is a large number of tags in OSM to create
detailed maps, but the values imputed are not always IM guide-friendly.
For example, in the guide 6 different types of tactile paving are
outlined, yet those types are not key values in the OSM as it focused on
the presence/absence of tactile paving. This, then, leads not only to
the fact that not all OSM data can be sensibly recategorized based on
the IM guide but also that it is highly unlikely that a single function
could capture the detailed specifications outlined in the IM guide.
Please note that, as per #129, the
oi_inclusive_mobility
function, based on the function
defined below, has now been split into a number of sub-functions as
described below:
New Function | Assesses |
---|---|
oi_im_flush_kerb | Flush Kerb |
oi_im_pavement_width |
Pavement
Width Estimated Width |
oi_im_pedestrian_infra |
Footways
Footpaths Implied Footways Crossings |
oi_im_surfaces |
Paved
Surface Even Surface |
oi_im_tactile_paving | Tactile Pacing |
oi_is_lit | Lighting |
oi_clean_maxspeed_uk | Speed |
For further information, please see documentation
for the functions starting oi_im_*
# region_wy = "West Yorkshire"
# tags_needed = c("cycleway",
# "bicycle",
# "wheelchair",
# "kerb",
# "disabled",
# "mobility_scooter",
# "handicap",
# "foot",
# "lit",
# "access",
# "sidewalk",
# "footway",
# "incline",
# "smoothness",
# "est_width",
# "width",
# "ramp",
# "sidewalk_left",
# "sidewalk_right",
# "ramp_wheelchair",
# "footway_left",
# "footway_right",
# "footway_surface",
# "priority",
# "sidewalk_both_surface",
# "sidewalk_both_width",
# "path",
# "pedestrian",
# "sidewalk_left_width",
# "sidewalk_right_width",
# "sidewalk_right_surface",
# "sidewalk_left_surface",
# "maxspeed",
# "segregated",
# "sloped_curb",
# "surface",
# "tactile_paving",
# "crossing"
# )
# wy_lines = osmextract::oe_get(
# place = region_wy,
# force_download = TRUE,
# force_vectortranslate = TRUE,
# extra_tags = tags_needed
# )
# saveRDS(wy_lines,
# "wy_lines_21-03-2022.RDS")
wy_lines = readRDS(url("https://github.com/udsleeds/openinfra/releases/download/v0.1/wy_lines_21-03-2022.RDS"))
# wy_points = osmextract::oe_get(
# place = region_wy,
# layer = "points",
# force_download = TRUE,
# force_vectortranslate = TRUE,
# extra_tags = tags_needed
# )
# saveRDS(wy_points,
# "wy_points_21-03-2022.RDS")
wy_points = readRDS(url("https://github.com/udsleeds/openinfra/releases/download/v0.1/wy_points_21-03-2022.RDS"))
# osm_query = "SELECT * FROM 'lines', 'points'"
#
# wy_points_lanes = osmextract::oe_get(
# place = region_wy,
# force_download = TRUE,
# force_vectortranslate = TRUE,
# extra_tags = tags_needed,
# query = osm_query
# )
# join points and lines into one df
# homogenizing columns
# names_lines = wy_lines %>% names
# names_points = wy_points %>% names
# setdiff(names_lines, names_points)
# setdiff(names_points, names_lines)
wy_lines_short = wy_lines %>% select(-c("waterway", "aerialway", "z_order"))
wy_points_short = wy_points %>% select(-c("ref", "address", "is_in", "place"))
wy_joined = rbind(wy_lines_short, wy_points_short)
There are two requirements for a function:
sf
(simple features) object. It can
easily be obtained using osmextract
packageThe following tags are used: highway, kerb, footway, path, cycleway, sidewalk, foot, segregated, access, crossing, lit, maxspeed, tactile_paving, surface, width, est_width.
To learn how to get extra tags, see lines 20-94 of this notebook or this vignette.
Finally, it is important to highlight what this function does not do:
osmextract
to
download a pre-defined waking or cycling network
inclusive_mobility_get = function(osm_sf) {
osm_sf_im = osm_sf %>%
# kerb: flush or not
dplyr::mutate(im_kerb = dplyr::if_else(kerb == "flush" | kerb == "no", "flush", "other")) %>%
# footway is a ‘pavement’ adjacent to a road
dplyr::mutate(im_footway = dplyr::case_when(
footway %in% c("left", "right", "both", "sidewalk") |
sidewalk %in% c("left", "right", "both", "yes", "separate") |
# trying to capture footways shared with cyclists
!is.na(cycleway) & # map cycling infrastructure that is an inherent part of the road
foot %in% c("yes", "designated") |
segregated %in% "yes"
~ "yes",
TRUE ~ "no"
)
) %>%
# footpath is any other right of way for pedestrians, that does not run adjacent to a road.
dplyr::mutate(im_footpath = dplyr::case_when(
highway %in% "footway" &
im_footway %in% "no" |
# not (always) an inherent part of the road
highway %in% c("cycleway", "bridleway", "path") & # foot = "designated" is implied
im_footway %in% "no" &
! foot %in% c("no", "private") |
! access %in% c("no", "private") &
segregated %in% "no" # shared space
~ "yes",
TRUE ~ "no"
)
) %>%
# presence of a crossing: give-way, signal controlled, none, or yes (but the type is unknown)
dplyr::mutate(im_crossing = dplyr::case_when(
stringr::str_detect(crossing, "zebra|uncontr|marked")~ "give-way",
stringr::str_detect(crossing, "toucan|pedex|puffin|equestrian|light|signal")~ "signal-controlled",
highway %in% "crossing" | footway %in% "crossing" | !is.na(crossing) ~ "yes",
TRUE ~ "no"
)) %>%
# implied footways but there's a lack of data to verify
dplyr::mutate(im_footway_imp = dplyr::case_when(
im_footway %in% "no" &
im_footpath %in% "no" &
im_crossing %in% "no"
~ "yes",
TRUE ~ "no"
)
) %>%
# lighting: yes or no
dplyr::mutate(im_light = dplyr::case_when(
# highway %in% "street_lamp" |
! lit %in% c("no", "disused") & ! is.na(lit)
~ "yes",
TRUE ~ "no"
)
) %>%
# recategorize speed
dplyr::mutate(im_maxspeed = maxspeed %>%
parse_number(),
im_maxspeed = dplyr::case_when(
im_maxspeed > 1 & im_maxspeed <= 20 ~ "1-20", # up to 20 mph
im_maxspeed > 20 & im_maxspeed <= 40 ~ "21-40", # 21 - 40 mph
im_maxspeed > 40 & im_maxspeed <= 60 ~ "41-60", # 41 - 60 mph
im_maxspeed > 60 ~ "61" # over 60 mph
)
) %>%
# tactile paving: yes, no
dplyr::mutate(im_tactile = dplyr::case_when(
! tactile_paving %in% c("no", "incorrect", "bad") & ! is.na(tactile_paving)
~ "yes",
! is.na(tactile_paving)
~ "no"
)
) %>%
# surface: paved, unpaved, or other
dplyr::mutate(
im_surface_paved = dplyr::case_when(
highway %in% "cycleway"
~ "paved",
stringr::str_detect(surface,
"pav|asph|chipseal|concrete|paving|sett|cobble|metal|wood|stepping")
~ "paved",
highway %in% c("footway", "bridleway") & # highway = footway implied surface value is unpaved
! surface %in% stringr::str_detect(surface, "pav|asph|chipseal|concrete|paving|sett|cobble|metal|wood|stepping")
~ "unpaved",
stringr::str_detect(surface, "unpav|compact|gravel|rock|pebble|ground|dirt|grass|mud|sand|woodchips|snow|ice|salt")
~ "unpaved",
TRUE & !is.na(surface) ~ "other"
)
) %>%
# surface: even or not
dplyr::mutate(im_surface = dplyr::case_when(
stringr::str_detect(surface, "asph|concrete")
~ "even",
im_surface_paved %in% "paved" &
smoothness %in% c("excellent", "good")
~ "even",
! is.na(im_surface_paved)
~ "uneven"
)
) %>%
# width: under 1.5 meters, 1.5-2 meters, or over 2 meters
dplyr::mutate(
im_width = width %>%
parse_number(),
im_width = case_when(
im_width > 0 & im_width < 1.5 ~ " 1.5",
im_width <= 1.5 & im_width <= 2 ~ "1.5 - 2",
im_width > 2 ~ "2"
)
) %>%
# estimated width: under 1.5 meters, 1.5-2 meters, or over 2 meters
dplyr::mutate(
im_width_est = est_width %>%
parse_number(),
im_width_est = case_when(
im_width_est > 0 & im_width_est < 1.5 ~ " 1.5",
im_width_est <= 1.5 & im_width_est <= 2 ~ "1.5 - 2",
im_width_est > 2 ~ "2"
)
)
}
Inclusive mobility: pavements adjacent to roads
OSM:
Hence, it can be assumed key:footway and key:sidewalk are associated with the footways going adjacent to the road. Also, given that key:cycleway is supposed to be an inherent part of the road, then it should go adjacent to the road, which implies that if one can wheel/walk on it, then it’s a footway too. Moreover, key:segregated might be used instead of sidewalk tag for shared spaces.
Inclusive Mobility:
OSM:
So, footpaths should be all the paths that are not footways.
Sidewalk can be considered a negative tag because it is implied that roads have sidewalks. Yet, given that it is not explicitly mapped so, there is an assumption that might not always be correct. For this reason, a separate column was created to account for that and indicate which highways might have sidewalks but the user, in the end, can make a decision based on the need.
Inclusive Mobility:
OSM:
OSM allows to specify the type of a crossing, yet the three approved tags are traffic_lights, uncontrolled, or none. Given this, OSM was recategorized based on the broad categorization of crossings in the IM guide. If the type of a crossing is unknown but it’s mapped as present, “yes” value was used, if it is explicitly known that there is no crossing, then “no” value is present.
Inclusive Mobility:
OSM:
So, OSM does not seem to support the categorization of tactile paving as outlines in the IM guide. For this reason simplified approach was taken in which only the presence or absence of tactile paving is determined.
Inclusive Mobility:
OSM:
So, it is hard to determine if a given surface matches the requirements of IM guide, especially if it’s slip-resistant. For this reason, a simple recategorization was used to only indicate if the surface is even. A basic assumption is that all surfaces, except asphalt and concrete, are not unless they have an excellent or good smoothness level tagged.
Inclusive Mobolity:
OSM:
So, OSM does not seem to provide an ability to tag illumination levels. Given that, a simple present/absent recategorization has been done. To account for potential overlaps between different tagging schemes, only key:lit has been used. However, for a more in-depth examination of lighting, both approaches should, ideally, be taken into consideration.
Note: if you want to include highway=street_lamp
in your
analysis, you will have to download point data by specifying this in the
query before downloading the data.
Inclusive Mobility:
OSM:
So, the speed was categorized into 4 groups: 1 to 20, 21 to 40, and 41 to 60, and over 60 mph. The main focus here might be on the roads with up to 20 mph speed limit as it has a positive effect on increasing active modes of travel.
Inclusive Mobility:
OSM:
So, while there is an implication in OSM tagging scheme that kerbs of ~ 3cm height are wheelchair-friendly, it is not a case in the IM guide. Therefore, only kerbs having values of ‘flush’ or ‘no’ have been categorized as “flush”.
Inclusive Mobility:
OSM:
So, the function recategorizes OSM data into 3 groups: width under 1.5 m, between 1.5 and 2m, and above 2 meters. The same is done for the key:est_width. It’s important to note that two new columns are returned – one for the estimated and another for the actual width. Finally, because of OSM tagging scheme, it is not always easy to differentiate (unless it is explicitly tagged) if the width refers to the carriageway, sidewalk, or include both. The function here does not provide this differentiation either, thus bear in mind that this column might be misleading. To avoid this, it is recommended to process the data further so only sidewalks and/or footways remain in the dataset as much as it is possible given the limitations of OSM.
think about: