---
title: "COVID-19"
output:
flexdashboard::flex_dashboard:
logo: rbmv_curve.png
orientation: rows
source_code: embed
theme: flatly
---
```{r setup, include=FALSE}
library(flexdashboard)
```
```{r, include=FALSE}
# Packages
library(tidyverse)
library(lubridate)
library(rvest)
library(sf)
library(leaflet)
library(plotly)
library(crosstalk)
library(rbmv)
library(classInt)
# imported functions
`%<>%` <- magrittr::`%<>%`
# adjust depending on when kniting
page_updated <- today()
# create the friendly label for value box
page_updated_string <- str_glue("{wday(page_updated, label = T)} {month(page_updated, label = T)} {day(page_updated)}, {year(page_updated)}")
# custom functions
get_bins <- function(.data, bins = 8) {
#' use kmeans to automatically set sensible bins that represent the data well
#' requires 'classInt' package
#' @return a vector with 8 default bins
intervals <- classIntervals(.data, n = bins, style = "kmeans", rtimes = 5)
return(round(intervals$brks))
}
# API key
mapbox <- read_lines(".mapbox-key")
# grab the html from the dph website
dph_covid19_page <- read_html("http://www.publichealth.lacounty.gov/media/Coronavirus/locations.htm")
# only extract the table tags
dph_covid19_tbls <- dph_covid19_page %>%
html_nodes("table") %>%
html_table()
# just focu on grabbing the locations, cases, and deaths for lb and pass
dph_covid19_messy <- dph_covid19_tbls[[1]] %>%
repair_names() %>%
janitor::clean_names() %>%
rename(locations = x1, total_cases = x2) %>%
select(-x3:-x5)
# what we want to keep
keep <- "Long Beach|Pasadena"
# add the labels so we can 'tidyr::spread' in preparation for a future join
label <- c("cases_final", "cases_final", "deaths_final", "deaths_final")
# save only the lb/pass data
lb_pass <- dph_covid19_messy %>%
filter(str_detect(locations, keep)) %>%
slice(1:4)
# add the labels
lb_pass$label <- label
# now spread and ensure the data types are correct for future join
lb_pass %<>%
spread(label, total_cases) %>%
mutate(
locations = str_replace(locations, "--", "City of"),
cases_final = parse_number(cases_final),
deaths_final = parse_number(deaths_final))
# read the data from the DPH shiny app
data <- read_csv("https://lacdph.shinyapps.io/covid19_surveillance_dashboard/_w_6c4098c3/session/c8a099ca7c06ead4f764f6803e9e75be/download/download2?w=6c4098c3")
# rename and join
dph_covid19 <- data %>%
select(-X1) %>%
rename(locations = geo_merge) %>%
full_join(
.,
lb_pass,
by = c("locations", "cases_final", "deaths_final"))
lac_total_cases <- dph_covid19 %>%
summarise(total_cases = sum(cases_final))
lac_total_deaths <- dph_covid19 %>%
summarise(total_deaths = sum(deaths_final))
# read the gis data
gis <- st_read(
dsn = "data/gis/geo_export_871186bb-3266-4a1c-a0f6-8cda86b55d55.shp",
layer = "geo_export_871186bb-3266-4a1c-a0f6-8cda86b55d55",
quiet = T
)
# make sure the st is set correctly
gis %<>% st_transform(crs = 4326) %>%
mutate(label = as.character.factor(label))
# join to cleaned data
lac_covid19 <- left_join(
dph_covid19,
gis,
by = c("locations" = "label")) %>%
rename(total_cases = cases_final, total_deaths = deaths_final) %>%
st_as_sf()
# get time series data from GitHub
covid19_cases <- read_csv("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_US.csv")
# same as above
covid19_deaths <- read_csv("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_US.csv")
# function to make sure we're getting the most current world data
make_link <- function(date) {
date_format <- format(date, format = "%m-%d-%Y")
link <- str_glue("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/{date_format}.csv")
return(link)
}
# test the link
test_data <- function(date) {
link <- make_link(date)
status <- httr::http_status(httr::GET(link))
return(status$category)
}
# if the link is correct, then get the world data
get_world_data <- function(date) {
if (test_data(date) == "Success") {
return(make_link(date))
} else if (test_data(date) == "Client error") {
return(make_link(date - 1))
}
}
# create link based on today's date
link <- get_world_data(today())
# now read it!
world <- read_csv(link)
world %<>% rename(long = Long_, lat = Lat)
covid19_time_series_cases <- covid19_cases %>%
filter(Admin2 == "Los Angeles") %>%
gather("date", "cases", 12:ncol(covid19_cases)) %>%
select(Admin2, date, cases) %>%
rename(county = Admin2) %>%
mutate(date = parse_date(date, "%m/%d/%y"),
case_type = "New Confirmed Case") %>%
distinct()
covid19_time_series_deaths <- covid19_deaths %>%
filter(Admin2 == "Los Angeles") %>%
gather("date", "cases", 13:ncol(covid19_deaths)) %>%
select(Admin2, date, cases) %>%
rename(county = Admin2) %>%
mutate(date = parse_date(date, "%m/%d/%y"),
case_type = "Death") %>%
distinct()
covid19_time_series <- bind_rows(covid19_time_series_cases, covid19_time_series_deaths)
covid19_cases %<>% mutate(Combined_Key = str_remove(Combined_Key, ", US"))
covid19_cases_top10_us <- covid19_cases %>%
arrange(desc(.[[ncol(covid19_cases)]])) %>%
slice(1:10) %>%
gather("date", "cases", 12:ncol(covid19_cases)) %>%
select(Combined_Key, date, cases) %>%
rename(location = Combined_Key) %>%
mutate(
location = str_remove(location, ", US"),
date = parse_date(date, "%m/%d/%y"),
case_type = "New Confirmed Case") %>%
distinct()
covid19_state_cases <- covid19_cases %>%
filter(iso3 == "USA") %>%
gather("date", "cases", 12:ncol(covid19_cases)) %>%
rename(state = Province_State) %>%
group_by(state, date) %>%
summarise(cases = sum(cases)) %>%
mutate(date = parse_date(date, "%m/%d/%y"))
light_blue <- rbmv_pal("main", plotly = T)[1]
ruby <- rbmv_pal("main", plotly = T)[2]
pale_black <- rbmv_pal("main", plotly = T)[5]
sd <- SharedData$new(covid19_cases_top10_us, ~location, "Select a city")
```
LA County {data-icon="fa-map"}
=====================================
Row {data-height=510}
-------------------------------------
###
```{r}
bins <- get_bins(lac_covid19$total_cases, bins = 12)
pal <- colorBin(
palette = rbmv_pal("spectrum", plotly = T),
domain = lac_covid19$total_cases,
bins = bins)
lac_covid19 %>%
leaflet() %>%
addTiles(mapbox, attribution = paste("Data from Los Angeles County Department of Public Health COVID-19 location table")) %>%
addPolygons(
fillColor = ~pal(total_cases),
weight = 1.5,
fillOpacity = 0.7,
smoothFactor = 0.5,
color = "white",
label = ~str_glue(
"{locations}
Total cases: {scales::comma(total_cases)}
Total deaths: {scales::comma(total_deaths)}
Population: {scales::comma(population)}
") %>%
map(htmltools::HTML),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(
pal = pal, values = ~total_cases, opacity = 0.7,
title = NULL, position = "bottomright") %>%
setView(-118.2, 34, zoom = 9.5)
```
Row {data-height=400}
-------------------------------------
###
```{r}
source <- list(
x = 1, y = -0.25, text = "Source: 2019 Novel Coronavirus COVID-19 (2019-nCoV)\nData Repository by Johns Hopkins CSSE",
showarrow = F, xref = "paper", yref = "paper", xanchor = "right", yanchor = "auto",
xshif = 0, yshift = 0, font = list(size = 12, color = "grey")
)
base <- plot_ly(sd, color = I(rbmv_pal(plotly = T)[6]), height = 320) %>%
group_by(location)
left_bar <- base %>%
add_bars(x = ~cases, y = ~location, hoverinfo = "text",
text = ~paste("Click bar to highlight line
on the left")) %>%
layout(
barmode = "overlay",
xaxis = list(title = ""),
yaxis = list(
title = "",
categoryorder = "max ascending")
)
right_line <- base %>%
add_lines(x = ~date, y = ~cases, alpha = 0.3, hoverinfo = "text",
text = ~paste(" Location: ", location,
" Case type: ", case_type, "x Log Scale",
" Cases: ", scales::comma(cases))) %>%
layout(xaxis = list(title = ""),
yaxis = list(type = "log"))
subplot(left_bar, right_line, titleX = TRUE, widths = c(.3, .7)) %>%
layout(title = "How does Los Angeles County compare to other major outbreak centers",
margin = list(l = 120, b = 40), annotations = source) %>%
hide_legend() %>%
highlight("plotly_click", color = rbmv_pal(plotly = T)[2]) %>%
config(displayModeBar = FALSE)
```
Row {data-height=110}
-------------------------------------
###
```{r}
valueBox(page_updated_string, color = light_blue, icon = "fa-calendar", caption = "Data pulled from both LAC DPH and John Hopkins CSSE")
```
###
```{r}
total_cases <- scales::comma(last(lac_total_cases$total_cases))
valueBox(total_cases, color = ruby, icon = "fa-ambulance", caption = "Total Lab Confirmed COVID-19 Cases in LAC")
```
###
```{r}
total_deaths <- scales::comma(last(lac_total_deaths$total_deaths))
valueBox(total_deaths, color = pale_black, icon = "fa-medkit", caption = "Total COVID-19 Related Deaths")
```
US States {data-icon="fa-chart-line"}
=====================================
###
```{r}
bins <- get_bins(covid19_state_cases$cases, bins = 8)
colors <- RColorBrewer::brewer.pal(9, "YlOrRd")
normalize <- function(x) round((x-min(x))/(max(x)-min(x)), 4)
state_colors <- tibble(range = bins, hex = colors) %>%
mutate(range = normalize(range))
plot_ly(covid19_state_cases) %>%
filter(date >= "2020-03-15") %>%
add_heatmap(x = ~date, y = ~state, z = ~cases,
colorscale = state_colors, xgap = .8,
opacity = .85, showscale = F,
text = ~paste(
"Date: ", date, "
State: ", state,
"
Total confirmed cases: ", scales::comma(cases)),
hoverinfo = "text") %>%
layout(
title = "COVID19 Cases by State",
xaxis = list(title = ""),
yaxis = list(title = "", categoryorder = "max ascending", side = "right")) %>%
config(displayModeBar = FALSE)
```
Global {data-icon="fa-globe"}
=====================================
###
```{r}
bins <- get_bins(world$Confirmed, bins = 12)
pal <- colorBin(
palette = rbmv_pal("warm", plotly = T),
domain = world$Confirmed,
bins = bins)
label <- str_glue("Location: {world$Combined_Key}
Cases: {scales::comma(world$Confirmed)}
Deaths: {scales::comma(world$Deaths)}
Active: {scales::comma(world$Active)}
Recovered: {scales::comma(world$Recovered)}
Last Update: {world$Last_Update}") %>%
lapply(htmltools::HTML)
world %>%
leaflet() %>%
addTiles(mapbox, attribution = paste("Data from Novel Coronavirus (COVID-19) Cases, provided by JHU CSSE")) %>%
addCircleMarkers(
lng = ~long, lat = ~lat,
label = ~label,
color = ~pal(Confirmed),
radius = ~ifelse(Confirmed >= 30000, 25, 15),
stroke = FALSE, fillOpacity = .7,
clusterOptions = markerClusterOptions(
showCoverageOnHover = FALSE),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(title = "COVID-19 Cases", opacity = 0.6, pal = pal, values = ~Confirmed, position = "bottomright")
```