1 1. Packages

need <- c(
  "sf","dplyr","stringr","readr","ggplot2","tmap","spdep",
  "flextable","officer","glue","tidyr"
)
inst <- need[!need %in% installed.packages()[, "Package"]]
if (length(inst)) install.packages(inst, dependencies = TRUE)

library(sf)
library(dplyr)
library(stringr)
library(readr)
library(ggplot2)
library(tmap)
library(spdep)
library(flextable)
library(officer)
library(glue)
library(tidyr)

2 2. Data & Basic Checks

data_path <- params$data_path
out_dir   <- params$out_dir
if (!dir.exists(out_dir)) dir.create(out_dir, recursive = TRUE)

dist_data_shp <- readRDS(data_path)

# Peek
class(dist_data_shp)
## [1] "sf"         "tbl_df"     "tbl"        "data.frame"
names(dist_data_shp)[1:20]
##  [1] "GID_2"              "GID_0"              "COUNTRY"           
##  [4] "GID_1"              "NAME_1"             "NL_NAME_1"         
##  [7] "NAME_2"             "VARNAME_2"          "NL_NAME_2"         
## [10] "TYPE_2"             "ENGTYPE_2"          "CC_2"              
## [13] "HASC_2"             "geometry"           "district_id"       
## [16] "Year"               "Tyhoid_cases"       "Population"        
## [19] "Typhoid_Prevalence" "incidence_rate"
head(dist_data_shp)
# Geometry type
sf::st_geometry_type(dist_data_shp)[1:5]
## [1] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## 18 Levels: GEOMETRY POINT LINESTRING POLYGON MULTIPOINT ... TRIANGLE
# Standardize needed columns
dat <- dist_data_shp %>%
  transmute(
    district_id = district_id,
    region      = NAME_1,
    district    = NAME_2,
    year        = as.integer(Year),
    cases       = as.numeric(`Tyhoid_cases`),
    pop         = as.numeric(Population),
    geometry
  ) %>%
  filter(!is.na(year), year >= 2015, year <= 2024) %>%
  filter(!is.na(cases), !is.na(pop), cases >= 0, pop > 0) %>%
  mutate(
    district_std = str_squish(str_to_lower(gsub("[^A-Za-z0-9 ]", " ", district))),
    region_std   = str_squish(str_to_lower(gsub("[^A-Za-z0-9 ]", " ", region)))
  )

# Summary
dat %>% summarise(
  n_rows = n(),
  n_years = dplyr::n_distinct(year),
  years = paste0(min(year), "–", max(year)),
  n_districts = dplyr::n_distinct(district_id),
  n_regions   = dplyr::n_distinct(region)
)

3 3. National Rate by Year & District-Year SIR

nat_by_year <- dat %>%
  sf::st_drop_geometry() %>%
  group_by(year) %>%
  summarise(
    nat_cases = sum(cases, na.rm = TRUE),
    nat_pop   = sum(pop,   na.rm = TRUE),
    nat_rate  = nat_cases / nat_pop,
    .groups = "drop"
  )

sir_yearly <- dat %>%
  left_join(nat_by_year, by = "year") %>%
  mutate(
    E        = nat_rate * pop,
    SIR      = ifelse(E > 0, cases / E, NA_real_),
    SIR_low  = ifelse(cases == 0, 0, qchisq(0.025, 2*cases) / (2*E)),
    SIR_high = qchisq(0.975, 2*(cases + 1)) / (2*E),
    sig_flag = dplyr::case_when(
      SIR_low  > 1 ~ "High (significant)",
      SIR_high < 1 ~ "Low (significant)",
      TRUE         ~ "Not significant"
    )
  )

# Check observed ≈ expected nationally per year
sir_yearly %>%
  sf::st_drop_geometry() %>%
  group_by(year) %>%
  summarise(obs = sum(cases), Exp = sum(E)) %>%
  mutate(obs_to_Exp = obs/Exp)

4 4. Overall (2015–2024) District SIR

