The goal for this project is to format county-level data on school vaccinations obtained from the states.
Publish the granularity the state publishes. If a source is by school or by
district, keep those rows and add school_name (with district/city where the
source has them) rather than aggregating in the ingest — the combined file rolls
them up to county itself, and it can only do that correctly if it can see the
denominator on each row. Aggregating early is how WI came to report a 95%
county religious-waiver rate: it averaged school percentages with no enrolment
to weight them, so one small school set the county figure.
The output is wide: index columns (geography, time, and any stratum the
source publishes, such as grade) plus one column per measure. The vaccine or
exemption category goes in the COLUMN NAME — rate_mmr, rate_medical_exempt,
N_full_exempt — not in a vax value column. Categories in use:
dtap · polio · mmr · hep_b · varicella
personal_exempt · medical_exempt · religious_exempt · full_exempt
Not every state's data comes from an automated pull. data/DATA_SOURCES.md
tracks, for every state, the public source, how it's accessed (API, static
download, dashboard-only, or by-request), what the ingest produces, and the
public sources that are known but not ingested yet. Check it before
starting work on a state. Each state folder also carries a machine-readable
sources.json with the URL, discovery pattern and publishing calendar of
every source. A few things worth knowing up front:
- DC, GA and NE have no data: DC Health blocks non-residential clients and the other two have no public file; all three are stubs.
- DE and WY are statewide or registry-based: Delaware publishes only statewide charts, and Wyoming's county report cards come from the immunization registry rather than a school survey.
- AK, WY, ID, SD and WV raw files were supplied to the project, not
downloaded by
ingest.R; there is no automated source behind them. - PDF sources are parsed with
resources/pdf_table.R(IA, TN, AL, SC, DE); states whose PDFs are charts without value labels (MS) or whose pages carry no file (KY, KS, NJ, UT, VA) stay exemption-only. - AR only has school-district-level data — Arkansas publishes no
county file, so its
standard/data.csv.gzhas district rows only, not county rows. - MA cannot be fetched from CI (the mass.gov WAF rejects datacenter IPs); new years are fetched from a workstation and committed.
Network ingests download through resources/fetch.R: the file goes to a
temporary path, is validated (workbook signature, CSV header, PDF magic,
bot-block page detection), and only then replaces the committed copy. A
failed download keeps the committed file, warns, and records the failure
in process.json. Parsing only runs when a raw file or the script changed.
Two reports are regenerated by CI:
data/BUILD_STATUS.md, written byscripts/build_status.Rat the end of the nightly build; the job fails if an ingest errored or a fetch failed with nothing to fall back on.data/SOURCE_STATUS.md, written byscripts/check_sources.Rweekly (.github/workflows/check_sources.yaml): checks every declared URL, lists files posted upstream that are not inraw/, and flags states whose latest ingested year is behind the publishing calendar. Run it locally withRscript scripts/check_sources.R --states=MN,TX.
This is set up as a Data Collection Framework project, initialized with dcf::dcf_init.
You can use the dcf package to check the source projects:
dcf::dcf_check()And process them:
dcf::dcf_process()