deployed Shiny app: Crime DC - Last 30 Days
data: DC Crime - Last 30 Days Open Data DC
dplyr for distinct(), select(), and mutate() functions.tidyr for the separate() function.jsonlite for the fromJSON() function needed to retrieve our dataset via the GeoJSON api.lubridate for ymd_hms() function to clean datetime column.leaflet to create our map.library(dplyr)
library(tidyr)
library(jsonlite)
library(lubridate)
library(leaflet)
Our data comes in a GeoJSON format. For a good primer on dealing with this and JSON data sources in general, see:
The data source link can be viewed/downloaded here. Note that it is in JSON document/collection format. The jsonlite::fromJSON() function retrieves the from the collection format it exists in and stores it in list format in the variable defined dccrimejsonlite.
We access the list elements which are nested within the features level, and then combine these two large lists:
properties which contain the main table elements for the dataset.geometry list which contains the latitude and longitude columns which we will need to map the data.Using the cbind function, we combine these two lists into a dataframe defined as dc_crime_json.
#Note that library jsonlite is loaded in the setup code chunk above
########---------------------------------------------------------------------#>>>
## Retrieve the data in JSON format from opendata.dc.gov using fromJson()
dccrimejsonlite <- fromJSON('http://opendata.dc.gov/datasets/dc3289eab3d2400ea49c154863312434_8.geojson')
## use cbind() combine the list elements and create a dataframe
dc_crime_json <- cbind(dccrimejsonlite$features$properties,dccrimejsonlite$features$geometry)
## Seperate and clean lat/long columns but keep original datetime column
## --also separate REPORTDATETIME column
dc_crime_clean <- dc_crime_json %>%
separate(coordinates, into = c("X", "Y"), sep = ",")%>%
separate(REPORTDATETIME, into = c("Date","Time"), sep="T", remove = FALSE)%>%
mutate(Weekday = weekdays(as.Date(REPORTDATETIME)),
DATETIME = ymd_hms(REPORTDATETIME, tz='America/New_York'),
Date = as.Date(Date),
X = as.numeric(gsub("c\\(","",X)),
Y = as.numeric(gsub("\\)","",Y)))
## Date in ISO8601 format; converting timezone from UTC to "America/New_York".
*Define a points element with the latitude and longitude vectors corresponding to the dataframe.
points <- cbind(dc_crime_clean$X,dc_crime_clean$Y)
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik",
options = providerTileOptions(noWrap = TRUE)
) %>%
addMarkers(data = points,
popup = paste0("<strong>Report Date: </strong>",
dc_crime_clean$DateClean,
"<br><strong>Offense: </strong>",
dc_crime_clean$OFFENSE,
"<br><strong>method: </strong>",
dc_crime_clean$METHOD,
"<br><strong>shift: </strong>",
dc_crime_clean$SHIFT,
"<br><strong>blocksite address: </strong><br>",
dc_crime_clean$BLOCKSITEADDRESS
),
clusterOptions = markerClusterOptions()
)
library(shiny)
library(shinythemes)
library(leaflet)
fluidPage(theme = shinytheme("cerulean"),
tags$head(
# Include our custom CSS
#includeCSS("style.css")
),
navbarPage("Crime DC",id='nav',
tabPanel("Interactive Map",
fluidRow(
column(4,plotOutput("plotOffense",height=300)),
column(4,plotOutput("plotDay",height=300)),
column(4,plotOutput("plotShift",height=300))
),
leafletOutput("mymap", width = '100%', height = '600px'),
br(),
absolutePanel(id = "controls",class = "panel panel-default", fixed = TRUE, draggable = TRUE,
top = 500, left = "auto", right = 20, bottom = "auto",
width = 330, height = "auto", style = "opacity: .75",
h2("Crime DC - Last 30 Days"),
paste("Click on cluster or scroll to zoom-in, Click an individual marker for additional detail popup."),
a("data source: http://opendata.dc.gov/datasets",href="http://opendata.dc.gov/datasets"),
br(),
a("author: neil kutty", href="http:/twitter.com/neilkutty"),
a("github",href="https://github.com/sampsonsimpson/DC_Crime_Data")
)
),
tabPanel("Data Explorer",
dataTableOutput("table1")
)
)
)
library(ggplot2)
library(leaflet)
library(dplyr)
library(tidyr)
library(jsonlite)
library(curl)
library(lubridate)
########---------------------------------------------------------------------#>>>
## Retrieve the data in JSON format from opendata.dc.gov using fromJson()
dccrimejsonlite <- fromJSON('http://opendata.dc.gov/datasets/dc3289eab3d2400ea49c154863312434_8.geojson')
## use cbind() combine the list elements and create a dataframe
dc_crime_json <- cbind(dccrimejsonlite$features$properties,dccrimejsonlite$features$geometry)
## Get distinct Offenses for shiny input
offenses <- distinct(select(dc_crime_json,OFFENSE))
row.names(offenses) <- offenses$OFFENSE
## Seperate and clean lat/long columns but keep original datetime column
## --also separate REPORTDATETIME column
dc_crime_clean <- dc_crime_json %>%
separate(coordinates, into = c("X", "Y"), sep = ",")%>%
separate(REPORTDATETIME, into = c("Date","Time"), sep="T", remove = FALSE)%>%
mutate(Weekday = weekdays(as.Date(REPORTDATETIME)),
DATETIME = ymd_hms(REPORTDATETIME, tz='America/New_York'),
Date = as.Date(Date),
X = as.numeric(gsub("c\\(","",X)),
Y = as.numeric(gsub("\\)","",Y)))
#Shiny server
function(input, output, session) {
filterData <- reactive({
if (is.null(input$mymap_bounds))
return(dc_crime_clean)
bounds <- input$mymap_bounds
latRng <- range(bounds$north, bounds$south)
lngRng <- range(bounds$east, bounds$west)
filter(dc_crime_clean,
Y >= latRng[1] & Y <= latRng[2] & X >= lngRng[1] & X <= lngRng[2])
})
output$plotOffense <-
renderPlot({
off <- as.data.frame(table(filterData()$OFFENSE))
off$Freq <- as.numeric(off$Freq)
off$Var1 <- factor(off$Var1)
colnames(off) <- c("OFFENSE","COUNT")
ggplot(off, aes(x=OFFENSE,y=COUNT)) +
geom_bar(stat="identity",alpha = 0.3,color='red',fill='red') +
ggtitle("Number of Crimes by Offense") +
geom_text(aes(label = off$COUNT), size = 5.5, hjust = .77, color = "black")+
coord_flip()+
theme(axis.title=element_text(size=10),
axis.text.x = element_text(face = 'bold', size=10, hjust = 1)
)
})
output$plotDay <-
renderPlot({
day <- as.data.frame(table(filterData()$Weekday))
day$Freq <- as.numeric(day$Freq)
colnames(day) <- c("Weekday","COUNT")
day$Weekday <- factor(day$Weekday, levels= c("Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"))
day[order(day$Weekday),]
ggplot(day, aes(x=Weekday,y=COUNT)) +
geom_bar(stat="identity",alpha = 0.3,color = 'blue', fill='blue') +
ggtitle("Number of Crimes by Day of Week") +
geom_text(aes(label = day$COUNT), size = 5.5, hjust = .77, color = "black")+
theme(axis.title=element_text(size=10),
axis.text.x = element_text(face = 'bold', size=10, angle = 45, hjust = 1)
)
})
output$plotShift<-
renderPlot({
Shift <- as.data.frame(table(filterData()$SHIFT))
Shift$Freq <- as.numeric(Shift$Freq)
colnames(Shift) <- c("Time Of Day","COUNT")
Shift$`Time Of Day` <- factor(Shift$`Time Of Day`, levels=c('DAY','EVENING','MIDNIGHT'))
Shift[order(Shift$`Time Of Day`),]
ggplot(Shift, aes(x=`Time Of Day`,y=COUNT)) +
geom_bar(stat="identity",alpha = 0.3,color = 'orange', fill='orange') +
ggtitle("Number of Crimes by Shift") +
geom_text(aes(label = Shift$COUNT), size = 5.5, hjust = .77, color = "black")+
theme(axis.title=element_text(size=10),
axis.text.x = element_text(face = 'bold', size=10, angle = 45, hjust = 1)
)
})
output$table1 <-
renderDataTable(options=list(pageLength=25),{
filterData()%>%
select(Weekday, SHIFT, DATETIME, BLOCKSITEADDRESS, OFFENSE, METHOD, OBJECTID)
})
points <- eventReactive(input$reset, {
cbind(dc_crime_clean$X,dc_crime_clean$Y)
}, ignoreNULL = FALSE)
output$mymap <- renderLeaflet({
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik",
options = providerTileOptions(noWrap = TRUE)
) %>%
addMarkers(data = points(),
popup = paste0("<strong>Report Date: </strong>",
dc_crime_clean$DateClean,
"<br><strong>Offense: </strong>",
dc_crime_clean$OFFENSE,
"<br><strong>method: </strong>",
dc_crime_clean$METHOD,
"<br><strong>shift: </strong>",
dc_crime_clean$SHIFT,
"<br><strong>blocksite address: </strong><br>",
dc_crime_clean$BLOCKSITEADDRESS
),
clusterOptions = markerClusterOptions()
)
})
}