library(tidyverse)
library(tidyr)
library(leaflet)
cities500 <- read_csv("500CitiesLocalHealthIndicators.cdc.csv")Healthy Cities GIS Assignment
Load the libraries and set the working directory
The GeoLocation variable has (lat, long) format
Split GeoLocation into two columns: lat and long.
latlong <- cities500 |>
mutate(GeoLocation = str_replace_all(GeoLocation, "[()]", "")) |>
separate(
GeoLocation,
into = c("lat", "long"),
sep = ",",
convert = TRUE
)
head(latlong)# A tibble: 6 × 25
Year StateAbbr StateDesc CityName GeographicLevel DataSource Category
<dbl> <chr> <chr> <chr> <chr> <chr> <chr>
1 2017 CA California Hawthorne Census Tract BRFSS Health Outcom…
2 2017 CA California Hawthorne City BRFSS Unhealthy Beh…
3 2017 CA California Hayward City BRFSS Health Outcom…
4 2017 CA California Hayward City BRFSS Unhealthy Beh…
5 2017 CA California Hemet City BRFSS Prevention
6 2017 CA California Indio Census Tract BRFSS Health Outcom…
# ℹ 18 more variables: UniqueID <chr>, Measure <chr>, Data_Value_Unit <chr>,
# DataValueTypeID <chr>, Data_Value_Type <chr>, Data_Value <dbl>,
# Low_Confidence_Limit <dbl>, High_Confidence_Limit <dbl>,
# Data_Value_Footnote_Symbol <chr>, Data_Value_Footnote <chr>,
# PopulationCount <dbl>, lat <dbl>, long <dbl>, CategoryID <chr>,
# MeasureId <chr>, CityFIPS <dbl>, TractFIPS <dbl>, Short_Question_Text <chr>
Filter the dataset
The assignment asks us to remove the United States, use crude prevalence, select 2017, Connecticut, and the Unhealthy Behaviors category.
latlong_clean <- latlong |>
filter(StateDesc != "United States") |>
filter(Data_Value_Type == "Crude prevalence") |>
filter(Year == 2017) |>
filter(StateAbbr == "CT") |>
filter(Category == "Unhealthy Behaviors")
head(latlong_clean)# A tibble: 6 × 25
Year StateAbbr StateDesc CityName GeographicLevel DataSource Category
<dbl> <chr> <chr> <chr> <chr> <chr> <chr>
1 2017 CT Connecticut Bridgeport Census Tract BRFSS Unhealthy B…
2 2017 CT Connecticut Danbury City BRFSS Unhealthy B…
3 2017 CT Connecticut Norwalk Census Tract BRFSS Unhealthy B…
4 2017 CT Connecticut Bridgeport Census Tract BRFSS Unhealthy B…
5 2017 CT Connecticut Hartford Census Tract BRFSS Unhealthy B…
6 2017 CT Connecticut Waterbury Census Tract BRFSS Unhealthy B…
# ℹ 18 more variables: UniqueID <chr>, Measure <chr>, Data_Value_Unit <chr>,
# DataValueTypeID <chr>, Data_Value_Type <chr>, Data_Value <dbl>,
# Low_Confidence_Limit <dbl>, High_Confidence_Limit <dbl>,
# Data_Value_Footnote_Symbol <chr>, Data_Value_Footnote <chr>,
# PopulationCount <dbl>, lat <dbl>, long <dbl>, CategoryID <chr>,
# MeasureId <chr>, CityFIPS <dbl>, TractFIPS <dbl>, Short_Question_Text <chr>
What variables are included?
names(latlong_clean) [1] "Year" "StateAbbr"
[3] "StateDesc" "CityName"
[5] "GeographicLevel" "DataSource"
[7] "Category" "UniqueID"
[9] "Measure" "Data_Value_Unit"
[11] "DataValueTypeID" "Data_Value_Type"
[13] "Data_Value" "Low_Confidence_Limit"
[15] "High_Confidence_Limit" "Data_Value_Footnote_Symbol"
[17] "Data_Value_Footnote" "PopulationCount"
[19] "lat" "long"
[21] "CategoryID" "MeasureId"
[23] "CityFIPS" "TractFIPS"
[25] "Short_Question_Text"
Remove the variables that will not be used
latlong_clean2 <- latlong_clean |>
select(
-DataSource,
-Data_Value_Unit,
-DataValueTypeID,
-Low_Confidence_Limit,
-High_Confidence_Limit,
-Data_Value_Footnote_Symbol,
-Data_Value_Footnote
)
head(latlong_clean2)# A tibble: 6 × 18
Year StateAbbr StateDesc CityName GeographicLevel Category UniqueID Measure
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 2017 CT Connecticut Bridgep… Census Tract Unhealt… 0908000… Obesit…
2 2017 CT Connecticut Danbury City Unhealt… 918430 Obesit…
3 2017 CT Connecticut Norwalk Census Tract Unhealt… 0955990… Obesit…
4 2017 CT Connecticut Bridgep… Census Tract Unhealt… 0908000… Curren…
5 2017 CT Connecticut Hartford Census Tract Unhealt… 0937000… Obesit…
6 2017 CT Connecticut Waterbu… Census Tract Unhealt… 0980000… Obesit…
# ℹ 10 more variables: Data_Value_Type <chr>, Data_Value <dbl>,
# PopulationCount <dbl>, lat <dbl>, long <dbl>, CategoryID <chr>,
# MeasureId <chr>, CityFIPS <dbl>, TractFIPS <dbl>, Short_Question_Text <chr>
The cleaned dataset is now manageable for the investigation.
Step 1: Create my own subset
For my investigation, I chose to study current smoking prevalence in Connecticut in 2017. I filtered the cleaned dataset to keep only the Current Smoking measure.
# Keep only observations about current smoking
smoking_ct <- latlong_clean2 |>
filter(Short_Question_Text == "Current Smoking")
head(smoking_ct)# A tibble: 6 × 18
Year StateAbbr StateDesc CityName GeographicLevel Category UniqueID Measure
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 2017 CT Connecticut Bridgep… Census Tract Unhealt… 0908000… Curren…
2 2017 CT Connecticut Waterbu… Census Tract Unhealt… 0980000… Curren…
3 2017 CT Connecticut New Bri… Census Tract Unhealt… 0950370… Curren…
4 2017 CT Connecticut Bridgep… Census Tract Unhealt… 0908000… Curren…
5 2017 CT Connecticut Hartford Census Tract Unhealt… 0937000… Curren…
6 2017 CT Connecticut Waterbu… Census Tract Unhealt… 0980000… Curren…
# ℹ 10 more variables: Data_Value_Type <chr>, Data_Value <dbl>,
# PopulationCount <dbl>, lat <dbl>, long <dbl>, CategoryID <chr>,
# MeasureId <chr>, CityFIPS <dbl>, TractFIPS <dbl>, Short_Question_Text <chr>
Check the number of observations.
# The assignment requires no more than 900 observations
nrow(smoking_ct)[1] 228
The subset contains 228 observations, which is below the assignment limit of 900 observations.
Step 2: Create a plot
I created a histogram to show the distribution of current smoking prevalence.
ggplot(smoking_ct, aes(x = Data_Value)) +
geom_histogram(
bins = 15,
na.rm = TRUE
) +
labs(
title = "Current Smoking Prevalence in Connecticut",
subtitle = "2017 CDC 500 Cities Data",
x = "Current Smoking Prevalence (%)",
y = "Number of Observations"
) +
theme_minimal()Step 3: Create a map
The map shows the geographic locations of the observations in the Current Smoking subset.
leaflet(smoking_ct) |>
setView(
lng = -72.7,
lat = 41.6,
zoom = 8
) |>
addProviderTiles("Esri.WorldStreetMap") |>
addCircles(
data = smoking_ct,
lng = ~long,
lat = ~lat,
radius = ~sqrt(Data_Value) * 1000,
fillOpacity = 0.5,
stroke = TRUE
)Step 4: Refine the map with a mouse-click tooltip
The popup shows more information when a point is clicked.
popup_smoking <- paste0(
"<b>City:</b> ", smoking_ct$CityName,
"<br><b>Geographic Level:</b> ", smoking_ct$GeographicLevel,
"<br><b>Year:</b> ", smoking_ct$Year,
"<br><b>Measure:</b> ", smoking_ct$Short_Question_Text,
"<br><b>Smoking Prevalence:</b> ",
round(smoking_ct$Data_Value, 1), "%"
)
leaflet(smoking_ct) |>
setView(
lng = -72.7,
lat = 41.6,
zoom = 8
) |>
addProviderTiles("Esri.WorldStreetMap") |>
addCircles(
data = smoking_ct,
lng = ~long,
lat = ~lat,
radius = ~sqrt(Data_Value) * 1000,
fillOpacity = 0.5,
stroke = TRUE,
popup = popup_smoking
)Step 5: Describe the plots
The histogram shows the distribution of current smoking prevalence in the Connecticut observations from 2017. The values range from 8.2% to 30.9%, so there is a noticeable difference between the lower and higher observations. The map shows where the observations are located across Connecticut. The circles make it possible to see the geographic pattern of the data, and larger circles represent higher smoking prevalence. When I click on a circle, the popup shows the city, geographic level, year, measure, and smoking prevalence. Overall, the histogram helps me understand the distribution of smoking prevalence, while the map helps me see where the observations are located.