Skip to contents
library(coschooldata)
library(dplyr)
library(tidyr)
library(ggplot2)

theme_set(theme_minimal(base_size = 14))

# Load pre-computed data bundled with the package.
# This ensures vignettes build reliably in CI without network access.
# Falls back to live fetch if bundled data is unavailable.
enr <- tryCatch(
  readRDS(system.file("extdata", "enrollment_bundled.rds", package = "coschooldata")),
  error = function(e) {
    warning("Bundled data not found, fetching live data")
    fetch_enr_multi(c(2020, 2024), use_cache = TRUE)
  }
)
if (is.null(enr) || nrow(enr) == 0) {
  enr <- fetch_enr_multi(c(2020, 2024), use_cache = TRUE)
}

enr_2024 <- tryCatch(
  readRDS(system.file("extdata", "enrollment_2024_tidy.rds", package = "coschooldata")),
  error = function(e) {
    warning("Bundled data not found, fetching live data")
    fetch_enr(2024, use_cache = TRUE)
  }
)
if (is.null(enr_2024) || nrow(enr_2024) == 0) {
  enr_2024 <- fetch_enr(2024, use_cache = TRUE)
}

This vignette explores Colorado’s public school enrollment data, surfacing key trends and demographic patterns. Colorado is part of the state schooldata project, a family of R packages providing consistent access to school enrollment data from all 50 states.

Data years: 2020 and 2024 (Student October Count, collected by the Colorado Department of Education). 881,000 students across 187 districts in the Centennial State.


1. Colorado lost 31,584 students since 2020

The pandemic accelerated enrollment decline in a state that had been growing for a decade. Colorado shed 3.5% of its student population between 2020 and 2024.

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))

stopifnot(nrow(state_totals) > 0)
state_totals
#>   end_year n_students change pct_change
#> 1     2020     913030     NA         NA
#> 2     2024     881446 -31584      -3.46
print(state_totals)
#>   end_year n_students change pct_change
#> 1     2020     913030     NA         NA
#> 2     2024     881446 -31584      -3.46

ggplot(state_totals, aes(x = end_year, y = n_students)) +
  geom_line(linewidth = 1.2, color = "#003366") +
  geom_point(size = 3, color = "#003366") +
  geom_vline(xintercept = 2020.5, linetype = "dashed", alpha = 0.5) +
  annotate("text", x = 2020.5, y = max(state_totals$n_students) * 0.99,
           label = "COVID", hjust = -0.1, size = 3) +
  scale_y_continuous(labels = scales::comma, limits = c(850000, NA)) +
  labs(
    title = "Colorado Public School Enrollment (2020 vs 2024)",
    subtitle = "31,584 fewer students -- a 3.5% decline",
    x = "School Year (ending)",
    y = "Total Enrollment"
  )


2. Denver lost 3,877 students but remains the largest district

Denver County 1 dropped from 92,112 to 88,235 students, a 4.2% decline. Despite the losses, it is still Colorado’s biggest district by a wide margin.

denver <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Denver County", district_name)) |>
  select(end_year, district_name, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 2))

stopifnot(nrow(denver) > 0)
denver
#>   end_year   district_name n_students change pct_change
#> 1     2020 Denver County 1      92112     NA         NA
#> 2     2024 Denver County 1      88235  -3877      -4.21
top4 <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Denver County|Douglas County|Jefferson County|Cherry Creek", district_name))

stopifnot(nrow(top4) > 0)
print(top4 |> select(end_year, district_name, n_students))
#>   end_year        district_name n_students
#> 1     2020       Cherry Creek 5      56172
#> 2     2020      Denver County 1      92112
#> 3     2020  Douglas County Re 1      67305
#> 4     2020 Jefferson County R-1      84032
#> 5     2024       Cherry Creek 5      52419
#> 6     2024      Denver County 1      88235
#> 7     2024  Douglas County Re 1      61964
#> 8     2024 Jefferson County R-1      76172

