Skip to content

Add 120th Congress district maps and tables - #41

Open
DTrim99 wants to merge 4 commits into
PolicyEngine:mainfrom
DTrim99:cd120-districts
Open

DTrim99 wants to merge 4 commits into
PolicyEngine:mainfrom
DTrim99:cd120-districts

Conversation

@DTrim99

@DTrim99 DTrim99 commented Nov 5, 2026 •

Copy link
Copy Markdown

Adds 120th Congress district maps beside the 119th ones. The 120th Congress is seated on January 3, 2027. Part of PolicyEngine/microcosm#1526, which tracks moving PolicyEngine's district data and maps to the 120th Congress.

What changes

  • The two loaders take an optional Congress, 119 by default:
    • loadCongressionalDistrictsGeo(congress?: CongressNumber)
    • loadCongressionalDistrictsHex(congress?: CongressNumber)
  • The map component. USDistrictChoroplethMap takes congress (119 by default) and loads the matching map.
  • New exported types: CongressNumber = 119 | 120, plus CongressionalDistrictMember and CongressionalDistrictMembers.
  • Members-elect. loadCongressionalDistrictMembers120() loads each district's member-elect and party letter, or "not yet called". The file is a snapshot of race calls, read from Wikipedia's 2026 House elections page, with its read time and page revision recorded. The first snapshot (November 5) has 406 races called (253 D, 153 R) and 30 not yet called, within a few seats of the news totals that morning (252 D, 158 R, 25 uncalled). fetch_members.py refreshes it.
  • New data files in src/visualization/data/, loaded only when asked for:
    • congressionalDistrictsGeo120.json: 851 KB, 437 features;
    • congressionalDistrictsHex120.json: 489 KB, 436 features;
    • congressionalDistrictMembers120.json: 436 districts.
  • Existing callers see no change. They still get the 119th files.

District IDs (ST-NN) follow each state's new numbering: in the 120th files, TX-35 is the area Texas's new map numbers 35. The list of IDs is the same in both Congresses, because seat counts come from the 2020 apportionment.

In the nine redrawn states, an ID now names a different area. For example, 40% of the new TX-35's 2020 population was in the old TX-28, and only 10% was in the old TX-35. So callers should draw each result on the boundaries it was computed with. The congress prop says which.

The 120th data

Nine states redrew for the 2026 elections: AL, CA, FL, LA, NC, OH, TN, TX and UT, 173 seats in all.

  • Block files. I compared Census's 120th and 119th block equivalency files block by block: 8,174,955 blocks with the same IDs in both.
    • Those nine states are the only ones where any block changed district.
    • Missouri keeps its 2022 map: Census regenerated the file on October 7, and the November referendum on the 2025 map failed.
    • Virginia's new map was struck down.
  • Boundaries.
    • The nine states come from TIGER/Line 2026, clipped to the shoreline.
    • Every other state, DC and Puerto Rico keep their 1:500k 119th boundaries.
    • The layer is simplified as one topology, so borders with unchanged neighbors stay aligned.
  • Hexes. The Downballot's hexmap v3.2 (2026) moves CA, FL, NC, OH, TN, TX and UT. The 119th hexes stay for every other state. The Downballot didn't move Alabama, Louisiana or Missouri. The hexmap is CC BY 4.0, so callers should credit "The Downballot" where it's shown.

data-sources/congressional-districts/ holds the build. It isn't in the package's files, so it isn't published:

  • sources.json, with all 66 inputs and their SHA-256s;
  • the download and build scripts;
  • a README covering method and checks;
  • tables built from 2020 block populations:
    • district keys in every format we use (ST-NN, Census GEOID, and policyengine-us's congressional_district_geoid), with labels;
    • district populations;
    • county → district and tract → district shares;
    • 119th → 120th overlaps;
    • a per-state change summary.

Checks

  • Population. The 2020 block populations sum to 331,449,281 people in 5,769,942 populated blocks, which matches the national total.

    • All 436 districts are present.
    • Every district's population is close to its state's ideal. The exceptions are states that count incarcerated people at their home address when they draw districts. California's largest is +2.34%, against +2.88% for the 119th map.
  • Boundaries against Census's block assignments. Take every tract wholly inside one district. Its internal point should fall in that district's shape.

    Points that land in another district
    120th file, redrawn states 1.02%
    120th file, other states 0.94%
    This package's current 119th file, same test (redrawn / other states) 2.51% / 1.97%

    Per state, the 120th file does as well as or better than the 119th baseline. Alabama is 2 of 1,382 tracts, so TIGER/Line carries its June 2026 map.

  • Data tests (tests/visualization/congressionalDistrictData.test.ts):

    • the 120th files have the same district IDs as the 119th files;
    • every boundary carries CONGRESS 120 and a 5002000US GEOID;
    • at-large districts and DC are -01;
    • hexes outside the seven moved states are unchanged;
    • the key table lists the map's districts;
    • the members file has an entry for every district, with a name and party for each called race.
  • Loader tests. The component asks for 119 by default and 120 when congress={120} is set, for both views.

  • Local runs.

    • bun run typecheck and bun run build pass.
    • All 64 visualization tests pass.
    • The full suite's only failures are two generated-css tests. They fail on this Windows checkout because of CRLF line endings in src/theme/quarto.scss, which this PR doesn't touch.

Not in this PR

  • Refreshing the members file. Rerun fetch_members.py before release, until every race is called and certified. After January 3, switch to unitedstates/congress-legislators.
  • Census's own 120th cartographic boundary file, when it's published.
  • Switching app-v2 to congress={120}, which happens when its data moves to the 120th. Existing dashboards keep the 119th default unless their owner changes them, and new projects pass congress={120}.

🤖 Generated with Claude Code

The 120th Congress, seated January 3, 2027, has new districts in AL, CA,
FL, LA, NC, OH, TN, TX and UT. The map loaders and USDistrictChoroplethMap
take an optional Congress (119 by default), and the package ships 120th
boundaries and hexes beside the 119th ones, with the same district IDs.

The boundaries redraw the nine states from Census's 2026 TIGER/Line files
and keep every other state's 119th boundaries, which Census's block
equivalency files show are unchanged (Missouri keeps its 2022 map). The
hexes use The Downballot's hexmap v3.2 (CC BY 4.0).

data-sources/congressional-districts (not packaged) records every source
with its SHA-256, the build scripts, a boundary check against Census's
block assignments, and county, tract and 119th-to-120th tables.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 5, 2026

Copy link
Copy Markdown

@DTrim99 is attempting to deploy a commit to the PolicyEngine Team on Vercel.

A member of the Team first needs to authorize it.

DTrim99 and others added 3 commits November 5, 2026 16:13
congressionalDistrictMembers120.json lists each district's member-elect
(name and party letter) or "not yet called", read from Wikipedia's 2026
House elections page with the revision and time recorded.
loadCongressionalDistrictMembers120() loads it. The first snapshot has 406
races called and 30 not yet called; fetch_members.py refreshes it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@DTrim99

DTrim99 commented Nov 6, 2026

Copy link
Copy Markdown
Author

@PavelMakarchuk could you review this? It adds the 120th Congress district maps and members-elect beside the 119th ones, chosen with a congress option that defaults to 119. (I can't request reviewers on this repo, since I only have read access.)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant