── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(tidycensus)library(sf)
Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
library(tigris)
To enable caching of data, set `options(tigris_use_cache = TRUE)`
in your R script or .Rprofile.
library(scales)
Attaching package: 'scales'
The following object is masked from 'package:purrr':
discard
The following object is masked from 'package:readr':
col_factor
library(ggplot2)library(terra)
terra 1.9.11
Attaching package: 'terra'
The following object is masked from 'package:scales':
rescale
The following object is masked from 'package:tigris':
blocks
The following object is masked from 'package:tidyr':
extract
library(mapview)
Part 1: Data Acquisition and Context
I choose to do this assignment on Hillsborough county in Florida for multiple reasons:
It is one of the most highly populated counties in the US with over 1.5 million residents as of 2026.
I saw the name Hillsborough and thought of Hillsborough street.
I was actually born in Tampa, which is inside Hillsborough county.
I wanted to investigate th eproportion of elderly people living there. In order to create a 65+ age variable, I had to select all of the variables for people over the age of 65 for both men and women, which was 12 columns in total. Those variables had to be added together and divided by the total population to create a percentage. I also used data from 2019 to 2024 from the ACS dataset.
ggplot(hills_age) +geom_sf(aes(fill = age_percent), color =NA) +scale_fill_viridis_c(option ="D",labels =label_percent(accuracy =1) ) +labs(title ="There is a low percentage of 65+ adults living in Hillsborough, FL",subtitle ="Hillsborough County census tracts, ACS 2019-2024",fill ="% 65+ Years Old",caption ="Source: ACS via tidycensus" ) +theme_void() +theme(plot.title =element_text(face ="bold"),plot.title.position ="plot",legend.position ="right" )
Downloading feature geometry from the Census website. To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
#creating the dots for the maphills_dots <- hills_race |>as_dot_density(value ="estimate",values_per_dot =300,group ="variable" )hills_background <- hills_race |>distinct(GEOID, .keep_all =TRUE)#dot density map ggplot() +geom_sf(data = hills_background,fill ="white",color ="gray80",linewidth =0.1 ) +geom_sf(data = hills_dots,aes(color = variable),size =1,alpha =0.5,show.legend =TRUE ) +scale_color_brewer(palette ="Dark2") +labs(title ="Race/ethnicity dot plot shows a random spread in Hillsborough",subtitle ="Hillsborough County census tracts, one dot = 300 people",color =NULL,caption ="ACS 2024 via tidycensus" ) +theme_void() +theme(plot.title =element_text(face ="bold"),plot.title.position ="plot",legend.position ="right" )
The race density in the county explains the results in the previous map. The population is concentrated in the north and there isn’t much data in the eastern areas, which could explain the lower percentages in the choropleth map.
Part 4: Simple Overlay or Spatial Subset
# Municipal boundaries from tigrisfl_places <-places(state ="FL", cb =TRUE)
Tampa <- fl_places %>%filter(NAME =="Tampa")# Making sure CRS matchesTampa <-st_transform(Tampa, st_crs(hills_age))# Keep tracts that intersect Tampatampa_tracts <-st_filter(hills_age, Tampa, .predicate = st_intersects)ggplot() +geom_sf(data = tampa_tracts, aes(fill = age_percent), color =NA) +geom_sf(data = Tampa, fill =NA, color ="black", linewidth =0.5) +scale_fill_viridis_c(labels =label_percent(accuracy =1)) +labs(title ="Elderly Population (65+) in Tampa Florida",subtitle ="Hillsborough County tracts intersecting the Tampa city boundary",fill ="% Age",caption ="Source: ACS 2024 via tidycensus; boundary via tigris" ) +theme_void() +theme(plot.title =element_text(face ="bold"),plot.title.position ="plot" )
Part 5: Interactive Map
# Create a display version rounded to 3 decimalstampa_tracts_map <- tampa_tracts |>mutate(age_percent_3 =round(age_percent, 3))mapview( tampa_tracts_map,zcol ="age_percent_3",layer.name ="Percent 65+") +mapview( Tampa,alpha.regions = .2,color ="black",lwd =2,layer.name ="Tampa boundary" )
Interactivity allows viewers to investigate specific locations and make comparisons between areas. However, in this map specifically, the squares seem arbitrarily drawn about the city and don’t have any location information.
Part 6: Interpretation
Write three substantive takeaways from your maps. Each takeaway should be 1–2 sentences and should refer to a specific visual pattern.
The choropleth map is really good at visualizing continuous variables.
The dot density plot is a good way to add a categorical variable without faceting, especially contrasting and visually distinct colors.
The interactive map is good for incorporating data labels since the cursor only displays one at a time; unlike how a static map like the choropleth would be overcrowded by labels.