ggplot(top4, aes(x = end_year, y = n_students, color = district_name)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 3) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Colorado's Largest Districts: All Declining",
    subtitle = "Denver, Jeffco, Douglas County, and Cherry Creek all lost students",
    x = "School Year",
    y = "Enrollment",
    color = "District"
  )


3. Jefferson County lost 7,860 students – shrinking faster than Denver

Jeffco shed 9.4% of its enrollment between 2020 and 2024, nearly 8,000 students. That is a steeper percentage decline than Denver.

jeffco <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Jefferson County", district_name)) |>
  select(end_year, district_name, n_students) |>
  mutate(change = n_students - lag(n_students),
         pct_change = round(change / lag(n_students) * 100, 2))

stopifnot(nrow(jeffco) > 0)
jeffco
#>   end_year        district_name n_students change pct_change
#> 1     2020 Jefferson County R-1      84032     NA         NA
#> 2     2024 Jefferson County R-1      76172  -7860      -9.35
front_range <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         grepl("Jefferson County|Denver County|Douglas County", district_name))

print(front_range |> select(end_year, district_name, n_students))
#>   end_year        district_name n_students
#> 1     2020      Denver County 1      92112
#> 2     2020  Douglas County Re 1      67305
#> 3     2020 Jefferson County R-1      84032
#> 4     2024      Denver County 1      88235
#> 5     2024  Douglas County Re 1      61964
#> 6     2024 Jefferson County R-1      76172

ggplot(front_range, aes(x = end_year, y = n_students, color = district_name)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 3) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Front Range Giants: Enrollment Trends",
    subtitle = "Jeffco's 9.4% decline outpaces Denver's 4.2%",
    x = "School Year",
    y = "Enrollment",
    color = "District"
  )


4. Hispanic students are now 35.5% of enrollment

Hispanic students make up the second-largest group in Colorado, just behind white students. The Hispanic share grew from 33.9% in 2020 to 35.5% in 2024.

demographics <- enr_2024 |>
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("hispanic", "white", "black", "asian",
                         "native_american", "multiracial", "pacific_islander")) |>
  mutate(pct = round(pct * 100, 1)) |>
  select(subgroup, n_students, pct) |>
  arrange(desc(n_students))

stopifnot(nrow(demographics) > 0)
demographics
#>           subgroup n_students  pct
#> 1            white     444973 50.5
#> 2         hispanic     312685 35.5
#> 3      multiracial      46570  5.3
#> 4            black      40070  4.5
#> 5            asian      28899  3.3
#> 6  native_american       5348  0.6
#> 7 pacific_islander       2901  0.3
print(demographics)
#>           subgroup n_students  pct
#> 1            white     444973 50.5
#> 2         hispanic     312685 35.5
#> 3      multiracial      46570  5.3
#> 4            black      40070  4.5
#> 5            asian      28899  3.3
#> 6  native_american       5348  0.6
#> 7 pacific_islander       2901  0.3

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 = "Colorado Student Demographics (2024)",
    subtitle = "Hispanic students are over a third of enrollment",
    x = "Number of Students",
    y = NULL
  )


5. White share dropped below 52.9% to 50.5% in four years

White students are still the largest group but their share fell 2.4 percentage points while the multiracial population surged from 4.5% to 5.3%.

demo_shift <- enr |>
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
  select(end_year, subgroup, n_students, pct) |>
  mutate(pct = round(pct * 100, 1))

stopifnot(nrow(demo_shift) > 0)
demo_shift
#>    end_year    subgroup n_students  pct
#> 1      2020       asian      29207  3.2
#> 2      2020       black      41550  4.6
#> 3      2020    hispanic     309900 33.9
#> 4      2020 multiracial      40785  4.5
#> 5      2020       white     482951 52.9
#> 6      2024       asian      28899  3.3
#> 7      2024       black      40070  4.5
#> 8      2024    hispanic     312685 35.5
#> 9      2024 multiracial      46570  5.3
#> 10     2024       white     444973 50.5

