Project 2

Author

Christian Estrada

In this project, I will be examining the average income per capita in Maryland based on its counties and eight congressional districts spanning from 2013-2023. I chose this subject due to my interest in economics and to study the income per capita in my home state to gain a better understanding of the general economic climate in the area I live in. The data I will be using comes from the Maryland Open Data portal, which contains a csv file containing all the necessary data I needed, cleaning up was not needed for the data set to be functional with my project. The quantitative variables I will be using will be the income (base income per year, not average), span of years and average income. The qualitative variables I will be using will be the counties and districts. I will be representing this data by creating a line plot containing all the counties within Maryland and their average income, and then I will create two different interactive maps using the leaflet package that show each district and each counties average income from 2013-2023. The first visualization shows the trend of income in each county spanning from 2013-2023, I noticed that Montgomery county started as the highest earning county and continued that trend throughout the entire span of the given time frame (reaching the thresh-hold of $100,000), being followed by Talbot county which had a sharp increase in income during mid-2017. Somerset county maintained the lowest income trend throughout the graph and was at a lower point in 2023 than it was in 2022. The first map is representative of Maryland’s 8 congressional districts, and is measured by the average income per capita of those 8 districts from 2013-2023. District 3 holds the highest average income at $68,994 while district 6 holds the lowest income at $48,440. Considering how low these averages are, it makes me consider how the average person in each of these districts manage to get by in a modern day society where typically much more money is needed to sustain themselves. The final map goes back to representing the counties, but instead is the average overall from the 2013-2023 period, rather than a trend. As to be expected, Montgomery County held the highest average at $84,003 and maintaining the trend from the original graph Somerset county held the lowest average income at $32,387, more than $50,000 less than Montgomery county. I especially have concern for Somerset county given this trend as I would have to assume its a more poverty stricken area of Maryland. What I wish I could have shown would be outlinig the counties and districts in a more geographical manner rather than circles, but I did not have a complete understanding of how to code that. The dataset I used came from Maryland Open Source: Maryland Per Capita Personal Income (Current Dollars): 2013-2023 | Open Data | https://opendata.maryland.gov/Demographic/Maryland-Per-Capita-Personal-Income-Current-Dollar/nv7y-8663/about_data

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.2     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.1.0     
── 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(tidyr)
library(leaflet)
Warning: package 'leaflet' was built under R version 4.5.2
setwd("C:/Users/chris/Downloads/DATA 110")
income <- read_csv ("Maryland_Per_Capita_Personal_Income__Current_Dollars___2013-2023.csv")
Rows: 11 Columns: 29
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (3): Date created, Reporting period start date, Reporting period end data
dbl (26): Year, MARYLAND, Allegany County, Anne Arundel County, Baltimore Ci...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
names(income)
 [1] "Date created"                "Reporting period start date"
 [3] "Reporting period end data"   "Year"                       
 [5] "MARYLAND"                    "Allegany County"            
 [7] "Anne Arundel County"         "Baltimore City"             
 [9] "Baltimore County"            "Calvert County"             
[11] "Caroline County"             "Carroll County"             
[13] "Cecil County"                "Charles County"             
[15] "Dorchester County"           "Frederick County"           
[17] "Garrett County"              "Harford County"             
[19] "Howard County"               "Kent County"                
[21] "Montgomery County"           "Prince George's County"     
[23] "Queen Anne's County"         "Somerset County"            
[25] "St. Mary's County"           "Talbot County"              
[27] "Washington County"           "Wicomico County"            
[29] "Worcester County"           
income_long <- income |>
  select(Year, where(is.numeric)) |>
  pivot_longer(
    cols = -Year,
    names_to = "County",
    values_to = "Income"
  ) |>
  filter(County != "MARYLAND") |>
  mutate(Year = as.numeric(Year))

latest_income <- income_long |>
  filter(Year == max(Year))   

Maryland Average Per-Capita Income (2013-2023) Line-plot (By County)

ggplot(income_long, aes(x = Year, y = Income, color = County)) +
  geom_line(linewidth = 1.1) +
  theme_bw() +
  scale_y_continuous(
  ) +
  labs(
    title = "Maryland Per-Capita Income (2013–2023)",
    y = "Income (USD)",
    caption = "Source: Maryland Open Data Portal"
  )

district_lookup <- tibble(
  County = c(
    "Baltimore County", "Caroline County", "Cecil County", "Dorchester County",
    "Harford County", "Kent County", "Queen Anne's County", "Somerset County",
    "Talbot County", "Wicomico County", "Worcester County",

    "Baltimore County", "Carroll County",

    "Howard County", "Anne Arundel County", "Carroll County",

    "Montgomery County", "Prince George's County",

    "Anne Arundel County", "Calvert County", "Charles County",
    "Prince George's County", "St. Mary's County",

    "Allegany County", "Garrett County", "Washington County",
    "Frederick County", "Montgomery County",

    "Baltimore City", "Baltimore County",

    "Montgomery County", "Prince George's County"
  ),
  CongressionalDistrict = c(
    rep(1, 11),
    rep(2, 2),
    rep(3, 3),
    rep(4, 2),
    rep(5, 5),
    rep(6, 4),
    rep(7, 3),
    rep(8, 2)
  )
)
income_with_cd <- income_long |>
  left_join(district_lookup, by = "County")
