No description
  • JavaScript 91.3%
  • Python 6.9%
  • HTML 1.3%
  • CSS 0.5%
Find a file
Derek Hammer af459f9b2a
All checks were successful
Deploy to Pages / deploy (push) Successful in 55s
Reclassify D8 as Open seat
2026-09-17 10:01:17 -06:00
.forgejo/workflows Extract inline CSS/JS into style.css and app.js 2026-07-17 09:06:56 -06:00
data Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
img Add Denver mayor race breakdown: win number, ground game, candidate headshots 2026-08-21 09:42:33 -06:00
scripts Enhance three-model-comparison with voter-file age/gender EI estimates 2026-07-27 17:14:12 -06:00
app.js Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
demographic-correlations.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
demographic-estimated-counts.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
demographic-segmentation.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
demographic-vote-weighted.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
denver-districts.geojson Fix tract-to-district mapping using real Denver council district boundaries (spatial join) 2026-06-27 21:42:38 -06:00
denver-precincts-2023.geojson Add 2026 CO-1 primary precinct results with real boundaries 2026-07-04 14:51:32 -06:00
denver-tracts-compact.geojson Externalize district data to district-data.json for easy updates 2026-06-21 02:43:17 -06:00
denver-tracts.geojson Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
district-data.js Reclassify D8 as Open seat 2026-09-17 10:01:17 -06:00
district-data.json Reclassify D8 as Open seat 2026-09-17 10:01:17 -06:00
districts.js Add council district boundary overlay with distinct colors 2026-06-27 21:49:01 -06:00
ecological-inference-results.csv Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
favicon.svg Add favicon and outsider-analysis framing to Mayor tab 2026-08-21 09:51:45 -06:00
goodman-regression.csv Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
index.html Add favicon and outsider-analysis framing to Mayor tab 2026-08-21 09:51:45 -06:00
neighborhood-census-rollup.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
neighborhood-data.js Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
neighborhood-rollup-2026.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
neighborhood-turnout-comparison.csv Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
neighborhood-vote-decomposition.csv Add centered neighborhood vote decomposition model (R²=0.877) 2026-07-27 17:22:49 -06:00
neighborhoods.js Add neighborhood census rollup, demographic analysis, and interactive neighborhood map layer 2026-07-27 16:22:24 -06:00
pika.png Footer: Pika logo, resource links, remove formulaic caveats 2026-06-21 04:02:57 -06:00
precinct-bisg-race.csv Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
precinct-results.json Switch to actual 2026 primary precinct vote totals 2026-07-20 14:39:47 -06:00
precinct-turnout-by-race.csv Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
precinct-voter-demos.csv Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00
precincts-geo.js Switch to actual 2026 primary precinct vote totals 2026-07-20 14:39:47 -06:00
README.md Extract inline CSS/JS into style.css and app.js 2026-07-17 09:06:56 -06:00
style.css Add Denver mayor race breakdown: win number, ground game, candidate headshots 2026-08-21 09:42:33 -06:00
three-model-comparison.csv Enhance three-model-comparison with voter-file age/gender EI estimates 2026-07-27 17:14:12 -06:00
tracts.js Add BISG race estimation, voter-file age data, turnout-by-race, and updated ecological models 2026-07-27 17:12:53 -06:00

Denver 2027 Election Cycle Visualizer

Interactive map and dashboard for the Denver DSA Electoral Working Group. Tracks all 13 City Council seats on the April 2027 ballot plus the November 2026 At-Large special election (Parady vacancy).

Quick start