6. 261 charter schools serve 135,223 students

Colorado has one of the most expansive charter sectors in the country. Charter schools now enroll 15.3% of all public school students.

charters <- enr_2024 |>
  filter(is_school, is_charter, subgroup == "total_enrollment", grade_level == "TOTAL")

state_total <- enr_2024 |>
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  pull(n_students)

charter_summary <- tibble(
  sector = c("All Public Schools", "Charter Schools"),
  enrollment = c(state_total, sum(charters$n_students, na.rm = TRUE)),
  pct = c(100, round(sum(charters$n_students, na.rm = TRUE) / state_total * 100, 1))
)

stopifnot(charter_summary$enrollment[2] > 0)
charter_summary
#> # A tibble: 2 × 3
#>   sector             enrollment   pct
#>   <chr>                   <dbl> <dbl>
#> 1 All Public Schools     881446 100  
#> 2 Charter Schools        135223  15.3
top_charters <- charters |>
  arrange(desc(n_students)) |>
  head(5) |>
  select(district_name, campus_name, n_students)

print(top_charters)
#>              district_name                     campus_name n_students
#> 1              District 49                    GOAL Academy       6142
#> 2      Douglas County Re 1                American Academy       2579
#> 3               Academy 20   The Classical Academy Charter       2149
#> 4 Charter School Institute Colorado Early Colleges Windsor       2139
#> 5 Charter School Institute     The Pinnacle Charter School       1909

7. Adams-Arapahoe (Aurora) is Colorado’s most diverse district

Aurora Public Schools has no racial majority. Hispanic students make up 57.3%, followed by Black (16.8%), White (13.7%), Multiracial (5.9%), and Asian (4.8%).

aurora <- enr_2024 |>
  filter(is_district, grade_level == "TOTAL",
         grepl("Adams-Arapahoe", district_name),
         subgroup %in% c("hispanic", "white", "black", "asian", "multiracial")) |>
  mutate(pct = round(pct * 100, 1)) |>
  select(district_name, subgroup, n_students, pct) |>
  arrange(desc(pct))

stopifnot(nrow(aurora) > 0)
aurora
#>        district_name    subgroup n_students  pct
#> 1 Adams-Arapahoe 28J    hispanic      22430 57.3
#> 2 Adams-Arapahoe 28J       black       6573 16.8
#> 3 Adams-Arapahoe 28J       white       5355 13.7
#> 4 Adams-Arapahoe 28J multiracial       2305  5.9
#> 5 Adams-Arapahoe 28J       asian       1867  4.8

8. Nearly half of Colorado students qualify for free or reduced lunch

45.2% of Colorado students – 398,112 children – are economically disadvantaged, qualifying for free or reduced-price lunch.

frl <- enr_2024 |>
  filter(is_state, grade_level == "TOTAL",
         subgroup == "free_reduced_lunch") |>
  mutate(pct = round(pct * 100, 1)) |>
  select(subgroup, n_students, pct)

stopifnot(nrow(frl) > 0)
frl
#>             subgroup n_students  pct
#> 1 free_reduced_lunch     398112 45.2
frl_districts <- enr_2024 |>
  filter(is_district, subgroup == "free_reduced_lunch", grade_level == "TOTAL") |>
  mutate(pct = round(pct * 100, 1)) |>
  filter(n_students >= 1000) |>
  arrange(desc(pct)) |>
  head(10) |>
  select(district_name, n_students, pct)

print(frl_districts)
#>                 district_name n_students  pct
#> 1             Adams County 14       4728 86.2
#> 2  Westminster Public Schools       6442 84.4
#> 3              Pueblo City 60      12130 83.4
#> 4          Adams-Arapahoe 28J      31204 79.7
#> 5              East Otero R-1       1055 79.6
#> 6                  Lamar Re-2       1117 76.3
#> 7                  Mapleton 1       5292 75.4
#> 8              Alamosa RE-11J       1495 72.7
#> 9                  Harrison 2       8803 71.1
#> 10                  Greeley 6      16071 71.0

