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 10 years of data
enr <- fetch_enr_multi((max_year - 9):max_year, use_cache = TRUE)
# Fetch long-range milestone years
key_years <- c(2006, 2011, 2016, 2021, max_year)
key_years <- key_years[key_years >= min_year & key_years <= max_year]
enr_long <- fetch_enr_multi(key_years, use_cache = TRUE)
# Fetch current year data
enr_current <- fetch_enr(max_year, use_cache = TRUE)1. Indiana lost 55,000 students since 2006
Indiana enrollment peaked above 1.08 million in 2006 and has steadily declined to just over 1.03 million. The state lost about 5% of its public school enrollment over two decades.
state_trend <- enr %>%
filter(is_state, grade_level == "TOTAL", subgroup == "total_enrollment")
stopifnot(nrow(state_trend) > 0)
state_trend %>% select(end_year, n_students)
#> end_year n_students
#> 1 2017 1049292
#> 2 2018 1053809
#> 3 2019 1055354
#> 4 2020 1051051
#> 5 2021 1033781
#> 6 2022 1036697
#> 7 2023 1036123
#> 8 2024 1032724
#> 9 2025 1040190
#> 10 2026 1028466
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 = "Indiana Public School Enrollment",
subtitle = "Gradual decline from 1.05M to 1.03M over the past decade",
x = "School Year", y = "Students") +
theme_readme()
2. Indianapolis Public Schools has lost over 15,000 students
IPS enrollment dropped from 37,554 in 2006 to under 22,000 by 2024 – a 42% decline. Charter schools and suburban flight continue to reshape Indianapolis education.
ips <- enr_long %>%
filter(is_corporation, grepl("Indianapolis Public Schools", corporation_name),
subgroup == "total_enrollment", grade_level == "TOTAL")
stopifnot(nrow(ips) > 0)
ips %>% select(end_year, corporation_name, n_students)
#> end_year corporation_name n_students
#> 1 2006 Indianapolis Public Schools 37554
#> 2 2011 Indianapolis Public Schools 33080
#> 3 2016 Indianapolis Public Schools 29583
#> 4 2021 Indianapolis Public Schools 22930
#> 5 2026 Indianapolis Public Schools 19774
ggplot(ips, 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 = "Indianapolis Public Schools Decline",
subtitle = "Lost over 15,000 students since 2006",
x = "School Year", y = "Students") +
theme_readme()
3. Hamilton County added 16,000 students since 2006
Carmel, Fishers, Westfield, and Noblesville suburbs are booming. These four Hamilton County corporations grew from about 42,000 to nearly 58,000 students – a 38% increase.
hamilton <- c("Carmel Clay Schools", "Hamilton Southeastern Schools",
"Noblesville Schools", "Westfield-Washington Schools")
hamilton_trend <- enr %>%
filter(corporation_name %in% hamilton, is_corporation,
grade_level == "TOTAL", subgroup == "total_enrollment") %>%
group_by(end_year) %>%
summarize(total = sum(n_students, na.rm = TRUE), .groups = "drop")
stopifnot(nrow(hamilton_trend) > 0)
hamilton_trend
#> # A tibble: 10 × 2
#> end_year total
#> <int> <dbl>
#> 1 2017 55465
#> 2 2018 56306
#> 3 2019 56681
#> 4 2020 57958
#> 5 2021 57117
#> 6 2022 57281
#> 7 2023 57442
#> 8 2024 57687
#> 9 2025 57856
#> 10 2026 57290
ggplot(hamilton_trend, aes(x = end_year, y = total)) +
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 = "Hamilton County: Indiana's Growth Engine",
subtitle = "Carmel, Fishers, Noblesville, Westfield combined",
x = "School Year", y = "Students") +
theme_readme()
4. Hispanic enrollment has more than doubled
Hispanic students grew from 5.8% to 14.6% of enrollment since 2006, a 2.5x increase. Northwest Indiana and Indianapolis drive this demographic shift.
hispanic <- enr_long %>%
filter(is_state, grade_level == "TOTAL", subgroup == "hispanic")
stopifnot(nrow(hispanic) > 0)
hispanic %>% select(end_year, n_students, pct) %>%
mutate(pct_display = round(pct * 100, 1))
#> end_year n_students pct pct_display
#> 1 2006 62718 0.05765497 5.8
#> 2 2011 87790 0.08384341 8.4
#> 3 2016 116671 0.11148398 11.1
#> 4 2021 135497 0.13106935 13.1
#> 5 2026 158808 0.15441249 15.4
ggplot(hispanic, aes(x = end_year, y = pct * 100)) +
geom_line(linewidth = 1.5, color = colors["hispanic"]) +
geom_point(size = 3, color = colors["hispanic"]) +
labs(title = "Hispanic Student Population in Indiana",
subtitle = "More than doubled from 5.8% to 14.6% since 2006",
x = "School Year", y = "Percent of Students") +
theme_readme()
5. COVID erased 5,600 kindergartners in one year
Indiana kindergarten enrollment dropped from 78,649 in 2020 to 72,993 in 2021 – a loss of nearly 5,700 students. Recovery has been uneven.
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)
#> end_year n_students
#> 1 2017 76870
#> 2 2018 77905
#> 3 2019 75746
#> 4 2020 78649
#> 5 2021 72993
#> 6 2022 76514
#> 7 2023 74124
#> 8 2024 72955
#> 9 2025 71379
#> 10 2026 69849
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 Indiana Kindergarten Hard",
subtitle = "Lost 5,600 kindergartners between 2020 and 2021",
x = "School Year", y = "Students", color = "") +
theme_readme()
6. White enrollment dropped 15 points while Hispanic surged
Indiana’s racial composition shifted dramatically since 2006. White students went from 78% to 63% while Hispanic students rose from 6% to 15%. Black enrollment has been comparatively stable.
race_trend <- enr_long %>%
filter(is_state, grade_level == "TOTAL", subgroup %in% c("black", "hispanic", "white")) %>%
mutate(subgroup = factor(subgroup, levels = c("white", "black", "hispanic"),
labels = c("White", "Black", "Hispanic")))
stopifnot(nrow(race_trend) > 0)
race_trend %>%
select(end_year, subgroup, pct) %>%
mutate(pct = round(pct * 100, 1))
#> end_year subgroup pct
#> 1 2006 White 78.0
#> 2 2006 Black 11.5
#> 3 2006 Hispanic 5.8
#> 4 2011 White 73.1
#> 5 2011 Black 12.1
#> 6 2011 Hispanic 8.4
#> 7 2016 White 69.3
#> 8 2016 Black 12.4
#> 9 2016 Hispanic 11.1
#> 10 2021 White 65.8
#> 11 2021 Black 12.9
#> 12 2021 Hispanic 13.1
#> 13 2026 White 61.4
#> 14 2026 Black 13.9
#> 15 2026 Hispanic 15.4
ggplot(race_trend, aes(x = end_year, y = pct * 100, color = subgroup)) +
geom_line(linewidth = 1.2) +
geom_point(size = 2.5) +
scale_color_manual(values = c("White" = colors["white"], "Black" = colors["black"],
"Hispanic" = colors["hispanic"])) +
labs(title = "Indiana's Racial Demographics Are Shifting Fast",
subtitle = "White share fell 15 points while Hispanic share nearly tripled",
x = "School Year", y = "Percent of Students", color = "") +
theme_readme()
7. Gary lost 73% of its students since 2006
Gary Community School Corp went from 15,119 students in 2006 to just 4,025 in 2024, one of the steepest enrollment declines of any school district in America.
gary <- enr_long %>%
filter(is_corporation, grepl("Gary Community", corporation_name, ignore.case = TRUE),
subgroup == "total_enrollment", grade_level == "TOTAL")
stopifnot(nrow(gary) > 0)
gary %>% select(end_year, corporation_name, n_students)
#> end_year corporation_name n_students
#> 1 2006 Gary Community School Corp 15119
#> 2 2011 Gary Community School Corp 11161
#> 3 2016 Gary Community School Corp 6480
#> 4 2021 Gary Community School Corp 4770
#> 5 2026 Gary Community School Corp 4025
ggplot(gary, 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 = "Gary Community Schools Collapse",
subtitle = "From 15,100 to 4,000 -- a 73% decline since 2006",
x = "School Year", y = "Students") +
theme_readme()
8. Indiana Connections Academy is the largest virtual school
Indiana Connections Academy serves over 5,400 students, making it by far the largest virtual school in the state.
virtual <- enr_current %>%
filter(grepl("Virtual|Online|Connections|Digital", corporation_name, ignore.case = TRUE),
grade_level == "TOTAL", subgroup == "total_enrollment") %>%
distinct(corporation_name, .keep_all = TRUE) %>%
arrange(desc(n_students)) %>%
head(10) %>%
mutate(corp_label = reorder(corporation_name, n_students))
stopifnot(nrow(virtual) > 0)
virtual %>% select(corporation_name, n_students)
#> corporation_name n_students
#> 1 Indiana Connections Academy 7-12 5027
#> 2 Indiana Connections Academy K-6 1631
#> 3 Phalen Virtual Leadership Academy 255
#> 4 Paramount Online Academy 151
ggplot(virtual, aes(x = corp_label, y = n_students)) +
geom_col(fill = colors["total"]) +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(title = "Indiana's Virtual Schools",
subtitle = "Indiana Connections Academy leads with 5,400+ students",
x = "", y = "Students") +
theme_readme()
9. Evansville is slowly losing students
Evansville Vanderburgh School Corp peaked around 22,800 and has gradually declined to about 21,400 – a modest but steady loss of about 5% over the past decade.
evansville <- enr %>%
filter(is_corporation, grepl("Evansville Vanderburgh", corporation_name, ignore.case = TRUE),
subgroup == "total_enrollment", grade_level == "TOTAL")
stopifnot(nrow(evansville) > 0)
evansville %>% select(end_year, corporation_name, n_students)
#> end_year corporation_name n_students
#> 1 2017 Evansville Vanderburgh School Corp 22801
#> 2 2018 Evansville Vanderburgh School Corp 22844
#> 3 2019 Evansville Vanderburgh School Corp 22601
#> 4 2020 Evansville Vanderburgh School Corp 22822
#> 5 2021 Evansville Vanderburgh School Corp 22192
#> 6 2022 Evansville Vanderburgh School Corp 21942
#> 7 2023 Evansville Vanderburgh School Corp 21741
#> 8 2024 Evansville Vanderburgh School Corp 21442
#> 9 2025 Evansville Vanderburgh School Corp 21589
#> 10 2026 Evansville Vanderburgh School Corp 20914
ggplot(evansville, 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 = "Evansville Vanderburgh School Corp",
subtitle = "Gradual decline from 22,800 to 21,400 over the past decade",
x = "School Year", y = "Students") +
theme_readme()
10. Indiana’s school system has grown more fragmented
Indiana went from 330 corporations in 2006 to 418 in 2024. Rather than consolidating, the state has added charter schools and virtual academies that count as new corporations.
corp_counts <- enr_long %>%
filter(is_corporation, subgroup == "total_enrollment", grade_level == "TOTAL") %>%
group_by(end_year) %>%
summarize(n_corporations = n(), .groups = "drop")
stopifnot(nrow(corp_counts) > 0)
corp_counts
#> # A tibble: 5 × 2
#> end_year n_corporations
#> <dbl> <int>
#> 1 2006 330
#> 2 2011 357
#> 3 2016 386
#> 4 2021 406
#> 5 2026 430
ggplot(corp_counts, aes(x = end_year, y = n_corporations)) +
geom_line(linewidth = 1.5, color = colors["total"]) +
geom_point(size = 3, color = colors["total"]) +
labs(title = "Indiana's Corporation Count Has Grown",
subtitle = "From 330 in 2006 to 418 in 2024 -- charters and virtual schools drive the increase",
x = "School Year", y = "Number of Corporations") +
theme_readme()
11. Fort Wayne is Indiana’s largest district at 28,500 students
Fort Wayne Community Schools is the largest district in Indiana with about 28,500 students, edging out Indianapolis Public Schools which has fallen to around 21,900.
fort_wayne <- enr %>%
filter(is_corporation, grepl("Fort Wayne Community", corporation_name, ignore.case = TRUE),
subgroup == "total_enrollment", grade_level == "TOTAL")
stopifnot(nrow(fort_wayne) > 0)
fort_wayne %>% select(end_year, corporation_name, n_students)
#> end_year corporation_name n_students
#> 1 2017 Fort Wayne Community Schools 29377
#> 2 2018 Fort Wayne Community Schools 29469
#> 3 2019 Fort Wayne Community Schools 29404
#> 4 2020 Fort Wayne Community Schools 29486
#> 5 2021 Fort Wayne Community Schools 28460
#> 6 2022 Fort Wayne Community Schools 28778
#> 7 2023 Fort Wayne Community Schools 28613
#> 8 2024 Fort Wayne Community Schools 28504
#> 9 2025 Fort Wayne Community Schools 28549
#> 10 2026 Fort Wayne Community Schools 28200
ggplot(fort_wayne, 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 = "Fort Wayne Community Schools",
subtitle = "Indiana's largest district at ~28,500 students",
x = "School Year", y = "Students") +
theme_readme()
12. Black enrollment share has risen slightly since 2006
Despite a common misconception, Indiana’s Black student share has actually edged up from 11.5% in 2006 to 13.4% in 2024, while Black student counts grew from 125,000 to 138,000.
black_trend <- enr_long %>%
filter(is_state, grade_level == "TOTAL", subgroup == "black")
stopifnot(nrow(black_trend) > 0)
black_trend %>% select(end_year, n_students, pct) %>%
mutate(pct_display = round(pct * 100, 1))
#> end_year n_students pct pct_display
#> 1 2006 125305 0.1151895 11.5
#> 2 2011 126350 0.1206699 12.1
#> 3 2016 129809 0.1240379 12.4
#> 4 2021 132917 0.1285737 12.9
#> 5 2026 142645 0.1386969 13.9
ggplot(black_trend, aes(x = end_year, y = pct * 100)) +
geom_line(linewidth = 1.5, color = colors["black"]) +
geom_point(size = 3, color = colors["black"]) +
labs(title = "Black Student Enrollment Share in Indiana",
subtitle = "Edged up from 11.5% to 13.4% since 2006",
x = "School Year", y = "Percent of Students") +
theme_readme()
13. South Bend has lost a third of its students
South Bend Community School Corp went from nearly 21,900 students in 2006 to about 14,500 in 2024 – a loss of 34%.
south_bend <- enr_long %>%
filter(is_corporation, grepl("South Bend Community", corporation_name, ignore.case = TRUE),
subgroup == "total_enrollment", grade_level == "TOTAL")
stopifnot(nrow(south_bend) > 0)
south_bend %>% select(end_year, corporation_name, n_students)
#> end_year corporation_name n_students
#> 1 2006 South Bend Community Sch Corp 21861
#> 2 2011 South Bend Community Sch Corp 19948
#> 3 2016 South Bend Community Sch Corp 18680
#> 4 2021 South Bend Community School Corp 16302
#> 5 2026 South Bend Community School Corp 12851
ggplot(south_bend, 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 = "South Bend Community Schools",
subtitle = "Lost 34% of enrollment since 2006",
x = "School Year", y = "Students") +
theme_readme()
14. Asian students are the fastest-growing demographic in percentage terms
Asian enrollment went from 1.2% to 3.0% of Indiana’s total since 2006. While a smaller population than Hispanic growth, it represents a 2.5x increase in share.
asian_trend <- enr_long %>%
filter(is_state, grade_level == "TOTAL", subgroup == "asian")
stopifnot(nrow(asian_trend) > 0)
asian_trend %>% select(end_year, n_students, pct) %>%
mutate(pct_display = round(pct * 100, 1))
#> end_year n_students pct pct_display
#> 1 2006 0 0.00000000 0.0
#> 2 2011 16970 0.01620711 1.6
#> 3 2016 22519 0.02151784 2.2
#> 4 2021 28265 0.02734138 2.7
#> 5 2026 33483 0.03255625 3.3
ggplot(asian_trend, aes(x = end_year, y = pct * 100)) +
geom_line(linewidth = 1.5, color = colors["asian"]) +
geom_point(size = 3, color = colors["asian"]) +
labs(title = "Asian Student Enrollment in Indiana",
subtitle = "Share grew from 1.2% to 3.0% since 2006",
x = "School Year", y = "Percent of Students") +
theme_readme()
15. The top 20 corporations serve 29% of all students
The 20 largest corporations educate nearly 300,000 of Indiana’s 1.03 million students. Fort Wayne, Indianapolis, and Evansville lead the pack.
top_corps <- enr_current %>%
filter(is_corporation, grade_level == "TOTAL", subgroup == "total_enrollment") %>%
arrange(desc(n_students)) %>%
head(20) %>%
mutate(corp_label = reorder(corporation_name, n_students))
stopifnot(nrow(top_corps) > 0)
top_corps %>% select(corporation_name, n_students)
#> corporation_name n_students
#> 1 Fort Wayne Community Schools 28200
#> 2 Evansville Vanderburgh School Corp 20914
#> 3 Hamilton Southeastern Schools 20633
#> 4 Indianapolis Public Schools 19774
#> 5 MSD Lawrence Township 16709
#> 6 Carmel Clay Schools 15913
#> 7 MSD Wayne Township 15734
#> 8 Perry Township Schools 15726
#> 9 Tippecanoe School Corp 13423
#> 10 Vigo County School Corp 12986
#> 11 South Bend Community School Corp 12851
#> 12 Franklin Township Com Sch Corp 11572
#> 13 MSD Warren Township 11502
#> 14 Bartholomew Con School Corp 11459
#> 15 MSD Washington Township 11325
#> 16 New Albany-Floyd Co Con Sch 11218
#> 17 Penn-Harris-Madison School Corp 11185
#> 18 Avon Community School Corp 10735
#> 19 MSD Pike Township 10640
#> 20 Greater Clark County Schools 10627
ggplot(top_corps, aes(x = corp_label, y = n_students)) +
geom_col(fill = colors["total"]) +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(title = "Top 20 Corporations by Enrollment",
subtitle = "The largest 20 districts serve 29% of Indiana students",
x = "", y = "Students") +
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 inschooldata_0.2.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 readxl_1.4.5
#> [9] yaml_2.3.12 fastmap_1.2.0 R6_2.6.1 labeling_0.4.3
#> [13] generics_0.1.4 curl_7.0.0 knitr_1.51 tibble_3.3.1
#> [17] desc_1.4.3 bslib_0.10.0 pillar_1.11.1 RColorBrewer_1.1-3
#> [21] rlang_1.1.7 cachem_1.1.0 xfun_0.56 fs_1.6.7
#> [25] sass_0.4.10 S7_0.2.1 cli_3.6.5 pkgdown_2.2.0
#> [29] withr_3.0.2 magrittr_2.0.4 digest_0.6.39 grid_4.5.2
#> [33] rappdirs_0.3.4 lifecycle_1.0.5 vctrs_0.7.1 evaluate_1.0.5
#> [37] glue_1.8.0 cellranger_1.1.0 farver_2.1.2 codetools_0.2-20
#> [41] ragg_1.5.1 rmarkdown_2.30 purrr_1.2.1 httr_1.4.8
#> [45] tools_4.5.2 pkgconfig_2.0.3 htmltools_0.5.9