Skip to contents
theme_readme <- function() {
  theme_minimal(base_size = 14) +
    theme(
      plot.title = element_text(face = "bold", size = 16),
      plot.subtitle = element_text(color = "gray40"),
      panel.grid.minor = element_blank(),
      legend.position = "bottom"
    )
}

colors <- c("total" = "#2C3E50", "white" = "#3498DB", "black" = "#E74C3C",
            "hispanic" = "#F39C12", "asian" = "#9B59B6")
# Get available years
years <- get_available_years()
max_year <- max(years)
min_year <- min(years)

# Fetch recent data (2016-2024; 2015 has no cached data)
enr <- tryCatch({
  df <- fetch_enr_multi(2016:max_year, use_cache = TRUE)
  # Filter out any years with zero state total (missing data)
  good_years <- df %>%
    filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL",
           n_students > 0) %>%
    pull(end_year)
  df %>% filter(end_year %in% good_years)
}, error = function(e) {
  warning("Could not fetch enrollment data: ", e$message)
  NULL
})

# Key years for long-term trend
key_years <- get_available_years()

enr_long <- tryCatch({
  df <- fetch_enr_multi(key_years, use_cache = TRUE)
  good_years <- df %>%
    filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL",
           n_students > 0) %>%
    pull(end_year)
  df %>% filter(end_year %in% good_years)
}, error = function(e) {
  warning("Could not fetch long-term data: ", e$message)
  NULL
})

enr_current <- tryCatch({
  fetch_enr(max_year, use_cache = TRUE)
}, error = function(e) {
  warning("Could not fetch current year data: ", e$message)
  NULL
})

# Check if we have data
has_data <- !is.null(enr) && nrow(enr) > 0

1. Mississippi is majority Black in many districts

Unlike most Southern states, Mississippi has numerous majority-Black school districts, especially in the Delta region.

black <- enr_current %>%
  filter(is_district, subgroup == "black", grade_level == "TOTAL") %>%
  arrange(desc(pct)) %>%
  head(10) %>%
  mutate(district_label = reorder(district_name, pct))

stopifnot(nrow(black) > 0)

black %>% select(district_name, pct)
ggplot(black, aes(x = district_label, y = pct)) +
  geom_col(fill = colors["black"]) +
  coord_flip() +
  labs(title = "Mississippi Has Many Majority-Black Districts",
       subtitle = "Especially in the Delta region",
       x = "", y = "Percent Black Students") +
  theme_readme()

2. The Delta is emptying out

Districts in the Mississippi Delta have seen steep enrollment declines since 2007.

delta <- c("Coahoma County", "Sunflower County", "Leflore County")
delta_trend <- enr_long %>%
  filter(is_district, grepl(paste(delta, collapse = "|"), district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL") %>%
  group_by(end_year) %>%
  summarize(n_students = sum(n_students, na.rm = TRUE), .groups = "drop")

stopifnot(nrow(delta_trend) > 0)

delta_trend
ggplot(delta_trend, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma) +
  labs(title = "The Delta is Emptying Out",
       subtitle = "Coahoma, Sunflower, Leflore counties combined",
       x = "School Year", y = "Students") +
  theme_readme()

3. DeSoto County: Mississippi’s largest district

Bordering Memphis, DeSoto County grew 21% since 2007 to become Mississippi’s largest district with nearly 35,000 students.

desoto <- enr %>%
  filter(is_district, grepl("DeSoto|Desoto", district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(desoto) > 0)

desoto %>% select(end_year, district_name, n_students)
ggplot(desoto, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(title = "DeSoto County: Mississippi's Largest District",
       subtitle = "Memphis suburb grew 21% since 2007",
       x = "School Year", y = "Students") +
  theme_readme()

4. Jackson Public Schools’ steep decline

Mississippi’s capital city has lost 44% of students since 2007, from 32,000 to under 18,000.

jackson <- enr %>%
  filter(is_district, grepl("Jackson Public", district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(jackson) > 0)

jackson %>% select(end_year, district_name, n_students)
ggplot(jackson, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(title = "Jackson Public Schools' Steep Decline",
       subtitle = "Capital city lost 44% of students since 2007",
       x = "School Year", y = "Students") +
  theme_readme()

5. Mississippi lost 50,000 students in a decade

State enrollment dropped from 487,000 in 2016 to 437,000 in 2024, a 10% decline.

state_trend <- enr %>%
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(state_trend) > 0)

state_trend %>% select(end_year, n_students)
ggplot(state_trend, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(title = "Mississippi Enrollment Declined 10% Since 2016",
       subtitle = "State lost ~50,000 students from 487K to 437K",
       x = "School Year", y = "Students") +
  theme_readme()

6. COVID hit kindergarten hard

Mississippi lost 13% of kindergartners in 2021 and enrollment hasn’t recovered.

k_trend <- enr %>%
  filter(is_state, subgroup == "total_enrollment",
         grade_level %in% c("K", "01", "06", "12")) %>%
  mutate(grade_label = case_when(
    grade_level == "K" ~ "Kindergarten",
    grade_level == "01" ~ "Grade 1",
    grade_level == "06" ~ "Grade 6",
    grade_level == "12" ~ "Grade 12"
  ))

stopifnot(nrow(k_trend) > 0)

k_trend %>%
  filter(grade_level == "K") %>%
  select(end_year, n_students)
ggplot(k_trend, aes(x = end_year, y = n_students, color = grade_label)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2.5) +
  geom_vline(xintercept = 2021, linetype = "dashed", color = "red", alpha = 0.5) +
  scale_y_continuous(labels = comma) +
  labs(title = "COVID Hit Mississippi Kindergarten Hard",
       subtitle = "Lost 13% of kindergartners and hasn't recovered",
       x = "School Year", y = "Students", color = "") +
  theme_readme()

7. Madison County holds steady while Jackson shrinks

Madison County has maintained enrollment around 13,000 while neighboring Jackson declined – a sign of suburban stability.

madison <- enr %>%
  filter(is_district, grepl("Madison County", district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(madison) > 0)

madison %>% select(end_year, district_name, n_students)
ggplot(madison, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(title = "Madison County Holds Steady",
       subtitle = "Suburban district maintained enrollment while Jackson declined",
       x = "School Year", y = "Students") +
  theme_readme()

8. Hispanic students reach 46% in Forest Municipal

Forest Municipal School District is 46% Hispanic, with several other districts above 15%.

hispanic <- enr_current %>%
  filter(is_district, subgroup == "hispanic", grade_level == "TOTAL") %>%
  arrange(desc(pct)) %>%
  head(10) %>%
  mutate(district_label = reorder(district_name, pct))

stopifnot(nrow(hispanic) > 0)

hispanic %>% select(district_name, pct)
ggplot(hispanic, aes(x = district_label, y = pct)) +
  geom_col(fill = colors["hispanic"]) +
  coord_flip() +
  labs(title = "Hispanic Population Growing",
       subtitle = "Forest Municipal at 46%, several districts above 15%",
       x = "", y = "Percent Hispanic Students") +
  theme_readme()

9. The Coast is holding steady

Gulf Coast districts have maintained enrollment despite hurricanes.

coast <- c("Harrison County", "Jackson County", "Hancock County")
coast_trend <- enr %>%
  filter(is_district, grepl(paste(coast, collapse = "|"), district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(coast_trend) > 0)

coast_trend %>%
  group_by(end_year) %>%
  summarize(total = sum(n_students, na.rm = TRUE), .groups = "drop")
ggplot(coast_trend, aes(x = end_year, y = n_students, color = district_name)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2.5) +
  scale_y_continuous(labels = comma) +
  labs(title = "The Coast is Holding Steady",
       subtitle = "Gulf Coast districts maintained enrollment despite hurricanes",
       x = "School Year", y = "Students", color = "") +
  theme_readme()

10. Charter schools are minimal

Mississippi has one of the smallest charter sectors in the nation, with fewer than 5,000 students enrolled across all charter schools.

Note: Charter school enrollment tracking is not yet implemented in this package. The MDE data portal does not currently distinguish charter schools as a separate entity type.

11. Mississippi is nearly 47% Black statewide

Mississippi has the highest percentage of Black students of any US state, with Black students outnumbering white students statewide.

race <- enr_current %>%
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("white", "black", "hispanic", "asian")) %>%
  mutate(subgroup_label = case_when(
    subgroup == "white" ~ "White",
    subgroup == "black" ~ "Black",
    subgroup == "hispanic" ~ "Hispanic",
    subgroup == "asian" ~ "Asian"
  ))

stopifnot(nrow(race) > 0)

race %>% select(subgroup_label, n_students, pct)
ggplot(race, aes(x = reorder(subgroup_label, -pct), y = pct, fill = subgroup)) +
  geom_col() +
  scale_fill_manual(values = colors, guide = "none") +
  labs(title = "Mississippi's Racial Demographics",
       subtitle = "Nearly 47% Black students - highest in the nation",
       x = "", y = "Percent of Students") +
  theme_readme()

12. DeSoto and Rankin dominate enrollment rankings

The top 15 districts account for nearly half of all Mississippi students, with Memphis and Jackson suburbs leading the pack.

top_districts <- enr_current %>%
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") %>%
  arrange(desc(n_students)) %>%
  head(15) %>%
  mutate(district_label = reorder(district_name, n_students))

stopifnot(nrow(top_districts) > 0)

top_districts %>% select(district_name, n_students)
ggplot(top_districts, aes(x = district_label, y = n_students)) +
  geom_col(fill = colors["total"]) +
  coord_flip() +
  scale_y_continuous(labels = comma) +
  labs(title = "Top 15 Largest Districts",
       subtitle = "DeSoto, Rankin, and Jackson lead the state",
       x = "", y = "Students") +
  theme_readme()

13. Rankin County is the stable suburban anchor

Rankin County (east of Jackson) has maintained enrollment around 19,000 while the capital city declined.

rankin <- enr %>%
  filter(is_district, grepl("Rankin County", district_name, ignore.case = TRUE),
         subgroup == "total_enrollment", grade_level == "TOTAL")

stopifnot(nrow(rankin) > 0)

rankin %>% select(end_year, district_name, n_students)
ggplot(rankin, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.5, color = colors["total"]) +
  geom_point(size = 3, color = colors["total"]) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(title = "Rankin County: Stable Suburban Anchor",
       subtitle = "Maintained enrollment while Jackson declined",
       x = "School Year", y = "Students") +
  theme_readme()

14. Mississippi’s gender balance is nearly even

Like most states, Mississippi schools are roughly 51% male and 49% female, with slight variation by district.

gender <- enr %>%
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("male", "female")) %>%
  mutate(subgroup_label = ifelse(subgroup == "male", "Male", "Female"))

stopifnot(nrow(gender) > 0)

gender %>%
  filter(end_year == max_year) %>%
  select(subgroup_label, n_students, pct)
ggplot(gender, aes(x = end_year, y = pct, color = subgroup_label)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2.5) +
  labs(title = "Gender Balance Over Time",
       subtitle = "Slight male majority, consistent over years",
       x = "School Year", y = "Percent of Students", color = "") +
  theme_readme()

Session Info

sessionInfo()
#> R version 4.5.2 (2025-10-31)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.3 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
#>  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
#>  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
#> [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
#> 
#> time zone: UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] scales_1.4.0       dplyr_1.2.0        ggplot2_4.0.2      msschooldata_0.1.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.6       jsonlite_2.0.0     compiler_4.5.2     tidyselect_1.2.1  
#>  [5] jquerylib_0.1.4    systemfonts_1.3.2  textshaping_1.0.5  yaml_2.3.12       
#>  [9] fastmap_1.2.0      R6_2.6.1           generics_0.1.4     curl_7.0.0        
#> [13] knitr_1.51         tibble_3.3.1       desc_1.4.3         bslib_0.10.0      
#> [17] pillar_1.11.1      RColorBrewer_1.1-3 rlang_1.1.7        cachem_1.1.0      
#> [21] xfun_0.56          fs_1.6.7           sass_0.4.10        S7_0.2.1          
#> [25] cli_3.6.5          pkgdown_2.2.0      withr_3.0.2        magrittr_2.0.4    
#> [29] digest_0.6.39      grid_4.5.2         rappdirs_0.3.4     lifecycle_1.0.5   
#> [33] vctrs_0.7.1        evaluate_1.0.5     glue_1.8.0         farver_2.1.2      
#> [37] codetools_0.2-20   ragg_1.5.1         rmarkdown_2.30     purrr_1.2.1       
#> [41] httr_1.4.8         tools_4.5.2        pkgconfig_2.0.3    htmltools_0.5.9