# Load the required packages
library(sf) #for spatial data
library(ggplot2) #for plotting
library(dplyr) #for data manipulation
library(RColorBrewer) #for diverging colour scheme
library(tidyverse) #for piping
library(ggmap) #for creating maps
library(png) #for importing inset map image
library(magick) #for adding inset image
library(ggpubr) #for multi-plot figures
library(cowplot) # for multi-plot figures
library(knitr) # for including graphics
# Import the LA Shapefile using st_read
LA <- st_read("Geo_Vis_2_Data/LA_County_City_Boundaries/LA_County_City_Boundaries.shp",
stringsAsFactors = FALSE)
## Reading layer `LA_County_City_Boundaries' from data source
## `C:\Users\shiva\Documents\University of Sheffield\Year 2\TRP620 Open Source GIS and Spatial Analysis\Assessment\Geo_Vis_2\Geo_Vis_2\Geo_Vis_2_Data\LA_County_City_Boundaries\LA_County_City_Boundaries.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 635 features and 19 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: -118.9447 ymin: 32.79959 xmax: -117.6464 ymax: 34.8233
## Geodetic CRS: WGS 84
# Check CRS of the LA shapefile
#st_crs(LA) # CRS is WGS 84, EPSG 4326
# View attribute table of the LA shapefile
#View(LA)
# Import the LA Crime Data
# https://data.lacity.org/Public-Safety/Crime-Data-from-2020-to-Present/2nrs-mtv8
# Feb 2020 to present (15/12/21)
LAcrime <- read.csv("Geo_Vis_2_Data/LA_Crime_Data_from_2020_to_Present.csv")
# View the imported dataframe
# Each observation/row is a crime incident that has occurred
#View(LAcrime)
#str(LAcrime) # see datatypes of each column
# Deal with missing coord data in the LAcrime dataframe
# Select the observations where LON does NOT have 0 values OR LAT does NOT have 0 values
LAcrime <- LAcrime %>% filter(LON != 0 | LAT != 0) # remaining 387,999 obs
# Extract only the City of LA boundary from the LA county
# Use filter from dplyr to select only the City of Los Angeles area
LA_city <- filter(LA, CITY_LABEL == "Los Angeles")
# View the geometry type of the shapefile
#st_geometry_type(LA_city)
# Plot the City of Los Angeles geometry using ggplot
ggplot() +
# Add the LA boundary shapefile
geom_sf(data=LA_city) +
# Add the crime point data +
#geom_point(data=LAcrime, mapping = aes(x=LON, y=LAT), color="red") +
# Add hex binned layer
geom_hex(data=LAcrime,
mapping = aes(x=LON, y=LAT), bins=15, color="black")+
scale_fill_fermenter(n.breaks=10,palette = "RdYlBu")+
# No theme to remove lat/long coord axis
theme_void()
ggplot() +
# Divide plane into rectangles and count number of cases in each
geom_bin_2d(data=LAcrime,
mapping = aes(x=LON, y=LAT)) +
# No theme to remove lat/long coord axis
theme_void()
ggplot() +
# Add the LA city boundary
geom_sf(data=LA_city) +
# Calculate 2D kernel density estimate and plot the contours
geom_density_2d(data=LAcrime,
mapping = aes(x=LON, y=LAT)) +
# No theme to remove lat/long coord axis
theme_void()
Measuring the density of the crime incidents using hex bins is informative, however does not look visually appealing.
Rectangle binning is also helpful, however the plot looks over-crowded.
Using the 2D Kernel Density Estimate (KDE) provides a better perspective on the crimes as it is a generalisation of the former two methods.
# Plot the City of Los Angeles geometry using ggplot
map1<- ggplot() +
# Add LA city boundary
geom_sf(data=LA_city) +
# 2D KDE and plot contours
stat_density_2d(data=LAcrime,
geom = "polygon",
contour = TRUE,
aes(x=LON, y=LAT, fill = after_stat(level)),
# Make transparent
alpha = 0.6,
# Contour line colour
colour = "darkblue",
# 5 bins used as this map will be smaller in main geovis
bins = 5) +
# Use colour-blind friendly colour palette and format legend labels
scale_fill_distiller(palette = "RdYlBu", direction = -1,
breaks = c(20, 30, 40, 50, 60),
labels = c("Low","","Med","","High"),
name = "Density (KDE)") +
# No theme to remove lat/long coord axis
theme_void() +
# Add plot title
ggtitle("All Crime Incidents (n = 387,999)") +
# Legend and title formatting
theme(legend.position = c(0.10, 0.25),
legend.title = element_text(size=8),
legend.key.size = unit(0.3, "cm"),
plot.title = element_text(size=9, face="bold",hjust = 0.5, vjust= 1.5),
plot.margin = rep(unit(0,"null"),4),
panel.spacing = unit(0,"null"))
map1
Both ‘petty’ shoplifting (under $950) and ‘grand’ shoplifting crimes (above $950) are included.
# Understand the crime categories
# Find all unique values for the Crm.Cd.Desc variable
#unique(LAcrime[c("Crm.Cd.Desc")]) # 135 different categories of crime
# Get count of each type of crime
#LAcrime %>% count(Crm.Cd.Desc, sort = TRUE)
# Map all Shoplifting crimes in LA
map2<- ggmap(LA_bmap) + #use the LA OSM basemap
# 2D KDE and display result with contours - to prevent overplotting of points
stat_density_2d(data= filter(LAcrime,
# Both types of shoplifting
Crm.Cd.Desc == "SHOPLIFTING-GRAND THEFT ($950.01 & OVER)" |
Crm.Cd.Desc =="SHOPLIFTING - PETTY THEFT ($950 & UNDER)"),
geom = "polygon",
contour = TRUE,
aes(x=LON, y=LAT,
fill = after_stat(level)),
# Make transparent
alpha = 0.4,
# Line colour of the contours
colour = "darkblue",
# 6 bins used to prevent too many contour lines
bins= 6) +
# Use colour-blind friendly colour palette and format legend labels
scale_fill_distiller(palette = "RdYlBu", direction = -1,
breaks = c(10, 15, 20, 25, 30),
labels = c("Low","","Med","","High"),
name = "Density") +
# No theme to remove lat/long coord axis
theme_void() +
# Add plot title
ggtitle("Shoplifting Incidents (n = 7290)") +
# Remove legend as Map1 in main geovis will include an identical one
theme(legend.position = "none",
# Format and position plot title
plot.title = element_text(size=9, face="bold",hjust = 0.5, vjust= 1.5),
# Adjust plot margins, both maps can be positioned correctly in main geovis
plot.margin = rep(unit(0,"null"),4),
panel.margin = unit(0,"null"))
map2
# Read in the contextual map image
# https://nsholmes21.medium.com/the-puzzle-of-places-in-la-18e8a537e3ac
inset <- image_read("LA_inset_map.png")
# Resize the image
inset<-image_scale(inset, "122x100")
# Use ggarrange to position the 3 maps - using NULL for the inset map
Map3 <- ggarrange(
ggarrange(NULL, map1, nrow = 2, heights=c(0.5,1)),
map2,
ncol= 3)
# Save map as .png with 300dpi resolution
png("Crime_Shoplifting_LA.png", units="in", width=10, height=5.5, res=300)
# Add the inset map in the space left by NULL in ggarrange
Map4 <- ggdraw(Map3) +
draw_image("LA_inset_map.png", scale=0.25, hjust=0.35, vjust=-0.3)
# Annotate the figure - add title, text, data source and authorship information
annotate_figure(Map4,
top = text_grob("Crime Incidents and Shoplifting Density \nin the City of Los Angeles, California 2020/21",
hjust=0.75,face = "bold",
size = 14),
left = text_grob("City of LA, LA County, CA",
size = 6,
face="italic",
vjust=-13, hjust=-2.4),
bottom = text_grob("Crime Data from data.lacity.org and Boundary Data from geohub.lacity.org. Created by Shivani Sickotra, December 2021",
hjust=0.75,
face = "italic",
size = 6))
dev.off()
## png
## 2
include_graphics("Crime_Shoplifting_LA.png")
Copyright © 2007 Free Software Foundation, Inc.