library(sf)
library(kableExtra)
library(gridExtra)
options(scipen=999)
options(tigris_class = "sf")
library(biscale)
library(dplyr)
library(ggplot2)
library(cowplot)
library(grid)
library(gridExtra)
library(viridis)
library(rgeoboundaries)
root.dir = "https://raw.githubusercontent.com/urbanSpatial/Public-Policy-Analytics-Landing/master/DATA/"
source("https://raw.githubusercontent.com/urbanSpatial/Public-Policy-Analytics-Landing/master/functions.r")
shooting <- st_read("https://services.arcgis.com/fLeGjb7u4uXqeF9q/arcgis/rest/services/SHOOTINGS/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson")%>% st_transform('ESRI:102286') %>% na.omit()
## Reading layer `OGRGeoJSON' from data source
## `https://services.arcgis.com/fLeGjb7u4uXqeF9q/arcgis/rest/services/SHOOTINGS/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson'
## using driver `GeoJSON'
## replacing null geometries with empty geometries
## Simple feature collection with 16352 features and 21 fields (with 27 geometries empty)
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -75.27362 ymin: 39.87799 xmax: -74.95936 ymax: 40.13117
## Geodetic CRS: WGS 84
group_year <- shooting %>%
group_by(YEAR) %>%
summarize(count = n()) %>%
arrange(-count)
shooting.23 <-
shooting %>%
filter(YEAR == 2023) %>%
dplyr::select(geometry) %>%
na.omit() %>%
st_as_sf(coords = c("Long", "Lat"), crs = "EPSG:4326") %>%
st_transform('ESRI:102286') %>%
distinct()
shooting.23_1 <-
shooting %>%
filter(YEAR == 2023)
philly <- geoboundaries("United States", adm_lvl = "adm2") %>%
filter(shapeName == "Philadelphia") %>% st_transform('ESRI:102286')
usa <- geoboundaries("United States", adm_lvl = "adm2") %>% st_transform('ESRI:102286')
R Markdown
final_map <-
ggplot() +
# Base map for Philadelphia
geom_sf(data = philly, fill = "grey70", color = "white", lwd = 0.4) +
#geom_sf(data = usa, fill = "grey50", color = "white", lwd = 0.4) +
# Density estimation layer for shootings
stat_density2d(
data = data.frame(st_coordinates(shooting.23)),
aes(X, Y, fill = ..level.., alpha = ..level..),
geom = 'polygon',
bins = 50,
size = 0.01
) +
# Density color and transparency
scale_fill_viridis(option = "plasma", name = "Density Levels") +
scale_alpha(range = c(0.00, 0.7), guide = FALSE) +
# Titles and labels
labs(
title = "Density of Shooting Victims in Philadelphia, 2023",
subtitle = "Hotspots of shooting incidents based on density estimation",
caption = "30 Day Map Challenge | Day 25 - Heat Map\nAuthor: Jiatong Su\nData Source: OpenDataPhilly",
x = NULL, y = NULL
) +
# Annotation for University City
annotate(
"text", x = -107023.9, y = 635206.3,
label = "High shooting victims in\nUniversity City",
color = "red", size = 3.5, hjust = 0
) +
annotate(
"segment", x = -107023.9, xend = -112723.9,
y = 635206.3, yend = 645006.3,
color = "red", size = 0.8,
arrow = arrow(length = unit(0.2, "cm"))
) +
# Enhance plot theme
theme_minimal() +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5, color = "white"),
plot.subtitle = element_text(size = 12, color = "gray70", hjust = 0.5),
plot.caption = element_text(size = 9, hjust = 0, color = "gray50"),
legend.position = "none", # Hide the legend
panel.grid = element_blank(), # Remove grid lines for cleaner visualization
axis.text = element_blank(), # Remove axis text
axis.ticks = element_blank(), # Remove axis ticks
plot.background = element_rect(fill = "black", color = NA), # Set plot background to black
panel.background = element_rect(fill = "black", color = NA), # Set panel background to black
plot.margin = margin(10, 85, 10, 85) # Add some margin for spacing
)
final_map