frl_districts |>
  mutate(district_name = forcats::fct_reorder(district_name, pct)) |>
  ggplot(aes(x = pct, y = district_name)) +
  geom_col(fill = "#E65100") +
  geom_text(aes(label = paste0(pct, "%")), hjust = -0.1) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.15))) +
  labs(
    title = "Most Economically Disadvantaged Districts (2024)",
    subtitle = "Free/Reduced Lunch rate among districts with 1,000+ students",
    x = "FRL %",
    y = NULL
  )


9. Byers 32J grew 175% in four years

Byers 32J, northeast of Denver, surged from 2,344 to 6,456 students – the fastest growth rate of any district in Colorado.

changes <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  select(end_year, district_name, n_students) |>
  pivot_wider(names_from = end_year, values_from = n_students, values_fn = sum) |>
  filter(!is.na(`2020`) & !is.na(`2024`)) |>
  mutate(change = `2024` - `2020`,
         pct_change = round(change / `2020` * 100, 1)) |>
  filter(`2020` >= 1000)

gainers <- changes |>
  arrange(desc(pct_change)) |>
  head(10)

stopifnot(nrow(gainers) > 0)
gainers
#> # A tibble: 10 × 5
#>    district_name                `2020` `2024` change pct_change
#>    <chr>                         <dbl>  <dbl>  <dbl>      <dbl>
#>  1 Byers 32J                      2344   6456   4112      175. 
#>  2 Education reEnvisioned BOCES   2836   7114   4278      151. 
#>  3 Bennett 29J                    1117   1645    528       47.3
#>  4 Charter School Institute      18275  23013   4738       25.9
#>  5 School District 27J           19248  23108   3860       20.1
#>  6 Elizabeth School District      2373   2614    241       10.2
#>  7 Strasburg 31J                  1080   1187    107        9.9
#>  8 District 49                   23890  25799   1909        8  
#>  9 Platte Valley RE-7             1093   1179     86        7.9
#> 10 Harrison 2                    11518  12386    868        7.5

10. 9 of the 10 largest districts lost students

Academy 20 was the sole top-10 district to hold steady (gaining 4 students). Everyone else shrank, led by Jefferson County (-9.4%) and Adams 12 Five Star (-9.4%).

top10_names <- enr_2024 |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  arrange(desc(n_students)) |>
  head(10) |>
  pull(district_name)

top10_compare <- enr |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL",
         district_name %in% top10_names) |>
  select(end_year, district_name, n_students) |>
  pivot_wider(names_from = end_year, values_from = n_students, values_fn = sum) |>
  mutate(change = `2024` - `2020`,
         pct_change = round(change / `2020` * 100, 1)) |>
  arrange(pct_change)

stopifnot(nrow(top10_compare) == 10)
top10_compare
#> # A tibble: 10 × 5
#>    district_name              `2020` `2024` change pct_change
#>    <chr>                       <dbl>  <dbl>  <dbl>      <dbl>
#>  1 Adams 12 Five Star Schools  38648  34998  -3650       -9.4
#>  2 Jefferson County R-1        84032  76172  -7860       -9.4
#>  3 Boulder Valley Re 2         31000  28362  -2638       -8.5
#>  4 Douglas County Re 1         67305  61964  -5341       -7.9
#>  5 Cherry Creek 5              56172  52419  -3753       -6.7
#>  6 Denver County 1             92112  88235  -3877       -4.2
#>  7 Poudre R-1                  30727  29896   -831       -2.7
#>  8 Adams-Arapahoe 28J          40088  39148   -940       -2.3
#>  9 St Vrain Valley RE1J        32855  32506   -349       -1.1
#> 10 Academy 20                  26603  26607      4        0
print(top10_compare)
#> # A tibble: 10 × 5
#>    district_name              `2020` `2024` change pct_change
#>    <chr>                       <dbl>  <dbl>  <dbl>      <dbl>
#>  1 Adams 12 Five Star Schools  38648  34998  -3650       -9.4
#>  2 Jefferson County R-1        84032  76172  -7860       -9.4
#>  3 Boulder Valley Re 2         31000  28362  -2638       -8.5
#>  4 Douglas County Re 1         67305  61964  -5341       -7.9
#>  5 Cherry Creek 5              56172  52419  -3753       -6.7
#>  6 Denver County 1             92112  88235  -3877       -4.2
#>  7 Poudre R-1                  30727  29896   -831       -2.7
#>  8 Adams-Arapahoe 28J          40088  39148   -940       -2.3
#>  9 St Vrain Valley RE1J        32855  32506   -349       -1.1
#> 10 Academy 20                  26603  26607      4        0

top10_compare |>
  mutate(district_name = forcats::fct_reorder(district_name, pct_change)) |>
  ggplot(aes(x = pct_change, y = district_name,
             fill = ifelse(pct_change >= 0, "gain", "loss"))) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = paste0(pct_change, "%")),
            hjust = ifelse(top10_compare$pct_change >= 0, -0.1, 1.1)) +
  scale_fill_manual(values = c("gain" = "#4CAF50", "loss" = "#F44336")) +
  labs(
    title = "Top 10 Districts: Change from 2020 to 2024",
    subtitle = "Only Academy 20 held steady; the rest all shrank",
    x = "% Change",
    y = NULL
  )


11. 115 tiny districts serve fewer than 1,000 students each

Colorado has an extraordinarily fragmented school system. Over 60% of districts enroll fewer than 1,000 students, though they educate a small fraction of the total.

size_cats <- enr_2024 |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  mutate(size = case_when(
    n_students >= 20000 ~ "Large (20K+)",
    n_students >= 5000 ~ "Medium (5K-20K)",
    n_students >= 1000 ~ "Small (1K-5K)",
    TRUE ~ "Tiny (<1K)"
  )) |>
  group_by(size) |>
  summarize(
    n_districts = n(),
    total_students = sum(n_students),
    .groups = "drop"
  ) |>
  mutate(pct_students = round(total_students / sum(total_students) * 100, 1))

stopifnot(nrow(size_cats) > 0)
size_cats
#> # A tibble: 4 × 4
#>   size            n_districts total_students pct_students
#>   <chr>                 <int>          <dbl>        <dbl>
#> 1 Large (20K+)             16         607827         69  
#> 2 Medium (5K-20K)          18         155496         17.6
#> 3 Small (1K-5K)            37          78414          8.9
#> 4 Tiny (<1K)              115          39709          4.5
smallest <- enr_2024 |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  arrange(n_students) |>
  head(10) |>
  select(district_name, n_students)

print(smallest)
#>         district_name n_students
#> 1  Kim Reorganized 88         26
#> 2          Campo RE-6         31
#> 3        Karval RE-23         36
#> 4      San Juan BOCES         51
#> 5      Pritchett RE-3         61
#> 6         Liberty J-4         64
#> 7        Pawnee RE-12         68
#> 8        Edison 54 JT         74
#> 9           Agate 300         75
#> 10        Silverton 1         75

12. Las Animas RE-1 lost 60% of its enrollment

The starkest decline in Colorado. Las Animas RE-1 went from 2,406 students in 2020 to just 956 in 2024 – a loss of 1,450 students.

losers <- changes |>
  arrange(pct_change) |>
  head(10)

stopifnot(nrow(losers) > 0)
losers
#> # A tibble: 10 × 5
#>    district_name              `2020` `2024` change pct_change
#>    <chr>                       <dbl>  <dbl>  <dbl>      <dbl>
#>  1 Las Animas RE-1              2406    956  -1450      -60.3
#>  2 Cheyenne Mountain 12         5309   3739  -1570      -29.6
#>  3 Mapleton 1                   9131   7017  -2114      -23.2
#>  4 Sheridan 2                   1359   1058   -301      -22.1
#>  5 Adams County 14              6610   5484  -1126      -17  
#>  6 Valley RE-1                  2258   1887   -371      -16.4
#>  7 Westminster Public Schools   9089   7631  -1458      -16  
#>  8 Manitou Springs 14           1441   1238   -203      -14.1
#>  9 Monte Vista C-8              1168   1010   -158      -13.5
#> 10 Ellicott 22                  1142    990   -152      -13.3

13. Adams County 14 has 86% economically disadvantaged students

Adams County 14, in the northern Denver metro area, has the highest free/reduced lunch rate among districts with 1,000+ students.

frl_top5 <- enr_2024 |>
  filter(is_district, subgroup == "free_reduced_lunch", grade_level == "TOTAL") |>
  mutate(pct = round(pct * 100, 1)) |>
  filter(n_students >= 1000) |>
  arrange(desc(pct)) |>
  head(5) |>
  select(district_name, n_students, pct)

stopifnot(nrow(frl_top5) > 0)
frl_top5
#>                district_name n_students  pct
#> 1            Adams County 14       4728 86.2
#> 2 Westminster Public Schools       6442 84.4
#> 3             Pueblo City 60      12130 83.4
#> 4         Adams-Arapahoe 28J      31204 79.7
#> 5             East Otero R-1       1055 79.6

14. Colorado’s gender split: 51.3% male, 48.7% female

Like most states, Colorado enrolls slightly more boys than girls – a gap of about 23,000 students.

gender <- enr_2024 |>
  filter(is_state, grade_level == "TOTAL",
         subgroup %in% c("male", "female")) |>
  mutate(pct = round(pct * 100, 1)) |>
  select(subgroup, n_students, pct)

stopifnot(nrow(gender) == 2)
gender
#>   subgroup n_students  pct
#> 1   female     428834 48.7
#> 2     male     452215 51.3
print(gender)
#>   subgroup n_students  pct
#> 1   female     428834 48.7
#> 2     male     452215 51.3

gender |>
  mutate(subgroup = factor(subgroup, levels = c("female", "male"))) |>
  ggplot(aes(x = subgroup, y = n_students, fill = subgroup)) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = paste0(scales::comma(n_students), "\n(", pct, "%)")),
            vjust = -0.2, size = 4) +
  scale_y_continuous(labels = scales::comma, expand = expansion(mult = c(0, 0.15))) +
  scale_fill_manual(values = c("female" = "#E91E63", "male" = "#2196F3")) +
  labs(
    title = "Colorado Student Gender Distribution (2024)",
    subtitle = "23,381 more boys than girls enrolled",
    x = NULL,
    y = "Number of Students"
  )


15. Top 10 districts serve 55% of all students

Just 10 districts out of 187 educate more than half of Colorado’s public school students, showing extreme concentration of enrollment in the Front Range metro areas.

