deployed Shiny app: Crime DC - Last 30 Days

data: DC Crime - Last 30 Days Open Data DC


Load needed libraries.

library(dplyr)
library(tidyr)
library(jsonlite)
library(lubridate)
library(leaflet)

Clean and transform data from GeoJSON format into a dataframe

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:

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".

Render the leaflet map

*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()
  ) 

Below are the full ui and server files for the Shiny app

ui.R

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")
                   )
          )
        )

server.R

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()
      ) 
    
  })
}