knitr::opts_chunk$set( echo = FALSE, message = FALSE, warning = FALSE ) library(glue) library(dplyr) years <- 2017:2020 org_level <- 'schools' nces_num <- "050306000073" state_abb <- 'AR' grades <- 10:12 devtools::load_all()
# This block pulls the academic data and shape files we need to create the panes # with academic data # set parameters and get data ------------------------- ## get initial information so that we can pull the data ----------------- # years data is available # this will be used when we pull the data saipe_years <- sr_years_data_available('saipe') ccd_years <- sr_years_data_available('ccd') # the fips code for the state that the school or district is located in state_fips <- sr_state_fips_code(state_abb) # the school directory contains all the information on the school and pieces # will be used throughout the report school_directory <- sr_ccd_directory(org_level, nces_num, max(ccd_years)) district_leaid_number <- unique(school_directory$leaid) # you should only have one district. Produce error if there are more than one. if (length(district_leaid_number) > 1) stop("All schools must be in the same school district", call. = FALSEs) # for school name, use the school if there is only one, otherwise use the district if (length(nces_num) == 1) { school_names <- stringr::str_to_title(school_directory$school_name) } else { distric_name <- unique(school_directory$lea_name) |> stringr::str_to_title() school_names <- stringr::str_to_title(paste0(distric_name," Schools")) } ## get data ------------------------ # get the school enrollment data school_enrollment <- sr_ccd_enrollment(org_level, nces_num, years, grades) # the number of 5-17 year olds in the district in poverty district_poverty <- sr_district_in_poverty(district_leaid_number, max(saipe_years)) # get state assessment data # grades 9-12 are lumped together as grade 9 for EdFacts state assessment data # therefore, convert any grade greater than 9 to 9 assessment_grades <- unique(ifelse(grades > 9, 9, grades)) # years state_assessment <- sr_state_assessments(org_level, state_fips, years, assessment_grades) |> sr_assessment_scores_by_race(org_level, nces_num) |> mutate(geography = recode(geography, 'state total' = glue("{state_abb} Total"), 'schools / districts' = school_names)) # get district shapefile to map district boundaries district_shapefile <- tigris::school_districts(state = state_abb, cb = FALSE) |> # filter for district filter(GEOID == district_leaid_number) dashboard_title <- stringr::str_c(school_names, " Landscape Analysis")
# value boxes ------------------ # the information in this block is used to create the value boxes at the top of the first page max_edfacts_year <- max(state_assessment$year) edfacts_year <- glue("{max_edfacts_year}-{max_edfacts_year}") max_ccd_year <- max(school_directory$year) ccd_year <- glue("{max_ccd_year}-{max_ccd_year}") lowest_grade <- min(grades) highest_grade <- max(grades) prettify_grade <- function(grade) { grade <- as.character(grade) case_when( grade == '-1' ~ 'Pre-K', grade == '0' ~ 'K', .default = grade ) } grade_span <- glue("{prettify_grade(lowest_grade)}-{prettify_grade(highest_grade)}")
r school_names
r glue("{ccd_year}<br>Grades {grade_span}")
# value box for school enrollment latest_year_enrollment <- school_enrollment |> filter(race == 'Total', year == max(years)) |> pull(enrollment) |> as.numeric() |> scales::comma() flexdashboard::valueBox(latest_year_enrollment, icon = "fa-child")
r school_names
r glue("{ccd_year}<br>Grades {grade_span}")
# value box for number of FTE teachers teachers_elementary <- sum(school_directory$teachers_fte) |> as.numeric() |> scales::comma() flexdashboard::valueBox(teachers_elementary, icon = "fa-chalkboard-teacher")
r max(saipe_years)
# value box for percentage of students in poverty percent_students_poverty <- district_poverty$est_population_5_17_pct[1] |> scales::percent() flexdashboard::valueBox(percent_students_poverty, icon = "fa-bed")
r glue("{edfacts_year}<br>Grades {grade_span}")
# value box for math state assessments # get most recent year for the district of state assessments school_assessment_recent_year <- state_assessment |> filter(year == !!max_edfacts_year, !stringr::str_detect(geography, 'Total'), race == 'Total') math_assess <- school_assessment_recent_year |> pull(math_pct_pass) math_assess <- scales::percent(math_assess / 100, accuracy = 1) flexdashboard::valueBox(math_assess, icon = "fa-calculator")
r glue("{edfacts_year}<br>Grades {grade_span}")
# value box for reading state assessments read_assess <- school_assessment_recent_year |> pull(read_pct_pass) read_assess <- scales::percent(read_assess / 100, accuracy = 1) flexdashboard::valueBox(read_assess, icon = "fa-book")
# district map and table of cities -------------------- # must create the map in a different code chunk than the chunk it is printed in # this is because sf prints a statement in one of the commands and the only # way to suppress the statement is the include the header include = FALSE # but, this header prevents the map from showing as well district_map <- sr_viz_district_boundary(district_shapefile, school_directory)
district_map
pop_colname <- glue("**City Pop.<br>{max(years)-1}**") cities_table <- sr_cities_in_district(district_shapefile, state = state_abb) |> # convert the data frame to a gt table and make nicer mutate(population = scales::comma(population)) |> gt::gt() |> gt::cols_label( city = gt::md("**City Name**"), population = gt::md("**Population**") )
cities_table
# plot enrollment ------------------- total_enrollment <- school_enrollment |> filter(race == 'Total') sr_plot_total_enrollment_by_year(total_enrollment, school_names, grade_span)
race_y_var_title <- glue("Percentage Enrollment by Race (grades {grade_span})") school_enrollment |> sr_clean_enrollment_by_race() |> sr_plot_grouped_line( x_col = 'school_year_both', y_col = 'percent_race', group_col = 'race', plt_title = NULL, x_var_title = NULL, y_var_title = race_y_var_title, y_percentage = TRUE ) |> sr_plot_create_tooltip('race', 'percent_race_clean', 'enrollment')
# state assessments ---------------- state_assessment <- state_assessment |> # make sure the different district names are all the same mutate( # percentages for plotting read_pct_pass_clean = scales::percent(read_pct_pass / 100, accuracy = 1), math_pct_pass_clean = scales::percent(math_pct_pass / 100, accuracy = 1) ) all_years_total <- state_assessment |> filter(race == 'Total') # create plots for math and reading subjects <- c('math', 'read') plt_titles <- c('Percent passing math state assessments', 'Percent passing reading state assessments') all_year_plts <- purrr::map2(subjects, plt_titles, function(.x, plt_title) { all_years_total |> sr_plot_grouped_line( 'school_year_both', glue('{.x}_pct_pass'), 'geography', glue("{plt_title} in grades {grade_span}"), NULL, 'Percent passing state assessment', y_percentage = TRUE ) |> sr_plot_create_tooltip('geography', glue('{.x}_pct_pass_clean'), glue('{.x}_test_num_valid')) })
all_year_plts[[2]]
all_year_plts[[1]]
Row {data-height=400}
# get school assessment by race data assessment_race <- state_assessment |> filter(!stringr::str_detect(geography, 'Total'), race != 'Total') # line plots of district assessments by race and year all_years_race_district <- purrr::map2(subjects, plt_titles, function(.x, plt_title) { assessment_race |> sr_plot_grouped_line( 'school_year_both', glue('{.x}_pct_pass'), 'race', NULL, NULL, glue("{plt_title} in grades {grade_span}"), y_percentage = TRUE ) |> sr_plot_create_tooltip('race', glue('{.x}_pct_pass_clean'), glue('{.x}_test_num_valid')) }) # bar chart comparing most recent year with state averages all_years_race <- state_assessment |> filter(race != 'Total') |> arrange(race) all_years_race_total <- purrr::map2(subjects, plt_titles, function(.x, plt_title) { sr_plot_grouped_bar(all_years_race, 'race', glue('{.x}_pct_pass'), 'geography', glue("{plt_title} in grades {grade_span}")) })
all_years_race_district[[2]]
all_years_race_total[[2]]
Row {data-height=400}
all_years_race_district[[1]]
all_years_race_total[[1]]
# get most recent year of census data census_most_recent <- max(sr_years_data_available('census'))
Note:
Community data is from the US Census's American Community Survey. The data is from the most recent year available, which is r census_most_recent
. The data is an aggregate of all census tracts where any portion of the tract is located within the school district.
# Community demographics ------------------ # find the census tracts in the school district tracts_in_district <- sr_census_tracts_in_district(district_shapefile, state_abb) geoid_tracts_in_district <- tracts_in_district$GEOID
race_population_variables <- c( 'B03002_001','B03002_004', 'B03002_012','B03002_003','B03002_005','B03002_006','B03002_007','B03002_010','B03002_011' ) census_demographics <- sr_demographic_data(race_population_variables, state_abb, geoid_tracts_in_district) |> dplyr::mutate(variable = case_match( variable, 'B03002_001' ~ 'Total', 'B03002_004' ~ 'Black / African-American', 'B03002_012' ~ 'Hispanic / Latinx', 'B03002_003' ~ 'White', 'B03002_005' ~ 'American Indian or Alaska Native', 'B03002_006' ~ 'Asian', 'B03002_007' ~ 'Native Hawaiian or other Pacific Islander', 'B03002_010' ~ 'Some Other', 'B03002_011' ~ 'Two or more races' )) # everything should have matched if (any(is.na(census_demographics$variable))) stop("Failed to properly match racial categories to census pop data", call. = FALSE) census_demographics_total <- census_demographics|> sr_calculate_percentages() |> filter(.data$variable != 'Total') |> mutate(variable = sr_rename_reorder_race_education(variable)) |> arrange(variable) # overall racial composition sr_plot_grouped_bar( census_demographics_total, 'variable', 'perc_demo', 'geography', x_var_title = NULL, y_var_title = 'Percentage breakdown by race', y_percentage = TRUE )
# create choropleth maps by census tract showing population and percentage # population by race for each census tract # create different map for each racial group # calculate percentage pop in each race races_to_use <- c('Black / African-American', 'Hispanic / Latinx', 'White') # make sure total population value is present, because future operations rely on it if (!"Total" %in% census_demographics$variable) stop("Population census tract data does not contain total populations.", call. = FALSE) # clean up data so we can easily plot it in a choropleth map in highcharts all_race_population <- sr_rmd_census_tracts_race(census_demographics, races_to_use) # create choropleth maps by census tract for each race choropleths_tracts_by_race <- purrr::map(races_to_use, function(race) { sr_rmd_plot_choropleth_tracts_race( .data = all_race_population, race = race, tract_shapefile = tracts_in_district, school_location = school_directory ) }) |> purrr::set_names(races_to_use)
choropleths_tracts_by_race[[1]]
choropleths_tracts_by_race[[2]]
choropleths_tracts_by_race[[3]]
# need lsit of census variables for median income and education; pull it out so # it can be used in both #var_year <- max(sr_years_data_available('census')) #acs_vars <- tidycensus::load_variables(var_year, "acs5", cache = TRUE) census_education <- sr_rmd_get_educational_attainment(state_abb, geoid_tracts_in_district) ed_order <- unique(census_education$variable) census_education <- census_education |> mutate(variable = factor(variable, levels = ed_order)) |> arrange(variable) sr_plot_grouped_bar( census_education, 'variable', 'perc_demo', 'geography', x_var_title = NULL, y_var_title = 'Educational attainment of community', y_percentage = TRUE )
census_education <- sr_rmd_get_educational_attainment(state_abb, geoid_tracts_in_district, acs_vars) ed_order <- unique(census_education$variable) census_education <- census_education |> mutate(variable = factor(variable, levels = ed_order)) |> arrange(variable) sr_plot_grouped_bar( census_education, 'variable', 'perc_demo', 'geography', x_var_title = NULL, y_var_title = 'Educational attainment of community', y_percentage = TRUE )
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.