district_totals <- enr_2024 |>
  filter(is_district, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  arrange(desc(n_students)) |>
  head(10) |>
  select(district_name, n_students)

state_total_val <- enr_2024 |>
  filter(is_state, subgroup == "total_enrollment", grade_level == "TOTAL") |>
  pull(n_students)

top_10_pct <- round(sum(district_totals$n_students) / state_total_val * 100, 1)

result <- district_totals |>
  mutate(pct_of_state = round(n_students / state_total_val * 100, 1))

stopifnot(nrow(result) == 10)
result
#>                 district_name n_students pct_of_state
#> 1             Denver County 1      88235         10.0
#> 2        Jefferson County R-1      76172          8.6
#> 3         Douglas County Re 1      61964          7.0
#> 4              Cherry Creek 5      52419          5.9
#> 5          Adams-Arapahoe 28J      39148          4.4
#> 6  Adams 12 Five Star Schools      34998          4.0
#> 7        St Vrain Valley RE1J      32506          3.7
#> 8                  Poudre R-1      29896          3.4
#> 9         Boulder Valley Re 2      28362          3.2
#> 10                 Academy 20      26607          3.0
print(result)
#>                 district_name n_students pct_of_state
#> 1             Denver County 1      88235         10.0
#> 2        Jefferson County R-1      76172          8.6
#> 3         Douglas County Re 1      61964          7.0
#> 4              Cherry Creek 5      52419          5.9
#> 5          Adams-Arapahoe 28J      39148          4.4
#> 6  Adams 12 Five Star Schools      34998          4.0
#> 7        St Vrain Valley RE1J      32506          3.7
#> 8                  Poudre R-1      29896          3.4
#> 9         Boulder Valley Re 2      28362          3.2
#> 10                 Academy 20      26607          3.0

district_totals |>
  mutate(district_name = forcats::fct_reorder(district_name, n_students)) |>
  ggplot(aes(x = n_students, y = district_name)) +
  geom_col(fill = "#673AB7") +
  geom_text(aes(label = scales::comma(n_students)), hjust = -0.1, size = 3.5) +
  scale_x_continuous(labels = scales::comma, expand = expansion(mult = c(0, 0.15))) +
  labs(
    title = "Colorado's 10 Largest School Districts (2024)",
    subtitle = paste0("These districts serve ", top_10_pct, "% of all students"),
    x = "Total Enrollment",
    y = NULL
  )


Summary

Colorado’s school enrollment data reveals:

  • Shrinking enrollment: 31,584 fewer students since 2020 (-3.5%)
  • Urban decline: Denver, Jeffco, and all but one top-10 district losing students
  • Demographic shift: White share fell to 50.5%, Hispanic grew to 35.5%
  • Charter expansion: 261 charter schools enroll 15.3% of students
  • Economic disparity: 45.2% of students qualify for free/reduced lunch
  • Fragmented system: 115 tiny districts under 1,000 students
  • Concentrated enrollment: Top 10 districts serve 55% of students

Data sourced from the Colorado Department of Education Student October Count.


Session Info

sessionInfo()
#> R version 4.5.0 (2025-04-11)
#> Platform: aarch64-apple-darwin22.6.0
#> Running under: macOS 26.1
#> 
#> Matrix products: default
#> BLAS:   /opt/homebrew/Cellar/openblas/0.3.30/lib/libopenblasp-r0.3.30.dylib 
#> LAPACK: /opt/homebrew/Cellar/r/4.5.0/lib/R/lib/libRlapack.dylib;  LAPACK version 3.12.1
#> 
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#> 
#> time zone: America/New_York
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] ggplot2_4.0.1      tidyr_1.3.2        dplyr_1.2.0        coschooldata_0.1.1
#> [5] rmarkdown_2.30    
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.6       jsonlite_2.0.0     compiler_4.5.0     tidyselect_1.2.1  
#>  [5] jquerylib_0.1.4    systemfonts_1.3.1  scales_1.4.0       textshaping_1.0.4 
#>  [9] yaml_2.3.12        fastmap_1.2.0      R6_2.6.1           labeling_0.4.3    
#> [13] generics_0.1.4     knitr_1.51         forcats_1.0.1      htmlwidgets_1.6.4 
#> [17] tibble_3.3.1       desc_1.4.3         RColorBrewer_1.1-3 bslib_0.9.0       
#> [21] pillar_1.11.1      rlang_1.1.7        utf8_1.2.6         cachem_1.1.0      
#> [25] xfun_0.55          S7_0.2.1           fs_1.6.6           sass_0.4.10       
#> [29] otel_0.2.0         cli_3.6.5          withr_3.0.2        pkgdown_2.2.0     
#> [33] magrittr_2.0.4     digest_0.6.39      grid_4.5.0         lifecycle_1.0.5   
#> [37] vctrs_0.7.1        evaluate_1.0.5     glue_1.8.0         farver_2.1.2      
#> [41] codetools_0.2-20   ragg_1.5.0         purrr_1.2.1        tools_4.5.0       
#> [45] pkgconfig_2.0.3    htmltools_0.5.9