ggsave("jiatong_day25.png", plot = final_map, width = 8, height = 6, dpi = 300)
LS0tCnRpdGxlOiAiZGF5MjUtSGVhdCIKYXV0aG9yOiBKaWF0b25nIFN1Cm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHNpbXBsZXgKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgcHJvZ3Jlc3M6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwotLS0KCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoZ3JpZEV4dHJhKQpvcHRpb25zKHNjaXBlbj05OTkpCm9wdGlvbnModGlncmlzX2NsYXNzID0gInNmIikKbGlicmFyeShiaXNjYWxlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoY293cGxvdCkKCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShyZ2VvYm91bmRhcmllcykKCmBgYAoKCmBgYHtyfQpyb290LmRpciA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdXJiYW5TcGF0aWFsL1B1YmxpYy1Qb2xpY3ktQW5hbHl0aWNzLUxhbmRpbmcvbWFzdGVyL0RBVEEvIgoKc291cmNlKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdXJiYW5TcGF0aWFsL1B1YmxpYy1Qb2xpY3ktQW5hbHl0aWNzLUxhbmRpbmcvbWFzdGVyL2Z1bmN0aW9ucy5yIikKYGBgCgoKYGBge3J9CgpzaG9vdGluZyA8LSBzdF9yZWFkKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vZkxlR2piN3U0dVhxZUY5cS9hcmNnaXMvcmVzdC9zZXJ2aWNlcy9TSE9PVElOR1MvRmVhdHVyZVNlcnZlci8wL3F1ZXJ5P291dEZpZWxkcz0qJndoZXJlPTElM0QxJmY9Z2VvanNvbiIpJT4lIHN0X3RyYW5zZm9ybSgnRVNSSToxMDIyODYnKSAlPiUgbmEub21pdCgpCmdyb3VwX3llYXIgPC0gc2hvb3RpbmcgJT4lIApncm91cF9ieShZRUFSKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JQogIGFycmFuZ2UoLWNvdW50KSAKCnNob290aW5nLjIzIDwtCiAgc2hvb3RpbmcgJT4lCiAgIGZpbHRlcihZRUFSID09IDIwMjMpICU+JQogICAgZHBseXI6OnNlbGVjdChnZW9tZXRyeSkgJT4lCiAgICBuYS5vbWl0KCkgJT4lCiAgICBzdF9hc19zZihjb29yZHMgPSBjKCJMb25nIiwgIkxhdCIpLCBjcnMgPSAiRVBTRzo0MzI2IikgJT4lCiAgICBzdF90cmFuc2Zvcm0oJ0VTUkk6MTAyMjg2JykgJT4lCiAgICBkaXN0aW5jdCgpCgpzaG9vdGluZy4yM18xIDwtCiAgc2hvb3RpbmcgJT4lCiAgIGZpbHRlcihZRUFSID09IDIwMjMpCgpwaGlsbHkgPC0gZ2VvYm91bmRhcmllcygiVW5pdGVkIFN0YXRlcyIsIGFkbV9sdmwgPSAiYWRtMiIpICU+JQogIGZpbHRlcihzaGFwZU5hbWUgPT0gIlBoaWxhZGVscGhpYSIpICU+JSBzdF90cmFuc2Zvcm0oJ0VTUkk6MTAyMjg2JykKCnVzYSA8LSBnZW9ib3VuZGFyaWVzKCJVbml0ZWQgU3RhdGVzIiwgYWRtX2x2bCA9ICJhZG0yIikgJT4lIHN0X3RyYW5zZm9ybSgnRVNSSToxMDIyODYnKQoKYGBgCgojIyBSIE1hcmtkb3duCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KZ2dwbG90KCkgKyAKICAgIGdlb21fc2YoZGF0YSA9IHVzYSwgZmlsbCA9ICJncmV5NjAiLCBjb2xvciA9IE5BKSArCgogIGdlb21fc2YoZGF0YSA9IHBoaWxseSwgZmlsbCA9ICJncmV5IiwgY29sb3IgPSBOQSkgKwogIHN0YXRfZGVuc2l0eTJkKGRhdGEgPSBkYXRhLmZyYW1lKHN0X2Nvb3JkaW5hdGVzKHNob290aW5nLjIzKSksIAogICAgICAgICAgICAgICAgIGFlcyhYLCBZLCBmaWxsID0gLi5sZXZlbC4uLCBhbHBoYSA9IC4ubGV2ZWwuLiksCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMDEsIGJpbnMgPSA1MCwgZ2VvbSA9ICdwb2x5Z29uJykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICAgY29vcmRfc2YoCiAgICB4bGltID0gYygtODAwMDAuMywgLSAxMzU1MDMuMyksICAKICAgICMgQWRqdXN0IHRvIHRoZSBhcHByb3ByaWF0ZSB4IChlYXN0aW5nKSBsaW1pdHMgaW4gbWV0ZXJzIGZvciBFU1JJOjEwMjI4NgogICAgeWxpbSA9IGMoNjI1NzY3LjMsIDY2NTc2Ny4zKSwgCiAgICAjIEFkanVzdCB0byB0aGUgYXBwcm9wcmlhdGUgeSAobm9ydGhpbmcpIGxpbWl0cyBpbiBtZXRlcnMgZm9yIEVTUkk6MTAyMjg2CiAgICBleHBhbmQgPSBGQUxTRSAgICAgICAgICAgICMgRW5zdXJlIHRoZSBmcmFtZSBkb2VzIG5vdCBhdXRvLWV4cGFuZAogICkgKwogIAogIHNjYWxlX2ZpbGxfdmlyaWRpcyhvcHRpb24gPSAicGxhc21hIiwgbmFtZSA9ICJEZW5zaXR5IExldmVscyIpICsgICMgRW5oYW5jZSBjb2xvciBwYWxldHRlCiAgc2NhbGVfYWxwaGEocmFuZ2UgPSBjKDAuMDAsIDAuNSksIGd1aWRlID0gRkFMU0UpICsgICMgQWRqdXN0IHRyYW5zcGFyZW5jeQogIGxhYnMoCiAgICB0aXRsZSA9ICJEZW5zaXR5IG9mIFNob290aW5nIFZpY3RpbXMgaW4gUGhpbGFkZWxwaGlhLCAyMDIzIiwKICAgIHN1YnRpdGxlID0gIkhvdHNwb3RzIG9mIHNob290aW5nIGluY2lkZW50cyBiYXNlZCBvbiBkZW5zaXR5IGVzdGltYXRpb24iLAogICAgY2FwdGlvbiA9ICIzMCBkYXkgbWFwIGNoYWxsZW5nZSB8IERheTEgLSBQb2ludFxuQXV0aG9yOiBKaWF0b25nIFN1XG5EYXRhIFNvdXJjZTogQ2FsaWZvcm5pYSBTdGF0ZSBHZW9wb3J0YWwiLAoKICAgIHggPSBOVUxMLCB5ID0gTlVMTAogICkgKyAKICAKICAjIEFubm90YXRpb24gZm9yIFVuaXZlcnNpdHkgQ2l0eQogIGFubm90YXRlKAogICAgInRleHQiLCB4ID0gLTEwNzAyMy45LCB5ID0gNjM1MjA2LjMsIGxhYmVsID0gIkhpZ2ggc2hvb3RpbmcgdmljaXRtcyBpblxuVW5pdmVyc2l0eSBDaXR5IiwKICAgIGNvbG9yID0gImRhcmtyZWQiLCBzaXplID0gMy41LCBoanVzdCA9IDAKICApICsKICBhbm5vdGF0ZSgKICAgICJzZWdtZW50IiwgeCA9IC0xMDcwMjMuOSwgeGVuZCA9IC0xMTI3MjMuOSwgeSA9IDYzNTIwNi4zLCB5ZW5kID0gNjQ1MDA2LjMsCiAgICBjb2xvciA9ICJkYXJrcmVkIiwgc2l6ZSA9IDAuOCwgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAKICBtYXBUaGVtZSh0aXRsZV9zaXplID0gMTQpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwKSwKICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBoanVzdCA9IDApLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImdyYXkiKSwKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKCgpgYGB7ciBjYXJzfQoKZmluYWxfbWFwIDwtIApnZ3Bsb3QoKSArCiAgIyBCYXNlIG1hcCBmb3IgUGhpbGFkZWxwaGlhCgogIGdlb21fc2YoZGF0YSA9IHBoaWxseSwgZmlsbCA9ICJncmV5NzAiLCBjb2xvciA9ICJ3aGl0ZSIsIGx3ZCA9IDAuNCkgKwogICNnZW9tX3NmKGRhdGEgPSB1c2EsIGZpbGwgPSAiZ3JleTUwIiwgY29sb3IgPSAid2hpdGUiLCBsd2QgPSAwLjQpICsKCgogICMgRGVuc2l0eSBlc3RpbWF0aW9uIGxheWVyIGZvciBzaG9vdGluZ3MKICBzdGF0X2RlbnNpdHkyZCgKICAgIGRhdGEgPSBkYXRhLmZyYW1lKHN0X2Nvb3JkaW5hdGVzKHNob290aW5nLjIzKSksCiAgICBhZXMoWCwgWSwgZmlsbCA9IC4ubGV2ZWwuLiwgYWxwaGEgPSAuLmxldmVsLi4pLAogICAgZ2VvbSA9ICdwb2x5Z29uJywKICAgIGJpbnMgPSA1MCwKICAgIHNpemUgPSAwLjAxCiAgKSArCiAgCiAgIyBEZW5zaXR5IGNvbG9yIGFuZCB0cmFuc3BhcmVuY3kKICBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uID0gInBsYXNtYSIsIG5hbWUgPSAiRGVuc2l0eSBMZXZlbHMiKSArCiAgc2NhbGVfYWxwaGEocmFuZ2UgPSBjKDAuMDAsIDAuNyksIGd1aWRlID0gRkFMU0UpICsKICAKICAjIFRpdGxlcyBhbmQgbGFiZWxzCiAgbGFicygKICAgIHRpdGxlID0gIkRlbnNpdHkgb2YgU2hvb3RpbmcgVmljdGltcyBpbiBQaGlsYWRlbHBoaWEsIDIwMjMiLAogICAgc3VidGl0bGUgPSAiSG90c3BvdHMgb2Ygc2hvb3RpbmcgaW5jaWRlbnRzIGJhc2VkIG9uIGRlbnNpdHkgZXN0aW1hdGlvbiIsCiAgICBjYXB0aW9uID0gIjMwIERheSBNYXAgQ2hhbGxlbmdlIHwgRGF5IDI1IC0gSGVhdCBNYXBcbkF1dGhvcjogSmlhdG9uZyBTdVxuRGF0YSBTb3VyY2U6IE9wZW5EYXRhUGhpbGx5IiwKICAgIHggPSBOVUxMLCB5ID0gTlVMTAogICkgKwogIAogICMgQW5ub3RhdGlvbiBmb3IgVW5pdmVyc2l0eSBDaXR5CiAgYW5ub3RhdGUoCiAgICAidGV4dCIsIHggPSAtMTA3MDIzLjksIHkgPSA2MzUyMDYuMywgCiAgICBsYWJlbCA9ICJIaWdoIHNob290aW5nIHZpY3RpbXMgaW5cblVuaXZlcnNpdHkgQ2l0eSIsCiAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMy41LCBoanVzdCA9IDAKICApICsKICBhbm5vdGF0ZSgKICAgICJzZWdtZW50IiwgeCA9IC0xMDcwMjMuOSwgeGVuZCA9IC0xMTI3MjMuOSwgCiAgICB5ID0gNjM1MjA2LjMsIHllbmQgPSA2NDUwMDYuMywKICAgIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjgsIAogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpCiAgKSArCiAgCiAgIyBFbmhhbmNlIHBsb3QgdGhlbWUKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJ3aGl0ZSIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImdyYXk3MCIsIGhqdXN0ID0gMC41KSwKICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgaGp1c3QgPSAwLCBjb2xvciA9ICJncmF5NTAiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgICAgIyBIaWRlIHRoZSBsZWdlbmQKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksICAjIFJlbW92ZSBncmlkIGxpbmVzIGZvciBjbGVhbmVyIHZpc3VhbGl6YXRpb24KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgICAjIFJlbW92ZSBheGlzIHRleHQKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksICAjIFJlbW92ZSBheGlzIHRpY2tzCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJibGFjayIsIGNvbG9yID0gTkEpLCAgICMgU2V0IHBsb3QgYmFja2dyb3VuZCB0byBibGFjawogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImJsYWNrIiwgY29sb3IgPSBOQSksICAjIFNldCBwYW5lbCBiYWNrZ3JvdW5kIHRvIGJsYWNrCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgODUsIDEwLCA4NSkgICMgQWRkIHNvbWUgbWFyZ2luIGZvciBzcGFjaW5nCiAgKSAKCmZpbmFsX21hcApgYGAKCmBgYHtyfQpnZ3NhdmUoImppYXRvbmdfZGF5MjUucG5nIiwgcGxvdCA9IGZpbmFsX21hcCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApCmBgYAoK