15 Insights from Florida School Enrollment Data
Source:vignettes/enrollment_hooks.Rmd
enrollment_hooks.Rmd
library(flschooldata)
library(dplyr)
library(tidyr)
library(ggplot2)
theme_set(theme_minimal(base_size = 14))This vignette explores Florida’s public school enrollment data, surfacing key trends and demographic patterns across recent years (2015-2024).
1. Florida is America’s fourth-largest school system
Florida public schools serve nearly 3 million students, trailing only California, Texas, and New York.
enr <- fetch_enr_multi(2015:2024, use_cache = TRUE)
state_totals <- enr |>
filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
select(end_year, n_students) |>
mutate(change = n_students - lag(n_students),
pct_change = round(change / lag(n_students) * 100, 2))
state_totals
#> end_year n_students change pct_change
#> 1 2015 2750108 NA NA
#> 2 2016 2785286 35178 1.28
#> 3 2017 2810249 24963 0.90
#> 4 2018 2826290 16041 0.57
#> 5 2019 2840029 13739 0.49
#> 6 2020 2852303 12274 0.43
#> 7 2021 2784931 -67372 -2.36
#> 8 2022 2826573 41642 1.50
#> 9 2023 2864292 37719 1.33
#> 10 2024 2865908 1616 0.06
stopifnot(nrow(state_totals) > 0)
ggplot(state_totals, aes(x = end_year, y = n_students)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = max(state_totals$n_students), label = "COVID",
hjust = 0, size = 3, color = "gray40") +
geom_line(linewidth = 1.2, color = "#FF6600") +
geom_point(size = 3, color = "#FF6600") +
scale_y_continuous(labels = scales::comma) +
labs(
title = "Florida Public School Enrollment (2015-2024)",
subtitle = "Nearly 3 million students in the Sunshine State",
x = "School Year (ending)",
y = "Total Enrollment"
)
2. Miami-Dade is larger than most states
Miami-Dade County Public Schools, with 340,000+ students, is the fourth-largest school district in America.
enr_2024 <- fetch_enr(2024, use_cache = TRUE)
top_10 <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
arrange(desc(n_students)) |>
head(10) |>
select(district_name, n_students)
top_10
#> district_name n_students
#> 1 MIAMI-DADE 337610
#> 2 BROWARD 251397
#> 3 HILLSBOROUGH 224144
#> 4 ORANGE 207695
#> 5 PALM BEACH 191390
#> 6 DUVAL 129083
#> 7 POLK 115990
#> 8 LEE 99952
#> 9 PINELLAS 90969
#> 10 PASCO 85808
stopifnot(nrow(top_10) > 0)
top_10 |>
mutate(district_name = forcats::fct_reorder(district_name, n_students)) |>
ggplot(aes(x = n_students, y = district_name)) +
geom_col(fill = "#FF6600") +
scale_x_continuous(labels = scales::comma) +
labs(
title = "Florida's 10 Largest School Districts (2024)",
x = "Total Enrollment",
y = NULL
)
3. COVID barely dented Florida enrollment
While other states saw sharp declines, Florida’s enrollment dipped only briefly in 2021 and has since rebounded.
covid <- enr |>
filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL",
end_year >= 2019) |>
select(end_year, n_students) |>
mutate(change = n_students - lag(n_students))
covid
#> end_year n_students change
#> 1 2019 2840029 NA
#> 2 2020 2852303 12274
#> 3 2021 2784931 -67372
#> 4 2022 2826573 41642
#> 5 2023 2864292 37719
#> 6 2024 2865908 1616
stopifnot(nrow(covid) > 0)4. Hispanic students are the plurality
Hispanic students now comprise over 35% of Florida enrollment, surpassing white students.
demographics <- enr_2024 |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
mutate(pct = round(pct * 100, 1)) |>
select(subgroup, n_students, pct) |>
arrange(desc(n_students))
demographics
#> subgroup n_students pct
#> 1 hispanic 1066935 37.2
#> 2 white 988822 34.5
#> 3 black 599867 20.9
#> 4 multiracial 119907 4.2
#> 5 asian 81688 2.9
stopifnot(nrow(demographics) > 0)
demographics |>
mutate(subgroup = forcats::fct_reorder(subgroup, n_students)) |>
ggplot(aes(x = n_students, y = subgroup, fill = subgroup)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = paste0(pct, "%")), hjust = -0.1) +
scale_x_continuous(labels = scales::comma, expand = expansion(mult = c(0, 0.15))) +
scale_fill_brewer(palette = "Set2") +
labs(
title = "Florida Student Demographics (2024)",
subtitle = "Hispanic students are now the plurality",
x = "Number of Students",
y = NULL
)
5. Central Florida is the growth engine
Orange, Osceola, and Polk counties have been among the fastest-growing, driven by the Orlando metro boom.
central_fl <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Orange|Osceola|Polk", district_name, ignore.case = TRUE),
end_year %in% c(2015, 2024)) |>
group_by(district_name) |>
summarize(
y2015 = n_students[end_year == 2015],
y2024 = n_students[end_year == 2024],
pct_change = round((y2024 / y2015 - 1) * 100, 1),
.groups = "drop"
) |>
arrange(desc(pct_change))
central_fl
#> # A tibble: 3 × 4
#> district_name y2015 y2024 pct_change
#> <chr> <dbl> <dbl> <dbl>
#> 1 OSCEOLA 59276 74278 25.3
#> 2 POLK 99650 115990 16.4
#> 3 ORANGE 191640 207695 8.4
stopifnot(nrow(central_fl) > 0)6. Broward and Miami-Dade are declining
South Florida’s two largest districts have been losing students as families relocate.
south_fl <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Broward|Miami-Dade", district_name, ignore.case = TRUE),
end_year >= 2018) |>
select(end_year, district_name, n_students) |>
pivot_wider(names_from = district_name, values_from = n_students)
south_fl
#> # A tibble: 7 × 3
#> end_year BROWARD `MIAMI-DADE`
#> <int> <dbl> <dbl>
#> 1 2018 271951 354767
#> 2 2019 270961 350372
#> 3 2020 269163 347239
#> 4 2021 260224 334858
#> 5 2022 256027 329483
#> 6 2023 254728 335831
#> 7 2024 251397 337610
stopifnot(nrow(south_fl) > 0)
enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Broward|Miami-Dade", district_name, ignore.case = TRUE),
end_year >= 2018) |>
ggplot(aes(x = end_year, y = n_students, color = district_name)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = Inf, label = "COVID", hjust = 0, vjust = 1.5,
size = 3, color = "gray40") +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
scale_y_continuous(labels = scales::comma) +
labs(
title = "South Florida's Enrollment Decline",
x = "School Year",
y = "Enrollment",
color = "District"
)
7. Florida Virtual School is a district unto itself
Florida Virtual School (FLVS) serves tens of thousands of students statewide.
virtual <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Virtual|FLVS", district_name, ignore.case = TRUE)) |>
select(district_name, n_students)
virtual
#> district_name n_students
#> 1 FL VIRTUAL 8874
stopifnot(nrow(virtual) > 0)8. Kindergarten is the leading indicator
Florida kindergarten enrollment has been relatively stable, unlike states with sharp K declines.
k_trend <- enr |>
filter(is_state, subgroup == "total_enrollment",
grade_level %in% c("K", "01", "05", "09"),
end_year >= 2019) |>
select(end_year, grade_level, n_students) |>
pivot_wider(names_from = grade_level, values_from = n_students)
k_trend
#> # A tibble: 6 × 5
#> end_year K `01` `05` `09`
#> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 2019 200437 206545 222947 221023
#> 2 2020 202460 207143 217518 223805
#> 3 2021 186147 200215 207750 227753
#> 4 2022 199099 200741 217770 231499
#> 5 2023 197925 209516 209060 237920
#> 6 2024 195032 204402 205135 232506
stopifnot(nrow(k_trend) > 0)9. Black students are 21% of enrollment
Florida has a significant Black student population, concentrated in South Florida and the Jacksonville region.
black_enr <- enr_2024 |>
filter(is_state, grade_level == "TOTAL", subgroup == "black") |>
select(subgroup, n_students, pct)
black_enr
#> subgroup n_students pct
#> 1 black 599867 0.2093113
stopifnot(nrow(black_enr) > 0)10. Florida’s county-based system is unique
Florida organizes schools by county, with 67 county districts (plus a few specialty districts). This structure differs from most states.
county_count <- enr_2024 |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
summarize(
n_districts = n_distinct(district_name),
total_students = sum(n_students, na.rm = TRUE)
)
county_count
#> n_districts total_students
#> 1 76 2865908
stopifnot(nrow(county_count) > 0)11. Tampa Bay is catching up to South Florida
Hillsborough and Pinellas counties represent Florida’s other major metro area. While South Florida declines, Tampa Bay has held steady.
tampa <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Hillsborough|Pinellas|Pasco", district_name, ignore.case = TRUE)) |>
group_by(district_name) |>
summarize(
y2015 = n_students[end_year == 2015],
y2024 = n_students[end_year == 2024],
pct_change = round((y2024 / y2015 - 1) * 100, 1),
.groups = "drop"
) |>
arrange(desc(y2024))
tampa
#> # A tibble: 3 × 4
#> district_name y2015 y2024 pct_change
#> <chr> <dbl> <dbl> <dbl>
#> 1 HILLSBOROUGH 207457 224144 8
#> 2 PINELLAS 103754 90969 -12.3
#> 3 PASCO 69218 85808 24
stopifnot(nrow(tampa) > 0)
enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Hillsborough|Pinellas|Pasco", district_name, ignore.case = TRUE)) |>
ggplot(aes(x = end_year, y = n_students, color = district_name)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = Inf, label = "COVID", hjust = 0, vjust = 1.5,
size = 3, color = "gray40") +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
scale_y_continuous(labels = scales::comma) +
scale_color_brewer(palette = "Set1") +
labs(
title = "Tampa Bay Metro Enrollment Trends (2015-2024)",
subtitle = "Hillsborough stable, Pasco growing, Pinellas declining",
x = "School Year",
y = "Enrollment",
color = "County"
)
12. Jacksonville is Florida’s hidden giant
Duval County (Jacksonville) often flies under the radar, but it’s Florida’s 6th largest district with over 125,000 students.
jax <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
grepl("Duval", district_name, ignore.case = TRUE)) |>
select(end_year, district_name, n_students) |>
mutate(change = n_students - lag(n_students))
jax
#> end_year district_name n_students change
#> 1 2015 DUVAL 128665 NA
#> 2 2016 DUVAL 129169 504
#> 3 2017 DUVAL 129414 245
#> 4 2018 DUVAL 129562 148
#> 5 2019 DUVAL 130224 662
#> 6 2020 DUVAL 130283 59
#> 7 2021 DUVAL 126802 -3481
#> 8 2022 DUVAL 128939 2137
#> 9 2023 DUVAL 129788 849
#> 10 2024 DUVAL 129083 -705
stopifnot(nrow(jax) > 0)
jax |>
ggplot(aes(x = end_year, y = n_students)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = max(jax$n_students), label = "COVID",
hjust = 0, size = 3, color = "gray40") +
geom_line(linewidth = 1.2, color = "#0066CC") +
geom_point(size = 3, color = "#0066CC") +
scale_y_continuous(labels = scales::comma) +
labs(
title = "Duval County (Jacksonville) Enrollment (2015-2024)",
subtitle = "Florida's 6th largest district",
x = "School Year",
y = "Total Enrollment"
)
13. Hispanic enrollment surpassed White for the first time
A demographic milestone: Hispanic student enrollment has overtaken White enrollment in Florida, reflecting broader population shifts.
crossover <- enr |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white")) |>
select(end_year, subgroup, n_students) |>
pivot_wider(names_from = subgroup, values_from = n_students)
crossover
#> # A tibble: 10 × 3
#> end_year white hispanic
#> <int> <dbl> <dbl>
#> 1 2015 1108227 846425
#> 2 2016 1101823 879982
#> 3 2017 1089439 912300
#> 4 2018 1077811 937352
#> 5 2019 1063838 963338
#> 6 2020 1054580 986005
#> 7 2021 1016772 974588
#> 8 2022 1021630 1003659
#> 9 2023 1014065 1043390
#> 10 2024 988822 1066935
stopifnot(nrow(crossover) > 0)
enr |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white")) |>
ggplot(aes(x = end_year, y = n_students, color = subgroup)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = Inf, label = "COVID", hjust = 0, vjust = 1.5,
size = 3, color = "gray40") +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
scale_y_continuous(labels = scales::comma) +
scale_color_manual(values = c("hispanic" = "#FF6600", "white" = "#3399CC"),
labels = c("Hispanic", "White")) +
labs(
title = "The Hispanic-White Enrollment Crossover",
subtitle = "Hispanic students now outnumber White students in Florida",
x = "School Year",
y = "Number of Students",
color = "Group"
)
14. Small rural counties face steep declines
While large metros grow, many of Florida’s smallest counties are losing students rapidly.
# Get the first and last year for comparison
first_year <- min(enr$end_year)
last_year <- max(enr$end_year)
county_change <- enr |>
filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
end_year %in% c(first_year, last_year)) |>
group_by(district_name) |>
filter(n() == 2) |> # Only counties with both years
summarize(
y_first = n_students[end_year == first_year],
y_last = n_students[end_year == last_year],
change = y_last - y_first,
pct_change = round((y_last / y_first - 1) * 100, 1),
.groups = "drop"
)
# Counties losing the most (by %)
declining <- county_change |>
filter(y_first > 1000) |> # Exclude tiny counties
arrange(pct_change) |>
head(10)
declining
#> # A tibble: 10 × 5
#> district_name y_first y_last change pct_change
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 GADSDEN 5837 4598 -1239 -21.2
#> 2 LIBERTY 1330 1156 -174 -13.1
#> 3 PINELLAS 103754 90969 -12785 -12.3
#> 4 LAFAYETTE 1132 1007 -125 -11
#> 5 MADISON 2498 2228 -270 -10.8
#> 6 JACKSON 6726 6037 -689 -10.2
#> 7 DESOTO 4658 4199 -459 -9.9
#> 8 HARDEE 5095 4598 -497 -9.8
#> 9 TAYLOR 2885 2602 -283 -9.8
#> 10 CALHOUN 2149 1942 -207 -9.6
stopifnot(nrow(declining) > 0)
declining |>
mutate(district_name = forcats::fct_reorder(district_name, pct_change)) |>
ggplot(aes(x = pct_change, y = district_name)) +
geom_col(fill = "#CC3333") +
labs(
title = paste0("Florida's Fastest Declining Counties (", first_year, "-", last_year, ")"),
subtitle = "Percent change in total enrollment",
x = "Percent Change",
y = NULL
)
15. Multiracial students are the fastest-growing demographic
While Hispanic students are the largest group, multiracial student enrollment has grown at the highest rate percentage-wise since 2015 (34.9% growth, compared to 26.1% for Hispanic students and 15.3% for Asian students).
demo_trend <- enr |>
filter(is_state, grade_level == "TOTAL",
subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
select(end_year, subgroup, n_students) |>
group_by(subgroup) |>
mutate(pct_change = round((n_students / first(n_students) - 1) * 100, 1)) |>
ungroup()
demo_2024 <- demo_trend |>
filter(end_year == 2024) |>
arrange(desc(pct_change))
demo_2024
#> # A tibble: 5 × 4
#> end_year subgroup n_students pct_change
#> <int> <chr> <dbl> <dbl>
#> 1 2024 multiracial 119907 34.9
#> 2 2024 hispanic 1066935 26.1
#> 3 2024 asian 81688 15.3
#> 4 2024 black 599867 -4.2
#> 5 2024 white 988822 -10.8
stopifnot(nrow(demo_2024) > 0)
demo_trend |>
ggplot(aes(x = end_year, y = pct_change, color = subgroup)) +
geom_vline(xintercept = 2021, linetype = "dashed", color = "gray50", alpha = 0.7) +
annotate("text", x = 2021.1, y = Inf, label = "COVID", hjust = 0, vjust = 1.5,
size = 3, color = "gray40") +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
geom_hline(yintercept = 0, linetype = "dashed", alpha = 0.5) +
scale_color_brewer(palette = "Set1") +
labs(
title = "Demographic Growth Trends (2015-2024)",
subtitle = "Percent change from 2015 baseline",
x = "School Year",
y = "Percent Change from 2015",
color = "Subgroup"
)
Summary
Florida’s school enrollment data reveals:
- Continued growth: Florida keeps growing while other major states decline
- Demographic crossover: Hispanic students now outnumber White students, Asian students growing fastest
- Regional divergence: Central Florida and Tampa Bay grow, South Florida and rural areas shrink
- Virtual pioneer: FLVS shows Florida’s embrace of online education
- County structure: 67 county districts create a unique administrative system
- Hidden giants: Jacksonville (Duval) often overlooked as a major district
These patterns shape education policy across the Sunshine State.
Data sourced from the Florida Department of Education.
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] testthat_3.3.2 ggplot2_4.0.2 tidyr_1.3.2 dplyr_1.2.0
#> [5] flschooldata_0.1.0
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 jsonlite_2.0.0 compiler_4.5.2 brio_1.1.5
#> [5] tidyselect_1.2.1 jquerylib_0.1.4 systemfonts_1.3.2 scales_1.4.0
#> [9] textshaping_1.0.5 readxl_1.4.5 yaml_2.3.12 fastmap_1.2.0
#> [13] R6_2.6.1 labeling_0.4.3 generics_0.1.4 curl_7.0.0
#> [17] knitr_1.51 forcats_1.0.1 tibble_3.3.1 desc_1.4.3
#> [21] bslib_0.10.0 pillar_1.11.1 RColorBrewer_1.1-3 rlang_1.1.7
#> [25] utf8_1.2.6 cachem_1.1.0 xfun_0.56 S7_0.2.1
#> [29] fs_1.6.7 sass_0.4.10 cli_3.6.5 withr_3.0.2
#> [33] pkgdown_2.2.0 magrittr_2.0.4 digest_0.6.39 grid_4.5.2
#> [37] rappdirs_0.3.4 lifecycle_1.0.5 vctrs_0.7.1 evaluate_1.0.5
#> [41] glue_1.8.0 cellranger_1.1.0 farver_2.1.2 codetools_0.2-20
#> [45] ragg_1.5.1 httr_1.4.8 rmarkdown_2.30 purrr_1.2.1
#> [49] tools_4.5.2 pkgconfig_2.0.3 htmltools_0.5.9