An exploratory analysis of the response times of ambulances in the Distrito Nacional, Dominican Republic.
This document offers the instructions to process, analyse and visualise data to examine the response times of the Emergency Medical Services (EMS) in a area of the capital of the Dominican Republic: the Distrito Nacional.
The data is stored in an online github repository: https://github.com/francicabrera/GISassessment To run this code you must clone the repository to your local machine.
#install.packages("mapboxapi", dependencies = TRUE)
library(mapboxapi)
library(here)
library(maptools)
library(sf)
library(tmap)
library(ggplot2)
library(plotly)
library(tidyverse)
library(grid)
library(data.table)
library(ggspatial)
library(ggsn)
provinces <- st_read(here("Data","geo","ShapeFilesCenso2010",
"PROVCenso2010.shp")) %>%
# Project to EPSG:32619. This is the projected coordinate system for the Dominican Republic.
st_transform(.,32619)
## Reading layer `PROVCenso2010' from data source `/Users/francinacabrera/OneDrive - University College London/CASA/MODULES/GIS/GISassessment/Data/geo/ShapeFilesCenso2010/PROVCenso2010.shp' using driver `ESRI Shapefile'
## Simple feature collection with 32 features and 4 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: 182215.8 ymin: 1933512 xmax: 571429.3 ymax: 2205216
## projected CRS: WGS 84 / UTM zone 19N
# Distrito Nacional shapefile
DistritoNacional <- provinces %>%
# Filter by the Distrito Nacional (DN)
filter(., TOPONIMIA=="DISTRITO NACIONAL")
# Quick look of the feature
qtm(DistritoNacional)
# Borough shapefile
boroughs <- st_read(here("Data","geo","ShapeFilesCenso2010",
"POBL_NACIONAL_BP.shp")) %>%
# Project to EPSG:32619.
st_transform(.,32619) %>%
#filter by the Distrito Nacional (DN)
filter(., PROV=="01")
## Reading layer `POBL_NACIONAL_BP' from data source `/Users/francinacabrera/OneDrive - University College London/CASA/MODULES/GIS/GISassessment/Data/geo/ShapeFilesCenso2010/POBL_NACIONAL_BP.shp' using driver `ESRI Shapefile'
## Simple feature collection with 12565 features and 14 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: 182215.8 ymin: 1933512 xmax: 571429.3 ymax: 2205216
## projected CRS: WGS 84 / UTM zone 19N
# Quick look of the feature
qtm(boroughs)
# Subboroughs of DN shapefile
subboroDN <- st_read(here("Data","geo","ShapeFilesCenso2010",
"SUBBARRIOS_DN.shp")) %>%
# Project to EPSG:32619
st_transform(.,32619)
## Reading layer `SUBBARRIOS_DN' from data source `/Users/francinacabrera/OneDrive - University College London/CASA/MODULES/GIS/GISassessment/Data/geo/ShapeFilesCenso2010/SUBBARRIOS_DN.shp' using driver `ESRI Shapefile'
## Simple feature collection with 274 features and 17 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: -7792284 ymin: 2087089 xmax: -7778408 ymax: 2101744
## projected CRS: WGS 84 / Pseudo-Mercator
# Quick look of the feature
qtm(subboroDN)
# Response Emergency Zones
RespZones <- st_read(here("Data","geo","ResponseZones",
"SALUD_DN.shp"))%>%
# Project to EPSG:32619
st_transform(.,32619)
## Reading layer `SALUD_DN' from data source `/Users/francinacabrera/OneDrive - University College London/CASA/MODULES/GIS/GISassessment/Data/geo/ResponseZones/SALUD_DN.shp' using driver `ESRI Shapefile'
## Simple feature collection with 2 features and 12 fields
## geometry type: POLYGON
## dimension: XY
## bbox: xmin: -7794521 ymin: 2085956 xmax: -7778408 ymax: 2101744
## projected CRS: WGS 84 / Pseudo-Mercator
# Quick look of the feature
qtm(RespZones)
# As we are going to work we an specific Response Zone, let's create the sf that will be used later
ZoneSA1 <- RespZones %>%
dplyr::filter(str_detect(ZONA, "S-A1"))%>%
# Project to EPSG:32619
st_transform(., 32619)
# Roads shapefile
# We will use this only for visualisation
roads <- st_read(here("Data","geo","roads_OSM",
"gis_osm_roads_free_1.shp")) %>%
# Project to EPSG:32619
st_transform(.,32619)
## Reading layer `gis_osm_roads_free_1' from data source `/Users/francinacabrera/OneDrive - University College London/CASA/MODULES/GIS/GISassessment/Data/geo/roads_OSM/gis_osm_roads_free_1.shp' using driver `ESRI Shapefile'
## Simple feature collection with 234628 features and 10 fields
## geometry type: LINESTRING
## dimension: XY
## bbox: xmin: -74.47969 ymin: 17.73146 xmax: -68.3239 ymax: 20.08665
## geographic CRS: WGS 84
# Clip Roads data to provinces
#This can take a while.
RoadsProv <- roads[provinces,]
# Clip Roads data to DN
RoadsDN <- roads[DistritoNacional,]
#Clip Roads to S-A1
RoadsA1 <- roads[ZoneSA1,]
# Emergency units allocations
# Read data from csv
EmerUnits<- read.csv("Data/Units.csv",
header = TRUE,
encoding = "latin1") %>%
# Create sf with Emergency Units allocations
st_as_sf(., coords = c("Long", "Lat"),
crs = 4326) %>%
# Project to EPSG:32619
st_transform(., 32619)
# Clip the sf data to DN
EmerUnitsDN <- EmerUnits[DistritoNacional,]
# Clip the sf data to S-A1
EmerUnitsSA1 <- EmerUnits[ZoneSA1,]
# 911 Cases from August 2019
# Read data from csv
Cases <- read.csv("Data/Cases.csv",
header = TRUE,
encoding = "latin1")
#Check the data
summary(Cases)
## longitude latitude primary_unitid zone
## Min. :-71.78 Min. :-21.75 Length:30718 Length:30718
## 1st Qu.:-69.98 1st Qu.: 18.47 Class :character Class :character
## Median :-69.90 Median : 18.49 Mode :character Mode :character
## Mean :-69.80 Mean : 18.50
## 3rd Qu.:-69.82 3rd Qu.: 18.53
## Max. :-14.75 Max. : 19.78
## NA's :38 NA's :38
## dispatch_date_to_onscene_date_mins
## Min. : 0.00
## 1st Qu.: 9.70
## Median :14.90
## Mean :17.12
## 3rd Qu.:22.50
## Max. :59.90
## NA's :13272
# Drop nas in longitude and latitude fields
Cases <- Cases %>%
drop_na(longitude, latitude, dispatch_date_to_onscene_date_mins) %>%
# Remove any duplicate cases.
distinct(., primary_unitid, zone, longitude, latitude, dispatch_date_to_onscene_date_mins)
summary(Cases)
## longitude latitude primary_unitid zone
## Min. :-70.83 Min. :-21.75 Length:17398 Length:17398
## 1st Qu.:-69.98 1st Qu.: 18.47 Class :character Class :character
## Median :-69.90 Median : 18.50 Mode :character Mode :character
## Mean :-69.80 Mean : 18.50
## 3rd Qu.:-69.83 3rd Qu.: 18.53
## Max. :-14.75 Max. : 19.75
## dispatch_date_to_onscene_date_mins
## Min. : 0.00
## 1st Qu.: 9.70
## Median :14.90
## Mean :17.13
## 3rd Qu.:22.50
## Max. :59.90
Add a column with the range of the response times.
#Response Times Range
Cases$RTrange <- cut(Cases$dispatch_date_to_onscene_date_mins,5,include.lowest=TRUE)
# Create sf with all Cases data
CasesAll <- Cases %>%
st_as_sf(., coords = c("longitude", "latitude"),
crs = 4326) %>%
# Project to EPSG:32619
st_transform(., 32619)
#Clip cases data to DN.
CasesDN <- CasesAll[DistritoNacional,]
#Clip cases data to S-A1.
CasesA1 <- CasesAll[ZoneSA1,]
Join the cases data with boroughs and subboroughs
#Boroughs
boro_CasesDN <- boroughs %>%
st_join(CasesAll) %>%
group_by(., TOPONIMIA) %>%
#add a count column to have the number of cases per borough
count(count=n())
#Subboroughs
subboro_CasesDN <- subboroDN %>%
st_join(CasesAll)
#Subboroughs
subboro_CasesDN2 <- subboro_CasesDN %>%
group_by(., COD_ONE) %>%
#add a count column to have the number of cases per subborough
count(count=n())
We will need to obtain the cases with RT over 10 minutes.
CasesHRT <- CasesDN %>%
filter(dispatch_date_to_onscene_date_mins > 10.0)
#Clip cases data to DN.
CasesHRTDN <- CasesHRT[DistritoNacional,]
#Clip cases data to S-A1.
CasesHRTA1 <- CasesHRT[ZoneSA1,]
# Join cases with High RT to boroughs and subboroughs
#Boroughs
boro_CasesHRTDN <- boroughs %>%
st_join(CasesHRT) %>%
group_by(., CODIGO) %>%
#add a count column to have the number of cases per borough
count(count=n())
#Subboroughs
subboro_CasesHRTDN <- subboroDN %>%
st_join(CasesHRT)
Obtain the descriptive statistics for the population and cases. Use the data from the boroughs and cases.
# Population in Distrito Nacional
sum(boroughs$pobl) # Count
## [1] 965040
mean(boroughs$pobl) # Average
## [1] 13786.29
sd(boroughs$pobl) # Standard deviation
## [1] 12226.5
# Population in Zone S-A1
sum(boroughs[ZoneSA1,]$pobl) # Count
## [1] 683112
mean(boroughs[ZoneSA1,]$pobl) # Average
## [1] 15886.33
sd(boroughs[ZoneSA1,]$pobl) # Standard deviation
## [1] 12809.85
# Cases in Distrito Nacional
sum(boro_CasesDN$count) # Count
## [1] 4333
mean(boro_CasesDN$count) # Average
## [1] 61.9
sd(boro_CasesDN$count) # Standard deviation
## [1] 52.49849
# Cases with HRT in Distrito Nacional
sum(boro_CasesHRTDN$count) # Count
## [1] 3180
mean(boro_CasesHRTDN$count) # Average
## [1] 45.42857
sd(boro_CasesHRTDN$count) # Standard deviation
## [1] 38.618
Create a choropleth map with the ranges of RT by subborough (to obtain a more precise visualisation) to observe the distribution of the cases. Overlap the population counts by borough.
# Modify the subboroughs of the DN with the density for Response Times (RTs)
subboro_CasesDN<- subboro_CasesDN %>%
group_by(COD_ONE) %>%
summarise(density = first(RTrange),
SUBboro= first(NOM_SUB))
# Plot
Map1 <- tm_shape(RespZones) +
tm_polygons(col = NA,
alpha = 0.1,
border.col = "#8856a7",
lwd = 1.5)+
tm_shape(subboro_CasesDN) +
tm_polygons("density",
style="jenks",
palette="GnBu",
border.col = "white",
lwd=0.5,
midpoint=NA,
title="Response Times (minutes) \nper subborough",
legend.hist=TRUE,
legend.is.portrait=FALSE)+
tm_shape(boroughs) +
tm_bubbles("pobl",
"#8c96c6",
alpha = 0.7,
border.col = "white",
border.lwd=0.1,
size.lim = c(0, 60000),
breaks=c(-Inf, seq(0, 6, by=2), Inf),
title.size="Population per borough",
legend.size.is.portrait = FALSE) +
#Roads are used for visualisation purpose.
#It can take a while to run. Un-comment to plot it.
# tm_shape(RoadsProv)+
# tm_lines(lwd=0.1,
# palette = "Greys",
# legend.show = FALSE)+
tm_shape(boroughs)+
tm_polygons(col="white",
alpha = 0.1,
border.col = "#8c96c6",
lwd=1)+
tm_shape(RespZones) +
tm_polygons(col = "ZONA",
palette = "Greys",
alpha = 0.05,
border.col = "#8856a7",
lwd = 1.5,
title="Response Zones",
legend.is.portrait=FALSE)+
tm_text("ZONA",
col = "#8856a7") +
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_scale_bar(position=c("left", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363") +
tm_layout(inner.margin=c(0.1,0.04,0.04,0.04),
legend.outside=TRUE,
legend.outside.position = "right",
legend.text.size = 0.5,
legend.height = 0.5)
# Inset Map of the studied area
inset <- tm_shape(provinces) +
tm_polygons(col = "#cccccc",
border.col = "white",
lwd=0.5)+
tm_layout(frame=FALSE,
bg.color = "transparent")+
tm_shape(DistritoNacional) +
tm_polygons(col = "#8856a7") +
tm_text("TOPONIMIA",
col = "black",
xmod=0.8,
ymod=-0.5,
size = 0.32)
# This will save the map in the same path as the project.
tmap_save(Map1,
insets_tm = inset,
insets_vp=viewport(0.35, 0.22, width = 0.15, height = 0.15),
filename="Map1.png",
dpi=600)
print(Map1, insets_tm = inset, insets_vp=viewport(0.35, 0.22, width = 0.15, height = 0.15))
## Legend labels were too wide. Therefore, legend.text.size has been set to 0.32. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.
# Point Density Visualisation of Cases with High RTs
# Create new sf with CRS 4326 and X and Y variables for Cases in Zone S-A1
CasesHRTA1_pd <- CasesHRTA1 %>%
st_transform(4326) %>% # transform to same CRS
cbind(st_coordinates(.)) # get X and Y coordinates
# Create new sf with CRS 4326 and X and Y variables for Cases in Zone S-A1
EmerUnitsA1_pd <- EmerUnitsSA1 %>%
st_transform(4326) %>% # transform to same CRS
cbind(st_coordinates(.)) # get X and Y coordinates
# Plot
Map2 <- ggplot() +
geom_bin2d(data = CasesHRTA1_pd,
aes(X, Y),
binwidth = c(0.005, 0.005)) +
geom_sf(data = RoadsA1,
col="#636363",
size=0.07) +
theme_minimal() +
scale_fill_distiller(palette = "GnBu",
direction = 1,
name= "Count of cases with High RTs")+
theme(legend.position="bottom")+
labs(x="",
y="")+
geom_sf(data = EmerUnitsA1_pd,
col="#8856a7",
size=1,)+
geom_text(data = EmerUnitsA1_pd,
aes(X, Y, label = Ficha),
colour = "#404040",
size=3,
vjust = -1)+
annotation_scale(bar_cols=c("#f0f0f0","#636363"))+
north(data=CasesHRTA1_pd,
location= "bottomright",
symbol = 3)
Map2
# This will save the map in the same path as the project.
ggsave("Map2.png",
plot=Map2,
dpi = 600)
## Saving 7 x 5 in image
VIsualisation of cases by units assigned and not assigned to S-A1
# Change name of column 'primary_unitid' to 'Ficha'.
CasesHRTA1 <- CasesHRTA1 %>%
rename(Ficha="primary_unitid")
##Cases in A1
CasesinA1 <- CasesHRTA1 %>%
filter(Ficha %in% EmerUnitsSA1$Ficha) #filter by emergency units assigned to S-A1
#Subset cases not in A1
CasesNOTA1 <- subset(CasesHRTA1, !(Ficha %in% EmerUnitsSA1$Ficha)) #filter by emergency units not assigned to S-A1
# Plot
tmap_mode("plot")
## tmap mode set to plotting
Map3 <- tm_shape(RoadsA1) +
tm_lines(lwd=0.2) +
#Roads are used for visualisation purpose.
#It can take a while to run. Un-comment to plot it.
# tm_shape(RoadsProv %>% filter(fclass == "primary"|fclass == "residential")) +
# tm_lines(lwd=0.1) +
tm_shape(ZoneSA1)+
tm_fill(col = "white",
alpha = 0.3,
border.lwd = 0.2,
border.col = "#8856a7",
show.legend = FALSE)+
tm_shape(provinces) +
tm_polygons(col = "white",
border.lwd = 0.2,
border.col = "#737373",
alpha = 0.1)+
tm_text("TOPONIMIA",
col = "#737373",
size = 0.7) +
tm_shape(CasesinA1) +
tm_dots(col = "#a8ddb5")+
tm_add_legend(title="Emergency Cases > 10 mins",
type = "symbol",
labels = "Solved by emergency units from S-A1",
col = "#a8ddb5")+
tm_shape(CasesNOTA1) +
tm_dots(col = "#43a2ca",
size = 0.1)+
tm_add_legend(type = "symbol",
labels = "Solved by emergency units not from S-A1",
col = "#43a2ca")+
tm_shape(ZoneSA1) +
tm_polygons(col = "ZONA",
palette = "white",
border.lwd = 0.2,
border.col = "#8856a7",
alpha = 0.1,
title="Response Zone")+
tm_text("ZONA",
col = "#8856a7",
size = 0.9)+
tm_layout(outer.margins = 0,
panel.label.bg.color = 'white',
panel.label.size = 1.2,
legend.outside=TRUE,
legend.outside.position = "right",
title.snap.to.legend = T)+
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_scale_bar(position=c("left", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")
Map3
## Legend labels were too wide. The labels have been resized to 0.58. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.
## Legend labels were too wide. The labels have been resized to 0.53. Increase legend.width (argument of tm_layout) to make the legend wider and therefore the labels larger.
# Save the plot
tmap_save(Map3,
filename="Map3.png",
dpi=600)
To run this part of the analysis you must create an account on Mapbox and use your token: https://www.mapbox.com
This part of the analysis uses code from this source: https://npalomin.github.io/CASA_seminar_2020/casa0005_seminar1.html
Check also the Mapbox documentation for more information: https://docs.mapbox.com/api/navigation/isochrone/
my_token <- my_token
# Count High RTs cases by Emergency Units
HRTperEU <- as.data.frame(table(CasesHRTA1$Ficha)) %>%
drop_na(Var1) %>%
rename(Ficha="Var1")
# Merge to obtain the count of High RTs cases by Emergency Units
EmerUnitsSA1 <- EmerUnitsSA1 %>%
merge(.,HRTperEU) %>%
rowid_to_column(., "sid") #Create a unique id variable "sid"
# Isochrones (for 8 and 10 minutes) for S- A1 Emergency Units
D_isoA1 <- mb_isochrone(EmerUnitsSA1,
"driving",
time = c(8,10),
id_column = "sid",
access_token = my_token)
# Get variables from EmerUnits sf to join with isochrones
euHRTsA1_m <- EmerUnitsSA1 %>%
st_drop_geometry()
# Join
D_isoA1 <- D_isoA1 %>%
merge(., euHRTsA1_m,
by.x="id",
by.y="sid")
# Plot the result
Map4.1 <- tm_shape(D_isoA1) +
tm_fill(col = "time",
palette="GnBu",
alpha = 0.9,
title="Drive time Isochrones (mins)",
legend.is.portrait = F) +
tm_facets(by="time",
ncol = 2) +
#Roads are used for visualisation purpose.
#It can take a while to run. Un-comment to plot it.
# tm_shape(RoadsProv %>% filter(fclass == "primary"|fclass == "residential")) +
# tm_lines(lwd=0.1) +
tm_shape(RoadsA1) +
tm_lines(lwd=0.2) +
tm_shape(provinces) +
tm_polygons(col = "white",
border.lwd = 0.2,
border.col = "#737373",
alpha = 0.1)+
tm_text("TOPONIMIA",
col = "#737373",
size = 0.7) +
tm_shape(ZoneSA1) +
tm_polygons(col = "ZONA",
palette = "white",
border.lwd = 0.2,
border.col = "#8856a7",
alpha = 0.1,
title="Response Zone")+
tm_text("ZONA",
col = "#8856a7",
size = 0.5)+
tm_shape(EmerUnitsSA1) +
tm_dots(col = "Ficha",
palette = "#8856a7",
size = 0.3,
border.col = "white",
border.lwd = 0.5,
legend.show = FALSE)+
tm_add_legend(title="Emergency Unit allocation",
type = "symbol",
labels = " Emergency Unit",
col = "#8856a7")+
tm_layout(outer.margins = 0,
panel.label.bg.color = 'white',
panel.label.size = 1.2,
legend.outside=TRUE,
legend.outside.position = "bottom",
title.snap.to.legend = T)+
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_scale_bar(position=c("left", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")
# This will save the map in the same path as the project.
tmap_save(Map4.1,
filename="Map4.1.png",
dpi=600)
Map4.1
### 4.1.Analysis of the service area. In this part will analyse how many events with high RT were reachable by the ambulances in 8-10 minutes.
# Join cases with isochrones
CasesHRTA1b <- CasesHRTA1 %>%
st_transform(4326) %>% # 1. project to the same crs as the isochrones
st_join(., D_isoA1) %>% # 2. Join
na.omit()
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
# Count the cases by the common field (Ficha) to get the number of
# events by ambulances
CasesHRTA1bcount <- CasesHRTA1b %>%
group_by(id, Ficha.y) %>%
summarise(n=n())
## `summarise()` regrouping output by 'id' (override with `.groups` argument)
CasesHRTA1bcount
## Simple feature collection with 14 features and 3 fields
## geometry type: MULTIPOINT
## dimension: XY
## bbox: xmin: -69.94585 ymin: 18.4447 xmax: -69.87543 ymax: 18.51247
## geographic CRS: WGS 84
## # A tibble: 14 x 4
## # Groups: id [14]
## id Ficha.y n geometry
## <int> <chr> <int> <MULTIPOINT [°]>
## 1 1 A-0101 1223 ((-69.94585 18.48148), (-69.94445 18.48263), (-69.9444 …
## 2 2 A-0103 2181 ((-69.94585 18.48148), (-69.94445 18.48263), (-69.94005…
## 3 3 A-0107 553 ((-69.94295 18.47778), (-69.94238 18.4812), (-69.94203 …
## 4 4 B-0101 1123 ((-69.9269 18.46707), (-69.92673 18.46722), (-69.92655 …
## 5 5 B-0102 414 ((-69.93363 18.46043), (-69.93247 18.46483), (-69.93223…
## 6 6 B-0103 267 ((-69.9413 18.4725), (-69.9408 18.47228), (-69.93977 18…
## 7 7 B-0107 2038 ((-69.94585 18.48148), (-69.94445 18.48263), (-69.9444 …
## 8 8 B-0108 1665 ((-69.94585 18.48148), (-69.94445 18.48263), (-69.9444 …
## 9 9 B-0109 1601 ((-69.91348 18.48183), (-69.91138 18.48193), (-69.91072…
## 10 10 B-0110 1063 ((-69.94585 18.48148), (-69.94445 18.48263), (-69.9418 …
## 11 11 B-0115 2054 ((-69.92248 18.47002), (-69.9222 18.4705), (-69.92158 1…
## 12 12 B-0121 2017 ((-69.92957 18.46597), (-69.92848 18.46648), (-69.9269 …
## 13 13 B-0133 1073 ((-69.93463 18.4996), (-69.93438 18.4989), (-69.93395 1…
## 14 14 CRD-0132 1830 ((-69.92422 18.499), (-69.92385 18.49928), (-69.92373 1…
# Here we create a single point per ambulance.
CasesHRTA1bcount_centroid <- st_centroid(CasesHRTA1bcount)
## Warning in st_centroid.sf(CasesHRTA1bcount): st_centroid assumes attributes are
## constant over geometries of x
## Warning in st_centroid.sfc(st_geometry(x), of_largest_polygon =
## of_largest_polygon): st_centroid does not give correct centroids for longitude/
## latitude data
# Plot the result
Map4.2 <- tm_shape(RoadsA1) +
tm_lines(lwd=0.2) +
#Roads are used for visualisation purpose.
#It can take a while to run. Un-comment to plot it.
# tm_shape(RoadsProv %>% filter(fclass == "primary"|fclass == "residential")) +
# tm_lines(lwd=0.1) +
tm_shape(ZoneSA1)+
tm_fill(col = "white",
alpha = 0.3,
border.lwd = 0.2,
border.col = "#8856a7",
show.legend = FALSE)+
tm_shape(provinces) +
tm_polygons(col = "white",
border.lwd = 0.2,
border.col = "#737373",
alpha = 0.1)+
tm_text("TOPONIMIA",
col = "#737373",
size = 0.7) +
tm_shape(ZoneSA1) +
tm_polygons(col = "ZONA",
palette = "white",
border.lwd = 0.2,
border.col = "#8856a7",
alpha = 0.1,
title="Response Zone")+
tm_text("ZONA",
col = "#8856a7",
size = 0.8,
ymod = -0.6)+
tm_shape(CasesHRTA1bcount_centroid) +
tm_bubbles(col = "#8856a7",
size = "n",
alpha = 0.4,
border.lwd = 0.3,
style = "kmeans",
title.size="Count of cases \nreachable by S-A1 emergency units") +
tm_text("Ficha.y",
col = "black",
size = 0.5,
ymod = -0.6) +
tm_layout(outer.margins = 0,
panel.label.bg.color = 'white',
panel.label.size = 1.2,
legend.outside=TRUE,
legend.outside.position = "right",
title.snap.to.legend = T)+
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_scale_bar(position=c("left", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")
# This will save the map in the same path as the project.
tmap_save(Map4.2,
filename="Map4.2.png",
dpi=600)
Map4.2
# Ambulances with Highest RTs
euHRTs <- EmerUnitsSA1 %>%
slice_max(EmerUnitsSA1$Freq, n = 4)
# Isochrones (for 8 and 10 minutes) for Emergency Units with most cases with highest RTs
D_isoA1b <- mb_isochrone(euHRTs,
"driving",
time = c(8,10),
id_column = "sid",
access_token = my_token)
# Get variables from EmerUnits sf to join with isochrones
euHRTs_mb <- euHRTs %>%
st_drop_geometry()
# Join
D_isoA1b <- D_isoA1b %>%
merge(., euHRTs_mb,
by.x="id",
by.y="sid")
# Change name of column 'primary_unitid' to 'Ficha'
CasesDNA1b <- CasesA1 %>%
rename(Ficha="primary_unitid") %>%
#Filter cases by Emergency Units with most cases with highest response times
filter(Ficha %in% euHRTs$Ficha)
# Plot
tmap_mode("plot")
## tmap mode set to plotting
Map4.3 <- tm_shape(D_isoA1b) +
tm_polygons(col = "time",
palette="GnBu",
border.lwd = 0.3,
border.col = "white",
alpha = 0.9,
title="Drive time Isochrones (mins)",
legend.is.portrait = F) +
tm_facets(by="Ficha",
ncol = 2) +
tm_shape(RoadsA1) +
tm_lines(lwd=0.2) +
tm_shape(ZoneSA1) +
tm_polygons(col = "ZONA",
palette = "white",
border.lwd = 0.2,
border.col = "#8856a7",
alpha = 0.1,
title="Response Zone")+
tm_shape(CasesDNA1b) +
tm_dots(col = "RTrange",
palette = "#e34a33",
legend.show = FALSE)+
tm_facets(by="Ficha",
ncol = 2)+
tm_add_legend(title="Emergency Cases",
type = "symbol",
labels = " > 10 mins",
col = "#e34a33")+
tm_shape(euHRTs) +
tm_dots(col = "Ficha",
palette = "#8856a7",
size = 0.5,
border.col = "white",
border.lwd = 0.5,
legend.show = FALSE)+
tm_add_legend(title="Emergency Unit allocation",
type = "symbol",
labels = " Emergency Unit",
col = "#8856a7")+
tm_facets(by="Ficha",
ncol = 2)+
tm_layout(outer.margins = 0,
panel.label.bg.color = 'white',
panel.label.size = 1.2,
legend.outside=TRUE,
legend.outside.position = "right",
title.snap.to.legend = T)+
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_scale_bar(position=c("left", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")
Map4.3
# Save the plot
tmap_save(Map4.3,
filename="Map4.3.png",
dpi=600)
Events that fall inside the Isochrones. Now we will count the events whit high RT that fall inside the calculated isochrones.
# Project to EPSG:32619.
D_isoA1c <- D_isoA1b %>%
st_transform(., 32619)
Cases_inIso <- CasesDNA1b[D_isoA1c,] %>%
group_by(., Ficha) %>%
count(count=n())
Cases_inIso
## Simple feature collection with 4 features and 3 fields
## geometry type: MULTIPOINT
## dimension: XY
## bbox: xmin: 402667.8 ymin: 2041559 xmax: 407505 ymax: 2047223
## projected CRS: WGS 84 / UTM zone 19N
## # A tibble: 4 x 4
## Ficha count n geometry
## * <chr> <int> <int> <MULTIPOINT [m]>
## 1 B-0101 200 200 ((402667.8 2045661), (402829.7 2043256), (403445.2 204662…
## 2 B-0109 216 216 ((402856.4 2045705), (403334.6 2045645), (403432.4 204411…
## 3 B-0115 222 222 ((403350.7 2045698), (403415.7 2046369), (403551.2 204636…
## 4 CRD-01… 221 221 ((403158 2043783), (403339.7 2043168), (403341.7 2045652)…
Here, we will calculate a route from a random Emergency Unit Allocation (from the 4 analysed before) to a random Emergency Case that had a high RT. The result will be a sf with a route, directions and ETA.
To run this part of the analysis you will use your Mapbox token. Go to this link to create it:https://www.mapbox.com
Check also the Mapbox documentation for more information: https://docs.mapbox.com/api/navigation/directions/
# Create new data frame for cases without geometry
CasesHRTA15 <- CasesHRTA1 %>%
#Coordinates must be in WGS84
st_transform(4326) %>%
#Obtain XY coordinates
cbind(st_coordinates(.)) %>%
#Drop the geometry
st_drop_geometry()
# Create new data frame for Emergency Units without geometry
euHRTA15 <- euHRTs %>%
#Coordinates must be in WGS84
st_transform(4326) %>%
#Obtain XY coordinates
cbind(st_coordinates(.)) %>%
#Drop the geometry
st_drop_geometry()
# Dataframe with origin and destination coordinates
dfCasesHRTmerge <- merge(CasesHRTA15,euHRTA15,by="Ficha")
# Create an object to select a random row from the data frame
Random_index <- floor(runif(1,min = 0,max = nrow(dfCasesHRTmerge)))
# Define the Origin and destination list from the data frame
Origin <- list(toString(dfCasesHRTmerge[Random_index,]['X.y']),toString(dfCasesHRTmerge[Random_index,]['Y.y']))
Destination <- list(toString(dfCasesHRTmerge[Random_index,]['X.x']),toString(dfCasesHRTmerge[Random_index,]['Y.x']))
# Create the optimal route with the Mapbox Api
D_dir <- mb_directions(origin = Origin,
destination = Destination,
#set the profile to "driving-traffic"
#this consults traffic data from the Mapbox API
profile="driving-traffic",
output = "sf",
access_token = my_token,
steps=TRUE)
# Let's have a look at the results
D_dir
## Simple feature collection with 5 features and 3 fields
## geometry type: LINESTRING
## dimension: XY
## bbox: xmin: -69.88938 ymin: 18.50468 xmax: -69.88428 ymax: 18.50816
## geographic CRS: WGS 84
## geometry distance duration
## 1 LINESTRING (-69.88428 18.50... 0.0597 0.170000
## 2 LINESTRING (-69.88479 18.50... 0.0814 0.245000
## 3 LINESTRING (-69.88527 18.50... 0.3784 1.536667
## 4 LINESTRING (-69.88736 18.50... 0.2629 1.031667
## 5 LINESTRING (-69.88938 18.50... 0.0000 0.000000
## instruction
## 1 Head southwest
## 2 Go straight onto Avenida Francisco del Rosario Sánchez
## 3 Make a slight left onto Calle Óscar Santana
## 4 Turn left onto Calle 23
## 5 You have arrived at your destination
# Obtain the time (minutes) and distance (kilometers) of the trip
sum(D_dir$duration)
## [1] 2.983333
sum(D_dir$distance)
## [1] 0.7824
# Create an sf for the Origin and Destination data frame
Origin_sf <- as.data.frame(Origin, col.names = c("longitude", "latitude")) %>%
data.frame(., type = "Origin") %>%
st_as_sf(., coords = c("longitude", "latitude"), crs = 4326)
Destination_sf <- as.data.frame(Destination, col.names = c("longitude", "latitude")) %>%
data.frame(., type = "Destination") %>%
st_as_sf(., coords = c("longitude", "latitude"), crs = 4326)
#Combine both sf into one.
OriDes <- rbind(Origin_sf,Destination_sf)
# Plot
tmap_mode("plot")
## tmap mode set to plotting
Map5 <- tm_shape(D_dir)+
tm_lines(col = "#7bccc4",
lwd=6)+
tm_add_legend(title="Leyend",
type = "line",
labels = " Route",
col = "#7bccc4",
lwd = 2)+
tm_shape(boroughs)+
tm_polygons(col = "#f0f0f0")+
tm_text("TOPONIMIA",
size = 0.8,
col = "#969696")+
tm_shape(D_dir)+
tm_lines(col = "#7bccc4",
lwd=6)+
tm_shape(RoadsA1 %>% filter(fclass == "primary"))+
tm_lines(col = "white",
lwd=0.6)+
tm_shape(RoadsA1)+
tm_lines(lwd=0.4,
palette = "white",
legend.show = FALSE)+
tm_shape(OriDes)+
tm_dots(col = "type",
palette = "BuPu",
size = 1,
title = "Type")+
tm_compass(north = 0,
type = "arrow",
text.size = 0.8,
show.labels = 1,
cardinal.directions = c("N", "E", "S", "W"),
lwd = 1,
position = c("right","top"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363",
size = 3)+
tm_scale_bar(position=c("right", "bottom"),
color.light="#f0f0f0",
color.dark="#636363",
text.color="#636363")+
tm_layout(legend.position = c("left", "bottom"),
legend.bg.color = "white",
legend.bg.alpha = 0.7,
legend.width = 0.6,
title.snap.to.legend = T,
inner.margin=c(0.12,0.10,0.10,0.12))
Map5
# Save the plot
tmap_save(Map5,
filename="Map5.png",
dpi=600)
This is the end of this document.