Warning in left_join(income_long, district_lookup, by = "County"): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 2 of `x` matches multiple rows in `y`.
ℹ Row 24 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
  "many-to-many"` to silence this warning.
district_income <- income_with_cd |>
  group_by(CongressionalDistrict) |>
  summarise(
    AvgIncome = mean(Income, nona = TRUE)
  )
district_coords <- tibble(
  CongressionalDistrict = 1:8,
  lat = c(38.6, 39.4, 39.2, 38.9, 38.4, 39.6, 39.3, 39.0),
  lon = c(-75.9, -76.8, -76.7, -76.7, -76.6, -77.5, -76.6, -77.1)
)
district_map <- district_income |>
  left_join(district_coords, by = "CongressionalDistrict")

Maryland Average Per-Capita Income (2013-2023) By Congressional District

pal_c <- colorNumeric(
  palette = c("#ffffcc", "#a1dab4", "#41b6c4", "#2c7fb8", "#253494"),
  domain = district_map$AvgIncome
)

leaflet(district_map) |>
  addTiles() |>
  addCircleMarkers(
    ~lon, ~lat,
    radius = ~AvgIncome / 1500,
    fillColor = ~pal_c(AvgIncome),
    fillOpacity = 0.8,
    color = "black",
    weight = 1,
    label = ~paste0(
      "District ", CongressionalDistrict,
      " Avg Income 2013–2023: $", round(AvgIncome, 0)
    ),
    popup = ~paste0(
      "<strong>District ", CongressionalDistrict, "</strong><br>",
      "Avg Per-Capita Income (2013–2023): $", round(AvgIncome, 0), "<br><br>",
      "<strong>Counties:</strong><br>",
      paste(
        income_with_cd$County[
          income_with_cd$CongressionalDistrict == CongressionalDistrict
        ],
        collapse = "<br>"
      )
    ),
    labelOptions = labelOptions(direction = "auto")
  ) |>
  addLegend(
    "bottomright",
    pal = pal_c,
    values = district_map$AvgIncome,
    title = "Avg Per-Capita Income<br>(2013–2023)"
  )
county_avg_income <- income_long |>
  group_by(County) |>
  summarise(
    AvgIncome = mean(Income, nona = TRUE)
  )
county_coords <- tibble(
  County = c(
    "Allegany County","Anne Arundel County","Baltimore City","Baltimore County",
    "Calvert County","Caroline County","Carroll County","Cecil County",
    "Charles County","Dorchester County","Frederick County","Garrett County",
    "Harford County","Howard County","Kent County","Montgomery County",
    "Prince George's County","Queen Anne's County","Somerset County",
    "St. Mary's County","Talbot County","Washington County","Wicomico County",
    "Worcester County"
  ),
  lat = c(
    39.62, 38.99, 39.29, 39.47,
    38.54, 38.86, 39.58, 39.56,
    38.52, 38.42, 39.41, 39.49,
    39.54, 39.21, 39.36, 39.15,
    38.83, 39.07, 38.12,
    38.28, 38.78, 39.64, 38.39,
    38.21
  ),
  lon = c(
    -78.76, -76.55, -76.61, -76.64,
    -76.59, -75.85, -77.01, -75.94,
    -77.01, -76.05, -77.41, -79.29,
    -76.34, -76.86, -76.06, -77.16,
    -76.70, -76.15, -75.62,
    -76.46, -76.07, -77.72, -75.64,
    -75.30
  )
)

county_map <- county_avg_income |>
  left_join(county_coords, by = "County")

Maryland Average Per-Capita Income (2013-2023) By County

pal_c <- colorNumeric(
  palette = c("#ffffcc", "#a1dab4", "#41b6c4", "#2c7fb8", "#253494"),
  domain = county_map$AvgIncome
)

leaflet(county_map) |>
  addTiles() |>
  addCircleMarkers(
    ~lon, ~lat,
    radius = ~AvgIncome / 1500,   
    fillColor = ~pal_c(AvgIncome),
    fillOpacity = 0.8,
    color = "black",
    weight = 1,
    label = ~paste0(
      County, " Avg Income 2013–2023: $", round(AvgIncome, 0)
    ),
    popup = ~paste0(
      "<strong>", County, "</strong><br>",
      "Avg Per-Capita Income (2013–2023): $", round(AvgIncome, 0)
    ),
    labelOptions = labelOptions(direction = "auto")
  ) |>
  addLegend(
    "bottomright",
    pal = pal_c,
    values = county_map$AvgIncome,
    title = "Avg Per-Capita Income<br>(2013–2023)"
  )