#Load packages
library(plotly) #Graphing library for making interactive, publication quality graphs
library(ggiraph) #Create dynamic ggplot graphs
library(tidycensus) #Allows users to download Census data and return tidyverse ready data frames
library(viridisLite) #Color maps designed to improve graph readability for common forms of color blindness
library(scales) #Provides methods for automatically determining breaks and labels for axes and legends
library(units) #Support for measurement units in R
library(tigris) #Load Census TIGER/Line shapefiles
library(mapview) #Create interactive visualizations of spatial data
library(gt) #Create customizable tables
library(dplyr) #Tool for working with data frame objects
library(tidyverse) #Series of packages used in common analysis tasks
Dr. Ron Jarmin, Deputy Director of the United States Census Bureau, described geography as “one of the cornerstones of every census and survey” they conduct (2019). Similarly, many geographers rely on data collected by the United States Census Bureau. Data collected through the Decennial Census or the American Community Survey (ACS), which includes information on various topics ranging from race, gender, and household income to veteran status, internet usage, and drivetime to work often forms the foundation for geographic research and analysis. Although this data is made freely available to the public, it can be difficult to work with. Locating the particular table containing the variable(s) you want through the Census Bureau’s website can be confusing and, particularly for geographic research, there are typically several additional steps required to prepare the census datasets for import into GIS programs. The tidycensus package, created for R by Dr. Kyle Walker, solves those issues by providing an intuitive method for retrieving census data and delivering it in a ready to use format.
This report uses the tidycensus, plotly, mapview, ggplot, and other R packages to explore, plot, and map ACS data. Part A of this report will explore the percentage of the population with graduate degrees, by county, for the State of Nevada. Part B will map the percentage of the population, at a county level, of the main demographic for National Hoceky League Fans: white males over the age of 35.
Typically, acquiring data from the U.S. Census Bureau website required sifting through multiple tables to find the information you needed, preproccessing the data outside of your GIS program to clean up any null entries or values which might cause errors during processing, and creating a custom field to join to the appropriate census geography shapefile. While Part A of this lab does not require spatial objects, tidycensus handles that task, as well as the others, easily.
#Pull data from the Census Bureau on the percentage of the population with a graduate degree within Michigan, at the county level
GradDegreeMI <- get_acs(
geography = "county",
variables=c(
GradDegreePct="DP02_0066P"), #Rename census variable code to a more memorable field heading
state="MI",
year=2021
)
GradDegreeMIFormat <- GradDegreeMI %>%
separate(NAME, c("County","state"),sep=", ")%>% #Split name field into county and state
select(County, estimate,moe,GEOID)%>%
mutate(estimate= estimate/100)
Part A focuses on answering two questions: which counties have the highest and lowest percentages of people with graduate school degrees, and then plotting the data, along with the margin of error for each county on an interactive chart.
First, what are the top 3 counties in terms of population with a graduate degree in the State of Michigan?
#Create a list of the top 3 counties in terms of population with a graduate degree
topGrad <- GradDegreeMIFormat %>%
arrange(desc(estimate))
top3<-gt(head(topGrad,3))%>%
fmt_percent(columns=estimate, #Format the column as a percentage field
decimals=2)
top3
| County | estimate | moe | GEOID |
|---|---|---|---|
| Washtenaw County | 30.30% | 0.7 | 26161 |
| Oakland County | 21.30% | 0.3 | 26125 |
| Leelanau County | 19.60% | 1.6 | 26089 |
Washtenaw and Oakland Counties are homes to two prominent universities (the blech University of Michigan and Oakland University). Washtenaw County contains Ann Arbor, a city offering many high-paying, white collar jobs requiring graduate level degrees. Oakland County likely benefits from the large number of white collar workers residing within the county and commuting into nearby Detroit. Leelanau County does not boast a highly educated labor force but is an attractive retirement community for wealthier individuals.
What are the bottom 3 counties in terms of population with a graduate degree in the State of Michigan?
#Create a list of the bottom 3 counties in terms of population with a graduate degree
bottomGrad <- GradDegreeMIFormat %>%
arrange(estimate)
bottom3<-gt(head(bottomGrad,3))%>%
fmt_percent(columns=estimate, #Format the column as a percentage field
decimals=2)
bottom3
| County | estimate | moe | GEOID |
|---|---|---|---|
| Lake County | 3.70% | 0.7 | 26085 |
| Montcalm County | 4.30% | 0.6 | 26117 |
| Ionia County | 4.40% | 0.6 | 26067 |
Lake, Montcalm, and Ionia Counties are all predominantly rural areas.
#Use the GGIRAPH package to add additional interactivity to the chart
MI_GradDegree_Interactive <- ggplot(GradDegreeMIFormat, aes(
x=estimate,
y=reorder(County,estimate),
tooltip = estimate))+
geom_errorbar(aes(xmin = estimate - moe, xmax = estimate + moe),
width=0.25, linewidth=0.5)+
geom_point_interactive(color="darkred", size=2)+
scale_x_continuous(labels=label_percent(scale=1))+
scale_y_discrete()+
labs(title= "Percent Population with Graduate Degree",
subtitle = "Counties in Michigan",
caption="Data acquired with R and tidycensus. Error bars represent margin of error around estimates.",
x= "ACS Estimate",
y="")+
theme_minimal()+
theme(axis.text.y = element_text(angle=45, hjust=1), #Rotate the angle of the labels
plot.margin=margin(t=0, r=0, b=1, l=1, "cm")) #Adjust margins
girafe(ggobj = MI_GradDegree_Interactive) %>%
girafe_options((opts_hover(css = "fill:cyan;")))
This is not an effective option for graphing this data because I could not figure out how to space out the y axis.
For this section, I am looking at the percentage of the population that makes up one of the key demographics for NHL fans: white males over the age of 35. I will be exploring this data at the county level for the state of Kansas.
NHL_Demos <- get_acs(
geography="county",
variables=c(total_pop = "B01001_001", #Total Population
wm_35_44 = "B01001A_011", #White males between 35 and 44
wm_45_54 = "B01001A_012", #White males between 45 and 54
wm_55_64 = "B01001A_013", #White males between 55 and 64
wm_65_74 = "B01001A_014", #White males between 65 and 74
wm_75_84 = "B01001A_015", #White males between 75 and 84
wm_o85 = "B01001A_016"), #White males over 85
year= 2021,
geometry=TRUE, #Include spatial objects
state="KS",
survey= "acs5")
## | | | 0% | | | 1% | |= | 1% | |= | 2% | |== | 2% | |== | 3% | |=== | 4% | |=== | 5% | |==== | 5% | |==== | 6% | |===== | 7% | |===== | 8% | |====== | 8% | |====== | 9% | |======= | 10% | |======= | 11% | |======== | 11% | |======== | 12% | |========= | 12% | |========= | 13% | |========== | 14% | |========== | 15% | |=========== | 15% | |=========== | 16% | |============ | 17% | |============ | 18% | |============= | 18% | |============= | 19% | |============== | 19% | |============== | 20% | |============== | 21% | |=============== | 21% | |=============== | 22% | |================ | 22% | |================ | 23% | |================ | 24% | |================= | 24% | |================= | 25% | |================== | 25% | |================== | 26% | |=================== | 26% | |=================== | 27% | |=================== | 28% | |==================== | 28% | |==================== | 29% | |===================== | 29% | |===================== | 30% | |===================== | 31% | |====================== | 31% | |====================== | 32% | |======================= | 32% | |======================= | 33% | |======================== | 34% | |======================== | 35% | |========================= | 35% | |========================= | 36% | |========================== | 37% | |========================== | 38% | |=========================== | 38% | |=========================== | 39% | |============================ | 39% | |============================ | 40% | |============================ | 41% | |============================= | 41% | |============================= | 42% | |============================== | 42% | |============================== | 43% | |============================== | 44% | |=============================== | 44% | |=============================== | 45% | |================================ | 45% | |================================ | 46% | |================================= | 47% | |================================= | 48% | |================================== | 48% | |================================== | 49% | |=================================== | 49% | |=================================== | 50% | |=================================== | 51% | |==================================== | 51% | |==================================== | 52% | |===================================== | 52% | |===================================== | 53% | |====================================== | 54% | |====================================== | 55% | |======================================= | 55% | |======================================= | 56% | |======================================== | 56% | |======================================== | 57% | |======================================== | 58% | |========================================= | 58% | |========================================= | 59% | |========================================== | 59% | |========================================== | 60% | |========================================== | 61% | |=========================================== | 61% | |=========================================== | 62% | |============================================ | 62% | |============================================ | 63% | |============================================= | 64% | |============================================= | 65% | |============================================== | 65% | |============================================== | 66% | |=============================================== | 67% | |=============================================== | 68% | |================================================ | 68% | |================================================ | 69% | |================================================= | 69% | |================================================= | 70% | |================================================= | 71% | |================================================== | 71% | |================================================== | 72% | |=================================================== | 72% | |=================================================== | 73% | |==================================================== | 74% | |==================================================== | 75% | |===================================================== | 75% | |===================================================== | 76% | |====================================================== | 77% | |====================================================== | 78% | |======================================================= | 78% | |======================================================= | 79% | |======================================================== | 79% | |======================================================== | 80% | |======================================================== | 81% | |========================================================= | 81% | |========================================================= | 82% | |========================================================== | 82% | |========================================================== | 83% | |=========================================================== | 84% | |=========================================================== | 85% | |============================================================ | 85% | |============================================================ | 86% | |============================================================= | 87% | |============================================================= | 88% | |============================================================== | 88% | |============================================================== | 89% | |=============================================================== | 89% | |=============================================================== | 90% | |=============================================================== | 91% | |================================================================ | 91% | |================================================================ | 92% | |================================================================= | 92% | |================================================================= | 93% | |================================================================== | 94% | |================================================================== | 95% | |=================================================================== | 95% | |=================================================================== | 96% | |==================================================================== | 97% | |==================================================================== | 98% | |===================================================================== | 98% | |===================================================================== | 99% | |======================================================================| 99% | |======================================================================| 100%
colnames(NHL_Demos)[3]="CensusData" #Rename variable to CensusData
NHL_DemosFormat <- NHL_Demos %>%
select(GEOID,NAME,CensusData,estimate)%>%
pivot_wider(names_from = CensusData, values_from = estimate)%>%
mutate(ofAgeMen= wm_35_44 + wm_45_54 + wm_55_64 + wm_65_74 + wm_75_84 + wm_o85)%>%
mutate(ofAgeMenPct = percent((ofAgeMen/total_pop),accuracy=.01))%>%
mutate(ofAgeMenPct = gsub("%$","",ofAgeMenPct))%>%
mutate(ofAgeMenPct = as.numeric(ofAgeMenPct))%>%
select(GEOID,NAME,total_pop, ofAgeMen, ofAgeMenPct,geometry)
colors <- rocket(n=100)
mapview(NHL_DemosFormat, zcol="ofAgeMenPct",
layer.name="Pct White Males Over 35<br/>2017-2021 ACS",
col.regions=colors)
## Warning: Found less unique colors (100) than unique zcol values (103)!
## Interpolating color vector to match number of zcol values.
The mapview package provides a quick method for creating interactive maps of spatial data; however, the documentation for the package does not provide a sufficient level of detail for customizing display of the map.
gg <- ggplot(NHL_DemosFormat, aes(fill=ofAgeMenPct, data_id=GEOID,
tooltip=paste0(NAME,"<br>",ofAgeMenPct,"%")))+
geom_sf_interactive()+
scale_fill_viridis_c(option="plasma")+
theme_void()+
labs(fill="Pct White Males Over 35\n2017-2021 ACS")
girafe(ggobj=gg)%>%
girafe_options(opts_hover(css="fill:cyan;"))
Figure 2. While the Mapview package used to create the previous map may be easier to use, the ggplot and ggiraph packages (used to create this map) allow for greater customization.
The original analysis covered the entirety of the United States and was intended to locate areas with high concentrations of “core NHL fans” where the league might want to consider expanding with a new franchise; however, after investigating several errors, I determined that a likely cause of my problems was trying to download too much data from the Census bureau website and so chose to use only the State of Kansas.
Jarmin, R. (2019). Using GIS Technology in the 2020 Census. United States Census Bureau. https://www.census.gov/newsroom/blogs/random-samplings/2019/02/using_gis_technology.html. Retrieved on April 1, 2024.