Open index.html in a browser (no build step, no server needed — it's a static page that loads data from local JSON files). To mirror the actual deployment (static files served from the repo root) instead:

uv run scripts/serve.py   # http://localhost:8080/

Tabs

  • Dashboard — voter landscape, priority targets (top 6 by score), district summary table
  • Map — 178 census tracts on OpenStreetMap with 15 toggleable data overlays
  • Special Election — Parady vacancy timeline, FEF rules, 2023 at-large results, candidate tracker

Updating data

Campaign numbers (DDSA members, Melat voter %, Melat doors canvassed)

Edit district-data.json. Fields you'll most likely change:

"D6": {
  "members": 120,       // DDSA members in this district (est.)
  "melatPct": 34,       // Melat Kiros voter % in this district (est.)
  "melatDoors": 4500,   // doors canvassed for Melat in this district (est.)
  "rating": "Open",     // Safe | Vulnerable | Open
  "open": "YES"         // YES | No | Maybe
}

Save the file, run uv run scripts/sync-district-data.py (the page actually loads district-data.js, a generated wrapper, so it works over file://), and refresh. Scores, priority ordering, table data, and map overlays all update automatically. No code changes needed.

Incumbency / candidate changes

Edit the same district-data.json. Update "incumbent", "rating", "open", and "notes" as the field develops.

Census data (renter %, demographics, median income)

Census data is per-tract and embedded in tracts.js. This is essentially static (ACS 2023 5-year). If you need to rebuild it from a new census spreadsheet:

uv run scripts/build-tracts.py

Voter registration / turnout

Currently at the district level in district-data.json ("voters", "turnout", "johnston"). For precinct-level updates, source files live in ~/Downloads/Data/Voter-Registration/.

Data pipeline

All generated data files are rebuilt by scripts in scripts/ (self-contained uv scripts; run with uv run scripts/<name>.py). Each script documents its sources in its docstring. Network fetches are cached: downloaded GeoJSON is reused unless you pass --fetch.

In dependency order:

Script Inputs Outputs
build-districts.py Denver ODC ArcGIS (2023 council districts) denver-districts.geojson, districts.js
build-tracts.py TIGERweb tracts, denver-districts.geojson, census xlsx denver-tracts.geojson, tracts.js
build-precinct-results.py Map.xlsx (2023 mayor), Map_ENR_2026_PE.csv_data.csv (2026 CO-1) precinct-results.json
build-precincts-geo.py Denver ODC ArcGIS (2023 precincts), precinct-results.json, precinct-now.json (2026 turnout) denver-precincts-2023.geojson, precincts-geo.js
calibrate-melat-pct.py precincts-geo.js, official CO-1 totals district-data.json melatPct/melatCI, district-data.js
sync-district-data.py district-data.json district-data.js
process-precinct-data.py 2020/2022/2024 primary xlsx exports historical merge (exploratory; output not shipped)

Scoring formula

The Target Score (1–10) weights each district by strategic priority:

Factor Weight Rationale
Incumbency (Open=10, Vuln=6, Safe=2) 30% Open seats are the biggest opportunity
Renter % 20% Renters skew progressive, more reachable
DDSA Members 20% Organizing capacity on the ground
Melat Voter % 15% Proxy for left-receptive electorate
Johnston % (inverted) 15% Lower establishment pull = better opening

Each factor is normalized 0–10, then combined with the weights above.

Source data

Raw source data is archived in the shared Google Drive folder: https://drive.google.com/drive/folders/1GC3COAuWL5P7eSEC_dlOjwUrpzFt87Uj

The pipeline scripts read from a local download of that folder (defaults point at ~/Downloads/; override with each script's CLI flags):

  • Census/ — census-tracts-Denver.xlsx (ACS 2023 5-year demographics)
  • Voter-Registration/ — sos-precinct-counts.xlsx, AprilStatistics2026.xlsx
  • Election-Results/ — denver-2023-results.pdf, Map.xlsx (precinct-level mayoral leaders)
  • Map_ENR_2026_PE.csv_data.csv (2026 CO-1 primary ENR export)
  • precinct-now.json (2026 primary turnout, Power BI capture)
  • ballot-returns-*.xlsx / votes-*.xlsx (2020/2022/2024 primaries)

Files

File Purpose
index.html Application markup (DSA-branded, tabbed dashboard)
style.css Application styles
app.js Application logic (scoring, Leaflet map, overlays, tabs)
district-data.json Edit this — district-level campaign data (then run sync-district-data.py)
district-data.js Generated from district-data.json; loaded by the page
tracts.js Tract GeoJSON + census demographics (178 Denver tracts)
districts.js Council district boundary overlay
precincts-geo.js Precinct polygons + 2026 CO-1 results + 2026 turnout
precinct-results.json Per-precinct 2026 CO-1 + 2023 mayor leaders
denver-*.geojson Cached source geometry (see Data pipeline)
scripts/ Rebuild pipeline (uv scripts)

Design

Denver DSA brand: Manifold DSA font, #EC1F27 (red) / #231F20 (black) palette. Reference: ~/dev/ddsa/proposal1/ (Proposal 1: Bold Typography).