sir_overall <- sir_yearly %>%
  sf::st_drop_geometry() %>%
  group_by(district_id, region, district, district_std, region_std) %>%
  summarise(
    obs = sum(cases, na.rm = TRUE),
    Exp = sum(E,     na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    SIR      = ifelse(Exp > 0, obs / Exp, NA_real_),
    SIR_low  = ifelse(obs == 0, 0, qchisq(0.025, 2*obs) / (2*Exp)),
    SIR_high = qchisq(0.975, 2*(obs + 1)) / (2*Exp),
    sig_flag = dplyr::case_when(
      SIR_low  > 1 ~ "High (significant)",
      SIR_high < 1 ~ "Low (significant)",
      TRUE         ~ "Not significant"
    )
  ) %>%
  arrange(desc(SIR))

summary(sir_overall$SIR)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##  0.05205  0.43194  0.79123  0.99661  1.25579 10.07133
table(sir_overall$sig_flag, useNA = "ifany")
## 
## High (significant)  Low (significant)    Not significant 
##                 89                169                  2

5 5. Tables: Top/Bottom 10 (Baseline & Stable)

# Baseline top/bottom 10
top10 <- sir_overall %>% filter(!is.na(SIR)) %>% arrange(desc(SIR)) %>% slice_head(n = 10) %>% mutate(Rank = row_number())
bottom10 <- sir_overall %>% filter(!is.na(SIR)) %>% arrange(SIR)      %>% slice_head(n = 10) %>% mutate(Rank = row_number())

fmt_table <- function(df) {
  df %>%
    mutate(
      Exp = round(Exp, 1),
      SIR = round(SIR, 2),
      SIR_low = round(SIR_low, 2),
      SIR_high = round(SIR_high, 2),
      `95% CI` = paste0(SIR_low, "–", SIR_high)
    ) %>%
    select(Rank, Region = region, District = district,
           Observed = obs, Expected = Exp, SIR, `95% CI`, Significance = sig_flag)
}

top10_tbl    <- fmt_table(top10)
bottom10_tbl <- fmt_table(bottom10)

# Stability filter (Exp >= 20)
stable_overall <- sir_overall %>% filter(Exp >= 20)
top10_stable    <- stable_overall %>% arrange(desc(SIR)) %>% slice_head(n = 10) %>% mutate(Rank = row_number())
bottom10_stable <- stable_overall %>% arrange(SIR)        %>% slice_head(n = 10) %>% mutate(Rank = row_number())
top10_stable_tbl    <- fmt_table(top10_stable)
bottom10_stable_tbl <- fmt_table(bottom10_stable)

# Export CSVs
readr::write_csv(sir_yearly %>% sf::st_drop_geometry() %>%
                   select(district_id, region, district, year, cases, pop, E, SIR, SIR_low, SIR_high, sig_flag),
                 file.path(out_dir, "district_year_SIR_2015_2024.csv"))
readr::write_csv(sir_overall %>% select(district_id, region, district, obs, Exp, SIR, SIR_low, SIR_high, sig_flag),
                 file.path(out_dir, "district_overall_SIR_2015_2024.csv"))
readr::write_csv(top10_tbl,    file.path(out_dir, "Top10_Districts_SIR_2015_2024.csv"))
readr::write_csv(bottom10_tbl, file.path(out_dir, "Bottom10_Districts_SIR_2015_2024.csv"))
readr::write_csv(top10_stable_tbl,    file.path(out_dir, "Top10_Districts_SIR_Stable_Exp20.csv"))
readr::write_csv(bottom10_stable_tbl, file.path(out_dir, "Bottom10_Districts_SIR_Stable_Exp20.csv"))
doc <- read_docx()
doc <- body_add_par(doc, "Top 10 Districts by Overall SIR (2015–2024)", style = "heading 2")
doc <- body_add_flextable(doc, flextable(top10_tbl) %>% autofit())
doc <- body_add_par(doc, "Bottom 10 Districts by Overall SIR (2015–2024)", style = "heading 2")
doc <- body_add_flextable(doc, flextable(bottom10_tbl) %>% autofit())
doc <- body_add_par(doc, "Top 10 Districts by Overall SIR (Stable: Expected ≥ 20)", style = "heading 2")
doc <- body_add_flextable(doc, flextable(top10_stable_tbl) %>% autofit())
doc <- body_add_par(doc, "Bottom 10 Districts by Overall SIR (Stable: Expected ≥ 20)", style = "heading 2")
doc <- body_add_flextable(doc, flextable(bottom10_stable_tbl) %>% autofit())
print(doc, target = file.path(out_dir, "District_SIR_TopBottom10.docx"))

6 6. Maps — Overall SIR & Significant High-Risk Outlines

# Build sf for mapping
dist_geom <- dat %>%
  select(district_id, region, district, district_std, region_std, geometry) %>%
  distinct(district_id, .keep_all = TRUE)

sir_overall_sf <- dist_geom %>%
  left_join(sir_overall, by = c("district_id","region","district","district_std","region_std")) %>%
  st_make_valid()

# ggplot map
p_sir <- ggplot(sir_overall_sf) +
  geom_sf(aes(fill = SIR), linewidth = 0.1, color = "grey30") +
  scale_fill_gradient(trans = "sqrt", name = "SIR") +
  labs(title = "Overall District SIR for Typhoid Fever (2015–2024)",
       caption = "Source: DHIMS II") +
  theme_minimal(base_size = 11) +
  theme(panel.grid.major = element_blank(), axis.text = element_blank(), axis.title = element_blank())
p_sir

ggsave(file.path(out_dir, "Map1_overall_SIR_2015_2024.png"), p_sir, width = 10, height = 8, dpi = 300)

# tmap (plot mode for saving)
tmap_mode("plot")
m_sir <- tm_shape(sir_overall_sf) +
  tm_polygons("SIR", style = "quantile", n = 5, palette = "Oranges", title = "SIR (overall)") +
  tm_layout(title = "Overall District SIR (2015–2024)", legend.outside = TRUE, frame = FALSE)
m_sir

tmap_save(m_sir, file.path(out_dir, "Map2_overall_SIR_tmap_2015_2024.png"), width = 10, height = 8, dpi = 300)

# Significant high-risk outlines
sig_sf <- sir_overall_sf %>%
  mutate(sig_simple = dplyr::case_when(
    SIR_low  > 1 ~ "High (sig.)",
    SIR_high < 1 ~ "Low (sig.)",
    TRUE         ~ "NS"
  ))
p_sig <- ggplot() +
  geom_sf(data = sig_sf, aes(fill = SIR), linewidth = 0.1, color = "grey30") +
  geom_sf(data = subset(sig_sf, sig_simple == "High (sig.)"),
          fill = NA, linewidth = 0.8, linetype = 2, color = "black") +
  scale_fill_gradient(trans = "sqrt", name = "SIR") +
  labs(title = "District SIR with Significant High-Risk Outlines (2015–2024)",
       subtitle = "Dashed outline = SIR 95% CI lower bound > 1",
       caption = "Source: DHIMS II") +
  theme_minimal(base_size = 11) +
  theme(panel.grid.major = element_blank(), axis.text = element_blank(), axis.title = element_blank())
p_sig

ggsave(file.path(out_dir, "Map3_overall_SIR_sig_highlight.png"), p_sig, width = 10, height = 8, dpi = 300)

7 7. Faceted District-Year SIR Map (Appendix)

sir_yearly_plot <- sir_yearly %>%
  filter(!is.na(SIR), is.finite(SIR), year >= 2015, year <= 2024)

upper_cap <- quantile(sir_yearly_plot$SIR, 0.95, na.rm = TRUE)
sir_yearly_plot <- sir_yearly_plot %>% mutate(SIR_capped = pmin(SIR, upper_cap))

p_faceted_cont <- ggplot(sir_yearly_plot) +
  geom_sf(aes(fill = SIR_capped), linewidth = 0.08, color = "grey30") +
  scale_fill_gradient(low = "#FFF0B3", high = "#E65100", trans = "sqrt",
                      limits = c(0, upper_cap), breaks = pretty(c(0, upper_cap), 5), name  = "SIR") +
  facet_wrap(~ year, ncol = 5) +
  labs(title = "District SIR by Year (2015–2024)",
       subtitle = "SIR = Observed / Expected (expected uses national annual rate)",
       caption = "Source: DHIMS II") +
  theme_minimal(base_size = 10) +
  theme(panel.grid.major = element_blank(), axis.text = element_blank(),
        axis.title = element_blank(), strip.text = element_text(face = "bold"))
p_faceted_cont

ggsave(file.path(out_dir, "Appendix_FacetMap_District_SIR_Continuous_2015_2024.png"),
       p_faceted_cont, width = 14, height = 10, dpi = 300)
ggsave(file.path(out_dir, "Appendix_FacetMap_District_SIR_Continuous_2015_2024.pdf"),
       p_faceted_cont, width = 14, height = 10)

8 8. Spatial Autocorrelation & Clusters (Moran’s I, LISA)

# Queen contiguity
nb <- poly2nb(sir_overall_sf, queen = TRUE)
lw <- nb2listw(nb, style = "W", zero.policy = TRUE)

# Global Moran's I (greater = positive autocorrelation)
x <- log(sir_overall_sf$SIR)
m_global <- moran.test(x, lw, alternative = "greater", zero.policy = TRUE)
m_perm   <- moran.mc(x, lw, nsim = 9999, alternative = "greater", zero.policy = TRUE)
m_global
## 
##  Moran I test under randomisation
## 
## data:  x  
## weights: lw    
## 
## Moran I statistic standard deviate = 3.27, p-value = 0.0005378
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.121037898      -0.003861004       0.001458897
m_perm
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  x 
## weights: lw  
## number of simulations + 1: 10000 
## 
## statistic = 0.12104, observed rank = 9992, p-value = 8e-04
## alternative hypothesis: greater
# Local Moran's I (LISA)
x_raw <- sir_overall_sf$SIR; x_raw[!is.finite(x_raw)] <- NA_real_
z <- as.numeric(scale(log1p(x_raw)))  # standardized numeric vector
lisa <- localmoran(z, lw, zero.policy = TRUE, na.action = na.exclude)

Ii <- lisa[, "Ii"]
Z  <- lisa[, "Z.Ii"]
p_raw <- 2 * pnorm(-abs(Z))
p_fdr <- p.adjust(p_raw, method = "fdr")

sir_overall_sf$Ii    <- Ii
sir_overall_sf$Z.Ii  <- Z
sir_overall_sf$P.FDR <- p_fdr

ok <- is.finite(Ii) & is.finite(z) & is.finite(p_fdr)
sir_overall_sf$LISA_cat <- "NS"
sir_overall_sf$LISA_cat[ok & z > 0 & Ii > 0 & p_fdr < 0.05] <- "High-High"
sir_overall_sf$LISA_cat[ok & z < 0 & Ii > 0 & p_fdr < 0.05] <- "Low-Low"
sir_overall_sf$LISA_cat[ok & z > 0 & Ii < 0 & p_fdr < 0.05] <- "High-Low"
sir_overall_sf$LISA_cat[ok & z < 0 & Ii < 0 & p_fdr < 0.05] <- "Low-High"

p_lisa <- ggplot(sir_overall_sf) +
  geom_sf(aes(fill = LISA_cat), color = "grey30", linewidth = 0.1) +
  scale_fill_manual(values = c("High-High"="#E65100","Low-Low"="#2B8CBE",
                               "High-Low"="#FDB863","Low-High"="#67A9CF","NS"="#F0F0F0"),
                    name = "LISA clusters") +
  labs(title = "Local Moran’s I Clusters (Overall SIR, 2015–2024)",
       subtitle = "Two-sided test; FDR-adjusted p < 0.05; variable = log1p(SIR), standardized",
       caption = "Source: DHIMS II") +
  theme_minimal() +
  theme(axis.text = element_blank(), axis.title = element_blank())
p_lisa

ggsave(file.path(out_dir, "Map_LISA_Overall_2015_2024.png"), p_lisa, width = 10, height = 8, dpi = 300)

9 9. Getis–Ord Gi* Hotspots

gi <- localG(z, lw, zero.policy = TRUE)
gi_z <- as.numeric(gi)
gi_p  <- 2 * pnorm(-abs(gi_z))
gi_fdr <- p.adjust(gi_p, method = "fdr")

sir_overall_sf$GiZ   <- gi_z
sir_overall_sf$GiFDR <- gi_fdr
sir_overall_sf$GiCat <- "NS"
sir_overall_sf$GiCat[gi_z > 0 & gi_fdr < 0.05] <- "Hotspot"
sir_overall_sf$GiCat[gi_z < 0 & gi_fdr < 0.05] <- "Coldspot"

p_gi <- ggplot(sir_overall_sf) +
  geom_sf(aes(fill = GiCat), color = "grey30", linewidth = 0.1) +
  scale_fill_manual(values = c("Hotspot"="#E65100","Coldspot"="#2B8CBE","NS"="#F0F0F0"),
                    name = "Getis–Ord Gi*") +
  labs(title = "Getis–Ord Gi* Hotspots (Overall SIR, 2015–2024)",
       subtitle = "Two-sided FDR-adjusted p < 0.05; variable = log1p(SIR), standardized",
       caption = "Source: DHIMS II") +
  theme_minimal() +
  theme(axis.text = element_blank(), axis.title = element_blank())
p_gi

ggsave(file.path(out_dir, "Map_GiStar_Overall_2015_2024.png"), p_gi, width = 10, height = 8, dpi = 300)

# Counts to report
table(sir_overall_sf$GiCat)
## 
## Hotspot      NS 
##       5     255

10 10. (Appendix) Year-by-Year Gi* Hotspots Facet

dist_geom_key <- dat %>% select(district_id, geometry) %>% distinct(district_id, .keep_all = TRUE)
years <- sort(unique(sir_yearly$year))
gi_year_list <- vector("list", length(years)); names(gi_year_list) <- years

for (i in seq_along(years)) {
  yy <- years[i]
  d <- sir_yearly %>% filter(year == yy) %>% select(district_id, SIR) %>% st_drop_geometry()
  d <- d[match(dist_geom_key$district_id, d$district_id), ]

  d_sf <- dist_geom_key
  d_sf$SIR <- d$SIR
  xr <- d_sf$SIR; xr[!is.finite(xr)] <- NA_real_
  zz <- as.numeric(scale(log1p(xr)))

  giz  <- as.numeric(localG(zz, lw, zero.policy = TRUE))
  gip  <- 2 * pnorm(-abs(giz))
  gifdr <- p.adjust(gip, "fdr")

  d_sf$GiCat <- "NS"
  d_sf$GiCat[giz > 0 & gifdr < 0.05] <- "Hotspot"
  d_sf$GiCat[giz < 0 & gifdr < 0.05] <- "Coldspot"
  d_sf$year  <- yy
  gi_year_list[[i]] <- d_sf
}
gi_year_sf <- do.call(rbind, gi_year_list)

p_gi_year <- ggplot(gi_year_sf) +
  geom_sf(aes(fill = GiCat), color = "grey30", linewidth = 0.05) +
  scale_fill_manual(values = c("Hotspot"="#E65100","Coldspot"="#2B8CBE","NS"="#F0F0F0"), name = "Gi*") +
  facet_wrap(~ year, ncol = 5) +
  labs(title = "Getis–Ord Gi* Hotspots by Year (2015–2024)",
       subtitle = "Two-sided FDR-adjusted p < 0.05; variable = log1p(SIR), standardized",
       caption = "Source: DHIMS II") +
  theme_minimal(base_size = 10) +
  theme(panel.grid.major = element_blank(), axis.text = element_blank(),
        axis.title = element_blank(), strip.text = element_text(face = "bold"))
p_gi_year

ggsave(file.path(out_dir, "Appendix_FacetMap_GiStar_2015_2024.png"), p_gi_year, width = 14, height = 10, dpi = 300)

# Yearly hotspot counts table
gi_counts_year <- gi_year_sf %>%
  st_drop_geometry() %>%
  count(year, GiCat) %>%
  tidyr::pivot_wider(names_from = GiCat, values_from = n, values_fill = 0) %>%
  arrange(year)
readr::write_csv(gi_counts_year, file.path(out_dir, "GiStar_counts_by_year.csv"))

11 11. Auto-filled Result Sentences

sir_sum <- summary(sir_overall$SIR)
n_high <- sum(sir_overall$SIR_low  > 1, na.rm = TRUE)
n_low  <- sum(sir_overall$SIR_high < 1, na.rm = TRUE)

line_sir <- glue(
  "Across districts, the overall SIR ranged from {round(sir_sum['Min.'],2)} to {round(sir_sum['Max.'],2)} ",
  "(median {round(sir_sum['Median'],2)}). ",
  "{n_high} districts had significantly higher risk (SIR 95% CI lower bound > 1), ",
  "and {n_low} districts had significantly lower risk (upper bound < 1)."
)
line_sir
## Across districts, the overall SIR ranged from 0.05 to 10.07 (median 0.79). 89 districts had significantly higher risk (SIR 95% CI lower bound > 1), and 169 districts had significantly lower risk (upper bound < 1).
# Global Moran's I summary (printed earlier too)
m_global
## 
##  Moran I test under randomisation
## 
## data:  x  
## weights: lw    
## 
## Moran I statistic standard deviate = 3.27, p-value = 0.0005378
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.121037898      -0.003861004       0.001458897
m_perm
## 
##  Monte-Carlo simulation of Moran I
## 
## data:  x 
## weights: lw  
## number of simulations + 1: 10000 
## 
## statistic = 0.12104, observed rank = 9992, p-value = 8e-04
## alternative hypothesis: greater

12 12. Session Info

sessionInfo()
## R version 4.3.3 (2024-02-29 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 11 x64 (build 26100)
## 
## Matrix products: default
## 
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: Atlantic/Reykjavik
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] tidyr_1.3.1     glue_1.7.0      officer_0.6.6   flextable_0.9.6
##  [5] spdep_1.3-5     spData_2.3.1    tmap_3.3-4      ggplot2_3.5.1  
##  [9] readr_2.1.5     stringr_1.5.1   dplyr_1.1.4     sf_1.0-16      
## 
## loaded via a namespace (and not attached):
##   [1] DBI_1.2.3               deldir_2.0-4            tmaptools_3.1-1        
##   [4] s2_1.1.6                rlang_1.1.4             magrittr_2.0.3         
##   [7] e1071_1.7-14            compiler_4.3.3          png_0.1-8              
##  [10] systemfonts_1.1.0       vctrs_0.6.5             httpcode_0.3.0         
##  [13] pkgconfig_2.0.3         wk_0.9.2                crayon_1.5.3           
##  [16] fastmap_1.2.0           labeling_0.4.3          lwgeom_0.2-14          
##  [19] leafem_0.2.4            utf8_1.2.4              promises_1.3.0         
##  [22] rmarkdown_2.27          tzdb_0.4.0              ragg_1.3.2             
##  [25] bit_4.0.5               purrr_1.0.2             xfun_0.45              
##  [28] cachem_1.1.0            jsonlite_1.8.8          highr_0.11             
##  [31] later_1.3.2             uuid_1.2-0              terra_1.7-78           
##  [34] parallel_4.3.3          R6_2.5.1                bslib_0.7.0            
##  [37] stringi_1.8.4           RColorBrewer_1.1-3      boot_1.3-29            
##  [40] jquerylib_0.1.4         stars_0.6-5             Rcpp_1.0.12            
##  [43] knitr_1.48              base64enc_0.1-3         httpuv_1.6.15          
##  [46] tidyselect_1.2.1        rstudioapi_0.16.0       dichromat_2.0-0.1      
##  [49] abind_1.4-5             yaml_2.3.9              codetools_0.2-19       
##  [52] curl_5.2.1              lattice_0.22-5          tibble_3.2.1           
##  [55] leafsync_0.1.0          shiny_1.8.1.1           withr_3.0.0            
##  [58] askpass_1.2.0           evaluate_0.24.0         units_0.8-5            
##  [61] proxy_0.4-27            zip_2.3.1               xml2_1.3.6             
##  [64] pillar_1.9.0            KernSmooth_2.23-22      generics_0.1.3         
##  [67] vroom_1.6.5             sp_2.1-4                hms_1.1.3              
##  [70] munsell_0.5.1           scales_1.3.0            xtable_1.8-4           
##  [73] class_7.3-22            gdtools_0.3.7           tools_4.3.3            
##  [76] gfonts_0.2.0            data.table_1.15.4       XML_3.99-0.17          
##  [79] grid_4.3.3              crosstalk_1.2.1         colorspace_2.1-0       
##  [82] raster_3.6-26           cli_3.6.3               textshaping_0.4.0      
##  [85] fontBitstreamVera_0.1.1 fansi_1.0.6             viridisLite_0.4.2      
##  [88] gtable_0.3.6            sass_0.4.9              digest_0.6.36          
##  [91] fontquiver_0.2.1        classInt_0.4-10         crul_1.4.2             
##  [94] farver_2.1.2            htmlwidgets_1.6.4       htmltools_0.5.8.1      
##  [97] lifecycle_1.0.4         leaflet_2.2.2           mime_0.12              
## [100] bit64_4.0.5             fontLiberation_0.1.0    openssl_2.2.0