Introduction: Broadband internet is important for daily life, including work, school, and access to services. However, access is not equal across all areas, especially in rural regions. In this project, I look at how broadband availability has changed over time using county-level data for Mississippi. I use spatial analysis methods like Moran’s I and hotspot analysis to find patterns and see where broadband is improving the most and where it is not. The goal is to understand spatial differences in broadband access and how development is happening across regions.

Load packages

# Load package

library(tidycensus)
library(tidyverse)
library(sf)
library(dplyr)
library(tmap)
library(ggplot2)
library(readr)
library(tidyr)
library(spdep)

Data collection

broadband availability were obtained from the Federal Communications Commission (FCC) Broadband Data Collection [https://broadbandmap.fcc.gov/data-download]

# Load broadband data for  Mississippi 2022 and 2024 

fcc22 <- read_csv("Broadband Summary by Geography Type2022.csv")
fcc24 <- read_csv("Broadband Summary by Geography Type2025.csv")

2022 Data (attributes):

colnames(fcc22)
##  [1] "area_data_type"      "geography_type"      "geography_id"       
##  [4] "geography_desc"      "geography_desc_full" "total_units"        
##  [7] "biz_res"             "technology"          "speed_02_02"        
## [10] "speed_10_1"          "speed_25_3"          "speed_100_20"       
## [13] "speed_250_25"        "speed_1000_100"

2024 Data (attributes):

colnames(fcc24)
##  [1] "area_data_type"      "geography_type"      "geography_id"       
##  [4] "geography_desc"      "geography_desc_full" "total_units"        
##  [7] "biz_res"             "technology"          "speed_02_02"        
## [10] "speed_10_1"          "speed_25_3"          "speed_100_20"       
## [13] "speed_250_25"        "speed_1000_100"

Prepare the data

filters the data by county, to get only fiber technology, and residential for Mississippi for both years.

# let filters the data by county, fiber technology, and residential for Mississippi for both years, then join in one.

# Clean Mississippi 2022
fcc22_ms <- fcc22 %>%
  filter(geography_type == "County") %>%
  filter(substr(geography_id, 1, 2) == "28") %>%
  filter(area_data_type == "Total") %>%
  filter(technology == "Fiber") %>%
  filter(biz_res == "R") %>%
  select(geography_desc_full, avail22 = speed_100_20) %>%
  distinct()

# Clean Mississippi 2024
fcc24_ms <- fcc24 %>%
  filter(geography_type == "County") %>%
  filter(substr(geography_id, 1, 2) == "28") %>%
  filter(area_data_type == "Total") %>%
  filter(technology == "Fiber") %>%
  filter(biz_res == "R") %>%
  select(geography_desc_full, avail24 = speed_100_20) %>%
  distinct()

check the data after filtering

head(fcc24_ms)
## # A tibble: 6 × 2
##   geography_desc_full avail24
##   <chr>                 <dbl>
## 1 Adams County, MS    0.261  
## 2 Alcorn County, MS   0.995  
## 3 Amite County, MS    0.00512
## 4 Attala County, MS   0.224  
## 5 Benton County, MS   0.353  
## 6 Bolivar County, MS  0.296
head(fcc22_ms)
## # A tibble: 6 × 2
##   geography_desc_full avail22
##   <chr>                 <dbl>
## 1 Adams, MS            0.184 
## 2 Alcorn, MS           0.998 
## 3 Amite, MS            0     
## 4 Attala, MS           0.142 
## 5 Benton, MS           0.162 
## 6 Bolivar, MS          0.0449

making sure the resulted data is correct

# making sure the resulted data is correct
nrow(fcc24_ms)
## [1] 82
nrow(fcc22_ms)
## [1] 82
head(fcc22_ms)
## # A tibble: 6 × 2
##   geography_desc_full avail22
##   <chr>                 <dbl>
## 1 Adams, MS            0.184 
## 2 Alcorn, MS           0.998 
## 3 Amite, MS            0     
## 4 Attala, MS           0.142 
## 5 Benton, MS           0.162 
## 6 Bolivar, MS          0.0449
remove “county” from the names to join the two datsets, then check the final dataset from FCC
## Remove county from 2024

fcc24_ms <- fcc24_ms %>%
  mutate(geography_desc_full = gsub(" County", "", geography_desc_full))

## join both datasets

fcc_final <- fcc22_ms %>%
  left_join(fcc24_ms, by = "geography_desc_full")

fcc_final
## # A tibble: 82 × 3
##    geography_desc_full avail22 avail24
##    <chr>                 <dbl>   <dbl>
##  1 Adams, MS            0.184  0.261  
##  2 Alcorn, MS           0.998  0.995  
##  3 Amite, MS            0      0.00512
##  4 Attala, MS           0.142  0.224  
##  5 Benton, MS           0.162  0.353  
##  6 Bolivar, MS          0.0449 0.296  
##  7 Calhoun, MS          0.812  0.905  
##  8 Carroll, MS          0.703  0.893  
##  9 Chickasaw, MS        0.696  0.784  
## 10 Choctaw, MS          0.563  0.976  
## # ℹ 72 more rows

download Census data: population, total households, households with broadband, and median household income

#  Census API 

census_api_key("7712f4050792f95cda2b3af671fd0eaf1f8129c4", install = TRUE, overwrite=TRUE)
## [1] "7712f4050792f95cda2b3af671fd0eaf1f8129c4"
# Download county-level data for Mississippi 
counties_ms <- get_acs(
  geography = "county",
  state = "MS",
  variables = "B01001_001",
  geometry = TRUE,
  year = 2022
)
##   |                                                                              |                                                                      |   0%  |                                                                              |                                                                      |   1%  |                                                                              |=                                                                     |   1%  |                                                                              |=                                                                     |   2%  |                                                                              |==                                                                    |   2%  |                                                                              |==                                                                    |   3%  |                                                                              |==                                                                    |   4%  |                                                                              |===                                                                   |   4%  |                                                                              |===                                                                   |   5%  |                                                                              |====                                                                  |   5%  |                                                                              |====                                                                  |   6%  |                                                                              |=====                                                                 |   6%  |                                                                              |=====                                                                 |   7%  |                                                                              |=====                                                                 |   8%  |                                                                              |======                                                                |   8%  |                                                                              |======                                                                |   9%  |                                                                              |=======                                                               |   9%  |                                                                              |=======                                                               |  10%  |                                                                              |=======                                                               |  11%  |                                                                              |========                                                              |  11%  |                                                                              |========                                                              |  12%  |                                                                              |=========                                                             |  12%  |                                                                              |=========                                                             |  13%  |                                                                              |==========                                                            |  14%  |                                                                              |==========                                                            |  15%  |                                                                              |===========                                                           |  15%  |                                                                              |===========                                                           |  16%  |                                                                              |============                                                          |  16%  |                                                                              |============                                                          |  17%  |                                                                              |============                                                          |  18%  |                                                                              |=============                                                         |  18%  |                                                                              |=============                                                         |  19%  |                                                                              |==============                                                        |  19%  |                                                                              |==============                                                        |  20%  |                                                                              |==============                                                        |  21%  |                                                                              |===============                                                       |  21%  |                                                                              |===============                                                       |  22%  |                                                                              |================                                                      |  22%  |                                                                              |================                                                      |  23%  |                                                                              |=================                                                     |  24%  |                                                                              |=================                                                     |  25%  |                                                                              |==================                                                    |  25%  |                                                                              |==================                                                    |  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%  |                                                                              |======================================                                |  54%  |                                                                              |======================================                                |  55%  |                                                                              |=======================================                               |  55%  |                                                                              |=======================================                               |  56%  |                                                                              |========================================                              |  56%  |                                                                              |========================================                              |  57%  |                                                                              |========================================                              |  58%  |                                                                              |=========================================                             |  58%  |                                                                              |=========================================                             |  59%  |                                                                              |==========================================                            |  59%  |                                                                              |==========================================                            |  60%  |                                                                              |==========================================                            |  61%  |                                                                              |===========================================                           |  61%  |                                                                              |===========================================                           |  62%  |                                                                              |============================================                          |  62%  |                                                                              |============================================                          |  63%  |                                                                              |============================================                          |  64%  |                                                                              |=============================================                         |  64%  |                                                                              |=============================================                         |  65%  |                                                                              |==============================================                        |  65%  |                                                                              |==============================================                        |  66%  |                                                                              |===============================================                       |  66%  |                                                                              |===============================================                       |  67%  |                                                                              |===============================================                       |  68%  |                                                                              |================================================                      |  68%  |                                                                              |================================================                      |  69%  |                                                                              |=================================================                     |  69%  |                                                                              |=================================================                     |  70%  |                                                                              |=================================================                     |  71%  |                                                                              |==================================================                    |  71%  |                                                                              |==================================================                    |  72%  |                                                                              |===================================================                   |  72%  |                                                                              |===================================================                   |  73%  |                                                                              |====================================================                  |  74%  |                                                                              |====================================================                  |  75%  |                                                                              |=====================================================                 |  75%  |                                                                              |=====================================================                 |  76%  |                                                                              |======================================================                |  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%
# Download internet access data: total households and households with broadband

internet_22 <- get_acs(
  geography = "county",
  state = "MS",
  variables = c(
    total22 = "B28002_001",
    broadband22 = "B28002_004"
  ),
  year = 2022
) %>%
  # Keep only needed columns
  select(GEOID, variable, estimate) %>%
  # Convert from long format to wide format
  pivot_wider(names_from = variable, values_from = estimate) %>%
  # Calculate new coulum which is the broadband adoption rate
  mutate(adopt22 = broadband22 / total22)

# Download income data for Mississippi 
income_ms <- get_acs(
  geography = "county",
  state = "MS",
  variables = "S1901_C01_012",  
  year = 2022
) %>%
  # Keep only GEOID and income 
  select(GEOID, income = estimate)

# census 2024 data
internet_24 <- get_acs(
  geography = "county",
  state = "MS",
  variables = c(
    total = "B28002_001",
    broadband = "B28002_004"
  ),
  year = 2024
) %>%
  select(GEOID, variable, estimate) %>%
  pivot_wider(names_from = variable, values_from = estimate) %>%
  mutate(adopt24 = broadband / total)

Join and clean the FCC, and Census data

Clean FCC data names so they match Census county names, replaces “MS” with “Mississippi” for joining, then check

# Clean FCC data names so they match Census county names, replaces "MS" with "Mississippi" for  joining
fcc_final <- fcc_final %>%
  mutate(county = gsub(", MS", ", Mississippi", geography_desc_full))
fcc_final
## # A tibble: 82 × 4
##    geography_desc_full avail22 avail24 county                
##    <chr>                 <dbl>   <dbl> <chr>                 
##  1 Adams, MS            0.184  0.261   Adams, Mississippi    
##  2 Alcorn, MS           0.998  0.995   Alcorn, Mississippi   
##  3 Amite, MS            0      0.00512 Amite, Mississippi    
##  4 Attala, MS           0.142  0.224   Attala, Mississippi   
##  5 Benton, MS           0.162  0.353   Benton, Mississippi   
##  6 Bolivar, MS          0.0449 0.296   Bolivar, Mississippi  
##  7 Calhoun, MS          0.812  0.905   Calhoun, Mississippi  
##  8 Carroll, MS          0.703  0.893   Carroll, Mississippi  
##  9 Chickasaw, MS        0.696  0.784   Chickasaw, Mississippi
## 10 Choctaw, MS          0.563  0.976   Choctaw, Mississippi  
## # ℹ 72 more rows
# Combine all datasets into one 
data_all <- counties_ms %>%
  left_join(internet_22, by = "GEOID") %>%
  left_join(internet_24, by = "GEOID") %>%   # NEW
  left_join(income_ms, by = "GEOID")

# Clean names
data_all <- data_all %>%
  mutate(NAME = gsub(" County", "", NAME),
         NAME = gsub(", Mississippi", ", MS", NAME))

# Join FCC
data_all <- data_all %>%
  left_join(fcc_final, by = c("NAME" = "geography_desc_full"))

Check data summary, and the combined dataset (Census& FCC for both years)

# Check summary of broadband availability for 2022, and 2024 to understand the distribution of values
summary(data_all$avail22)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.00000 0.07615 0.31620 0.35856 0.58078 0.99840
summary(data_all$avail24)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0000  0.3050  0.6160  0.5506  0.7888  0.9985
data_all
## Simple feature collection with 82 features and 15 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -91.65501 ymin: 30.17537 xmax: -88.09789 ymax: 34.99605
## Geodetic CRS:  NAD83
## First 10 features:
##    GEOID        NAME   variable estimate moe total22 broadband22   adopt22
## 1  28087 Lowndes, MS B01001_001    58547  NA   22651       19217 0.8483952
## 2  28121  Rankin, MS B01001_001   157185  NA   58982       52653 0.8926961
## 3  28083 Leflore, MS B01001_001    27920  NA    9656        5282 0.5470174
## 4  28149  Warren, MS B01001_001    44341  NA   16823       13200 0.7846401
## 5  28153   Wayne, MS B01001_001    19760  NA    7410        5792 0.7816464
## 6  28029  Copiah, MS B01001_001    28210  NA    9841        6968 0.7080581
## 7  28089 Madison, MS B01001_001   109257  NA   42182       38456 0.9116685
## 8  28081     Lee, MS B01001_001    83343  NA   32001       25934 0.8104122
## 9  28051  Holmes, MS B01001_001    16848  NA    5798        3650 0.6295274
## 10 28073   Lamar, MS B01001_001    64425  NA   24896       22062 0.8861665
##    total broadband   adopt24 income avail22   avail24               county
## 1  23006     20054 0.8716856  53687  0.6843 0.7890117 Lowndes, Mississippi
## 2  60133     55408 0.9214242  76460  0.4727 0.5766189  Rankin, Mississippi
## 3  10203      7067 0.6926394  33115  0.4445 0.6127967 Leflore, Mississippi
## 4  16772     14125 0.8421774  54117  0.1353 0.2793023  Warren, Mississippi
## 5   7681      6371 0.8294493  34875  0.6911 0.7582116   Wayne, Mississippi
## 6  10060      7994 0.7946322  46889  0.2213 0.2403995  Copiah, Mississippi
## 7  43917     40691 0.9265433  79105  0.5906 0.6653713 Madison, Mississippi
## 8  32591     27819 0.8535792  64479  0.8168 0.8529897     Lee, Mississippi
## 9   6157      4198 0.6818256  28818  0.1336 0.1565157  Holmes, Mississippi
## 10 25381     22477 0.8855837  67972  0.3081 0.5481495   Lamar, Mississippi
##                          geometry
## 1  MULTIPOLYGON (((-88.67125 3...
## 2  MULTIPOLYGON (((-90.25346 3...
## 3  MULTIPOLYGON (((-90.45376 3...
## 4  MULTIPOLYGON (((-91.17366 3...
## 5  MULTIPOLYGON (((-88.94294 3...
## 6  MULTIPOLYGON (((-90.73628 3...
## 7  MULTIPOLYGON (((-90.4514 32...
## 8  MULTIPOLYGON (((-88.8255 34...
## 9  MULTIPOLYGON (((-90.43168 3...
## 10 MULTIPOLYGON (((-89.65421 3...

Normalize variables to a 0–1 scale so they are comparable, to help combine different measures (adoption and availability)

# normalization function
norm <- function(x) {
  (x - min(x, na.rm = TRUE)) /
  (max(x, na.rm = TRUE) - min(x, na.rm = TRUE))
}

# Apply normalization to variables
data_all <- data_all %>%
  mutate(
    adopt22_n = norm(adopt22),
    adopt24_n = norm(adopt24),   # NEW
    avail22_n = norm(avail22),
    avail24_n = norm(avail24)
  )

Create Broadband Accessibility Index (LBAI), to combine adoption and availability into one measure

data_all <- data_all %>%
  mutate(
    LBAI_22 = (adopt22_n + avail22_n) / 2,
    LBAI_24 = (adopt24_n + avail24_n) / 2,
    change = LBAI_24 - LBAI_22
  )

Check the data with all the new attributies

data_all
## Simple feature collection with 82 features and 22 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -91.65501 ymin: 30.17537 xmax: -88.09789 ymax: 34.99605
## Geodetic CRS:  NAD83
## First 10 features:
##    GEOID        NAME   variable estimate moe total22 broadband22   adopt22
## 1  28087 Lowndes, MS B01001_001    58547  NA   22651       19217 0.8483952
## 2  28121  Rankin, MS B01001_001   157185  NA   58982       52653 0.8926961
## 3  28083 Leflore, MS B01001_001    27920  NA    9656        5282 0.5470174
## 4  28149  Warren, MS B01001_001    44341  NA   16823       13200 0.7846401
## 5  28153   Wayne, MS B01001_001    19760  NA    7410        5792 0.7816464
## 6  28029  Copiah, MS B01001_001    28210  NA    9841        6968 0.7080581
## 7  28089 Madison, MS B01001_001   109257  NA   42182       38456 0.9116685
## 8  28081     Lee, MS B01001_001    83343  NA   32001       25934 0.8104122
## 9  28051  Holmes, MS B01001_001    16848  NA    5798        3650 0.6295274
## 10 28073   Lamar, MS B01001_001    64425  NA   24896       22062 0.8861665
##    total broadband   adopt24 income avail22   avail24               county
## 1  23006     20054 0.8716856  53687  0.6843 0.7890117 Lowndes, Mississippi
## 2  60133     55408 0.9214242  76460  0.4727 0.5766189  Rankin, Mississippi
## 3  10203      7067 0.6926394  33115  0.4445 0.6127967 Leflore, Mississippi
## 4  16772     14125 0.8421774  54117  0.1353 0.2793023  Warren, Mississippi
## 5   7681      6371 0.8294493  34875  0.6911 0.7582116   Wayne, Mississippi
## 6  10060      7994 0.7946322  46889  0.2213 0.2403995  Copiah, Mississippi
## 7  43917     40691 0.9265433  79105  0.5906 0.6653713 Madison, Mississippi
## 8  32591     27819 0.8535792  64479  0.8168 0.8529897     Lee, Mississippi
## 9   6157      4198 0.6818256  28818  0.1336 0.1565157  Holmes, Mississippi
## 10 25381     22477 0.8855837  67972  0.3081 0.5481495   Lamar, Mississippi
##                          geometry adopt22_n adopt24_n avail22_n avail24_n
## 1  MULTIPOLYGON (((-88.67125 3... 0.8853692 0.8754957 0.6853966 0.7901852
## 2  MULTIPOLYGON (((-90.25346 3... 0.9656281 0.9883818 0.4734575 0.5774766
## 3  MULTIPOLYGON (((-90.45376 3... 0.3393698 0.4691339 0.4452123 0.6137082
## 4  MULTIPOLYGON (((-91.17366 3... 0.7698655 0.8085241 0.1355168 0.2797178
## 5  MULTIPOLYGON (((-88.94294 3... 0.7644420 0.7796364 0.6922075 0.7593394
## 6  MULTIPOLYGON (((-90.73628 3... 0.6311237 0.7006158 0.2216546 0.2407571
## 7  MULTIPOLYGON (((-90.4514 32... 1.0000000 1.0000000 0.5915465 0.6663610
## 8  MULTIPOLYGON (((-88.8255 34... 0.8165562 0.8344014 0.8181090 0.8542585
## 9  MULTIPOLYGON (((-90.43168 3... 0.4888514 0.4445908 0.1338141 0.1567485
## 10 MULTIPOLYGON (((-89.65421 3... 0.9537985 0.9070386 0.3085938 0.5489648
##      LBAI_22   LBAI_24      change
## 1  0.7853829 0.8328404  0.04745751
## 2  0.7195428 0.7829292  0.06338636
## 3  0.3922911 0.5414210  0.14912995
## 4  0.4526912 0.5441209  0.09142976
## 5  0.7283247 0.7694879  0.04116313
## 6  0.4263892 0.4706865  0.04429731
## 7  0.7957732 0.8331805  0.03740726
## 8  0.8173326 0.8443299  0.02699735
## 9  0.3113327 0.3006697 -0.01066305
## 10 0.6311961 0.7280017  0.09680554

Maps and Plots

broadband access for 2024

# Set map mode to static plots
tmap_mode("plot")

# broadband access for 2024  

LBAI2024 <- tm_shape(data_all) +
  tm_polygons("LBAI_24", palette = "Blues",
              title = "LBAI 2024")

tmap_save(LBAI2024,"Broadband Access using Broadband Accessibility Index (LBAI) for 2024.png", width = 12, height = 6)
LBAI2024 

broadband access for 2022

# broadband access for 2022 

LBAI2022 <-tm_shape(data_all) +
  tm_polygons("LBAI_22", palette = "Blues",
              title = "LBAI 2022") 

tmap_save(LBAI2022,"Broadband Access using Broadband Accessibility Index (LBAI) for 2022.png", width = 12, height = 6)
LBAI2022

broadband access change

# the change between 2022 and 2024

changeMap <- tm_shape(data_all) +
  tm_polygons("change", palette = "-RdBu",
              title = "Change") 

tmap_save(changeMap,"Change in Broadband Access using Broadband Accessibility Index (LBAI) between 2022–2024.png", width = 12, height = 6)

changeMap

broadband access scatter plot

# Scatter plot to compare 2022 vs 2024, points above red line = improvement

p_scatter <- ggplot(data_all, aes(x = LBAI_22, y = LBAI_24)) +
  geom_point(size = 3) +
  geom_abline(slope = 1, intercept = 0, color = "red") +
  labs(
    title = "Broadband Access Change (2022 vs 2024)",
    x = "LBAI 2022",
    y = "LBAI 2024"
  )
p_scatter

broadband access histogram

# Histogram to show how change is distributed

Histogram_Change <- ggplot(data_all, aes(x = change)) +
  geom_histogram(bins = 20, fill = "lightblue", color = "black") +
  labs(title = "Distribution of Broadband Change")
Histogram_Change

# Save the figures
ggsave("Scatter_LBAI.png", plot = p_scatter, width = 8, height = 6)
ggsave("Histogram_Change.png", plot = Histogram_Change, width = 8, height = 6)

Spatial Analysis [Moran’s I]

# Create spatial neighbors based on county borders
nb <- poly2nb(data_all)

# Convert neighbors into spatial weights
lw <- nb2listw(nb, style = "W")

# test spatial clustering for 2024 broadband access
moran.test(data_all$LBAI_24, lw)
## 
##  Moran I test under randomisation
## 
## data:  data_all$LBAI_24  
## weights: lw    
## 
## Moran I statistic standard deviate = 7.9707, p-value = 7.892e-16
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.527918899      -0.012345679       0.004594356
# test spatial clustering for 2022 broadband access
moran.test(data_all$LBAI_22, lw)
## 
##  Moran I test under randomisation
## 
## data:  data_all$LBAI_22  
## weights: lw    
## 
## Moran I statistic standard deviate = 7.1457, p-value = 4.477e-13
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.472173445      -0.012345679       0.004597633
# test spatial clustering for the change 
moran.test(data_all$change, lw)
## 
##  Moran I test under randomisation
## 
## data:  data_all$change  
## weights: lw    
## 
## Moran I statistic standard deviate = 2.9467, p-value = 0.001606
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.185452539      -0.012345679       0.004505763

Local spatial analysis (Local Moran’s I )

# Local Moran’s I to detect clusters

local_22 <- localmoran(data_all$LBAI_22, lw)
local_24 <- localmoran(data_all$LBAI_24, lw)

# Store results
data_all$local_I22 <- local_22[,1]
data_all$local_I24 <- local_24[,1]

# Map Moran’s I
map22 <- tm_shape(data_all) +
  tm_polygons("local_I22", palette = "-RdBu") +   
  tm_layout(title = "Local Moran's I (2022)")

map24 <- tm_shape(data_all) +
  tm_polygons("local_I24", palette = "-RdBu") +
  tm_layout(title = "Local Moran's I (2024)")

# Show  comparison map side by side
tmap_arrange(map22, map24, ncol = 2)

####store values into categories

# positive means clustered, negative means outlier
data_all$lisa22_cat <- ifelse(data_all$local_I22 > 0, "Cluster", "Outlier")
data_all$lisa24_cat <- ifelse(data_all$local_I24 > 0, "Cluster", "Outlier")

Hotspot analysis (Getis-Ord Gi*)

# detect hotspots and coldspots
gi <- localG(data_all$LBAI_24, lw)
gi2 <- localG(data_all$LBAI_22, lw)

# store results
data_all$hotspot24 <- as.numeric(gi)
data_all$hotspot22 <- as.numeric(gi2)

# Map hotspots
HS24 <- tm_shape(data_all) +
  tm_polygons("hotspot24", palette = "-RdBu") +
  tm_layout(title = "Hotspot Analysis (2024)")
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the visual variable `fill` namely 'palette' (rename to 'values') to fill.scale
## = tm_scale(<HERE>).
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
HS22 <- tm_shape(data_all) +
  tm_polygons("hotspot22", palette = "-RdBu") +
  tm_layout(title = "Hotspot Analysis (2022)")
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
# show  comparison map side by side
tmap_arrange(HS22, HS24, ncol = 2)
## Multiple palettes called "rd_bu" found: "brewer.rd_bu", "matplotlib.rd_bu". The first one, "brewer.rd_bu", is returned.
## [scale] tm_polygons:() the data variable assigned to 'fill' contains positive and negative values, so midpoint is set to 0. Set 'midpoint = NA' in 'fill.scale = tm_scale_intervals(<HERE>)' to use all visual values (e.g. colors)
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "-RdBu" is named
## "rd_bu" (in long format "brewer.rd_bu")[plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.Multiple palettes called "rd_bu" found: "brewer.rd_bu", "matplotlib.rd_bu". The first one, "brewer.rd_bu", is returned.
## [scale] tm_polygons:() the data variable assigned to 'fill' contains positive and negative values, so midpoint is set to 0. Set 'midpoint = NA' in 'fill.scale = tm_scale_intervals(<HERE>)' to use all visual values (e.g. colors)
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "-RdBu" is named
## "rd_bu" (in long format "brewer.rd_bu")[plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.

change map

map_change <- tm_shape(data_all) +
  tm_polygons("change", palette = "-RdBu") +   # red = increase, blue = decrease
  tm_layout(title = "Change in Broadband Access Local Moran’s I (2022–2024)")

tmap_arrange(map22, map24, map_change, ncol = 3)

map_changeHS <- tm_shape(data_all) +
  tm_polygons("change", palette = "-RdBu") +   # red = increase, blue = decrease
  tm_layout(title = "Change in Broadband Hotspots (2022–2024)")

tmap_arrange(HS22, HS24, map_changeHS, ncol = 3)

save the maps

# Local Moran comparison
comp_moran <- tmap_arrange(map22, map24, ncol = 2)
tmap_save(comp_moran, "Comparison_Moran.png", width = 12, height = 6)

# Hotspot comparison
comp_hotspot <- tmap_arrange(HS22, HS24, ncol = 2)
tmap_save(comp_hotspot, "Comparison_Hotspot.png", width = 12, height = 6)

# Final comparison (2022, 2024, Change)
final_mapHS <- tmap_arrange(HS22, HS24, map_changeHS, ncol = 3)
tmap_save(final_mapHS, "HSFinal_Comparison.png", width = 14, height = 6)

# Final comparison (2022, 2024, HSChange)
final_map <- tmap_arrange(map22, map24, map_change, ncol = 3)
tmap_save(final_map, "Final_Comparison.png", width = 14, height = 6)