Robinlovelace / openTransportDataDemo

10 stars 2 forks source link

dangerous Streets? #1

Open emantzo opened 3 years ago

emantzo commented 3 years ago

Hello and thank you for the insightful tools. I am not quite familiar with mapping tools in R, and I hope my question is short and relevant. Is there an easy way to group accidents by street, or otherwise extract the info on street name by accident? I would like to investigate which road sections are particularly dangerous.

Many thanks!

Robinlovelace commented 3 years ago

Yes, you can do this. You need to do a geographic join between the streets in the OSM data and the crashes. See ?sf::st_join for details and let us know how you get on!

emantzo commented 3 years ago

Thank you for your reply!

I have finally managed to proceed with the code a bit (using code from this and from related packages), and I am copying here, in case you have the time to have a look or in case anyone else might be trying a similar approach.

In the following part, I try to join crashes and osm roads, in Leeds. It seems that st_join will not work, so I am using st_nearest_feature


library(stats19)
library(ggmap)
library(dplyr)
library(tibble)
library(tidygeocoder)
library(sf)

pkgs = c(
  "pct",
  "osmextract",
  "tmap",
  "stplanr",
  "od"
)

lapply(pkgs, library, character.only = TRUE)[length(pkgs)]

tmap_mode("view")

## roads from osm

# leeds+buffer

leeds_point = tmaptools::geocode_OSM( "leeds")
c_m_coordiantes = rbind( leeds_point$coords,leeds_point$coords)
c_m_od = od::points_to_od(p = c_m_coordiantes, interzone_only = TRUE)
c_m_desire_line = od::odc_to_sf(c_m_od[-(1:2)])[1, ]
leeds_buffer = stplanr::geo_buffer(c_m_desire_line, dist = 5000)
qtm(leeds_buffer)

### osm roads

library(osmextract)
library(osmdata)

osm_lines = oe_get(leeds_buffer, stringsAsFactors = FALSE, quiet = TRUE)

## crash data
crashes = get_stats19(year = 2019, output_format = "sf", lonlat = TRUE)
casualties = get_stats19(year = 2019, type = "casualties")
crashes_combined = inner_join(crashes, casualties)
# table(crashes_combined$casualty_type)
crashes_active = crashes_combined 

crashes_in_area = crashes_active[leeds_buffer, ]

tm_shape(crashes_in_area) +
  tm_dots("accident_severity", popup.vars = c("casualty_type", "accident_severity", "datetime"), palette = "viridis")

cras_samp=crashes_in_area

points.sf <- st_as_sf(cras_samp, coords = c("longitude","latitude"),crs=4326)

## match crashes to osm roads
cras_samp$road=st_nearest_feature(points.sf$geometry,osm_lines)

dist = st_distance(points.sf$geometry,osm_lines[cras_samp$road,], by_element=TRUE)

## using st_join... not working??
dist2=st_join(st_sf(points.sf),osm_lines)

In addition, I tried to join crashes with od routes, in a similar manner (to find out whether more crashes are related to more road usage), and I am not sure if it is ok.

### od data

# get nationwide OD data
od_all <- pct::get_od("west-yorkshire")

centroids_all <- pct::get_centroids_ew() %>% sf::st_transform(4326)

leeds <- pct::pct_regions %>% filter(region_name == "west-yorkshire")
centroids_leeds <- centroids_all[leeds, ]
od_leeds <- od_all %>%
  filter(geo_code1 %in% centroids_leeds$msoa11cd) %>%
  filter(geo_code2 %in% centroids_leeds$msoa11cd)

###

desire_lines <- od2line(od_leeds, centroids_leeds)

desire_lines$distance = as.numeric(st_length(desire_lines))
desire_carshort = dplyr::filter(desire_lines, car_driver > 300 & distance < 5000)

# make routes from od
route_carshort = route(l = desire_carshort, route_fun = route_osrm)

## join routes- osm
route_osm=st_join(route_carshort, osm_lines)

## correct??
## join routes- crash
cras_samp$road2=st_nearest_feature(points.sf$geometry, route_osm)

Many thanks for your time!!

Robinlovelace commented 3 years ago

Hi @emantzo I'm sorry but just got back from holidays and lots of other things going on. Looks like you have made great progress, will try to pick up on this at some point. A cursory glance suggests that you're in the right ballpark, interested to see what the results look like.