Election Comparison — Methodology

How our election calculations are performed, why each method was chosen, and what the numbers mean. Published in the interest of transparency.

1

Data Source

All election results displayed on this tool are official certified results published by the Montgomery County Board of Elections following each general election. Results are loaded directly from ArcGIS Online (AGOL) hosted feature tables maintained by the Montgomery County GIS & Mapping Services department.

Each year's results are stored in a separate hosted table and updated once after certification. No manual edits or transformations are applied to the vote counts — the numbers displayed are exactly as published.

Available election years

2020, 2021, 2022, 2023, 2024, 2025 General Elections.

Note: This tool compares races that appear in both selected years. Races unique to one year (such as Governor in an off year) do not appear in the comparison dropdown. Race titles are matched after removing wording that changed between years but does not change the office — letter case, punctuation, "Congressional / Legislative / Senatorial" before "District", and "Township", "Borough" or "Area" (except to tell Hatfield Borough from Hatfield Township). For example, "Representative in Congress 4th District" (2020) matches "Representative in Congress (4th Congressional District)" (2022).
2

DEM% and REP% — Two-Party Vote Share

All Democratic and Republican percentage figures on this page use two-party vote share. This is the standard method used in electoral analysis and political science reporting.

Source fields

Two fields from the AGOL hosted results table drive every DEM% and REP% calculation on the page:

FieldDescription
Party_CodeParty affiliation of the candidate row — values include DEM, REP, and others
total_votesTotal votes for that candidate in that precinct (all ballot types combined)
Aggregation

For each selected race, all rows where Party_Code = 'DEM' are summed across every precinct to produce a county-wide DEM total. The same is done for REP. This happens for both the county-level swing card and the municipality table (where the sum is per municipality rather than county-wide).

Formula
DEM total = SUM(total_votes) WHERE Party_Code = 'DEM'
REP total = SUM(total_votes) WHERE Party_Code = 'REP'
Two-party total = DEM total + REP total

DEM% = DEM total ÷ Two-party total × 100
REP% = REP total ÷ Two-party total × 100

DEM% + REP% always equals 100%, making year-over-year comparison direct and consistent.

Rows with no party code

Ballot questions, retention questions and write-ins have a blank Party_Code. These rows are grouped by candidate_name (for example YES and NO) rather than by party. When neither year of a race has any party-coded rows, each answer is compared as a share of all votes in the race:

Answer % = SUM(total_votes for the answer) ÷ SUM(total_votes for all answers) × 100

Write-in rows (Candidate_Type = 'W') are added together as one “Write-ins” choice. Cross-filed candidates (Party_Code = 'DEM/REP') are not counted in either the DEM total or the REP total.

Why total_votes and not a ballot-type specific field?

total_votes is the sum of Election Day votes + Mail-in votes + Provisional votes for that candidate in that precinct. Using it for DEM%/REP% ensures every ballot type is included in the partisan comparison regardless of which vote type filter the user has selected. Vote-type breakdowns in the breakdown chart use the individual fields (Election_Day_votes, Mail_in_votes, Absentee_votes where the year's table includes it, and Provisional_votes) separately.

Why not share of all votes?

If a significant third-party candidate runs in one election year but not another, the DEM and REP percentages would appear to shift even if their actual vote counts were identical. Two-party share removes this distortion by focusing on the head-to-head comparison. This is particularly important when comparing Presidential years (with more minor party activity) to off-year elections.

Where two-party share applies
ChartUses two-party share?Notes
Year card candidate barsNoShows all candidates — uses share of all votes so bars sum to 100%
Swing card DEM%/REP%YesCounty-wide, summed across all precincts
Vote type breakdownYesTwo-party share per vote type using type-specific fields
Municipality table DEM%/REP%YesTwo-party share per municipality
3

Swing

Swing measures how much a party's two-party vote share changed between the two selected election years, expressed in percentage points (pp).

DEM Swing = DEM% (Year B) − DEM% (Year A)
REP Swing = REP% (Year B) − REP% (Year A)

A positive swing means the party gained share in that geography between the two elections. A negative swing means it lost share.

Swing is calculated from the unrounded percentages and rounded to one decimal place only for display. Because DEM% + REP% = 100%, REP Swing always equals −DEM Swing.

When swing is not calculated

Swing is left blank (shown as “—”) when:

• a geography has no DEM or REP votes for the race in one of the two years;
• the race did not have both a DEM and a REP candidate in both years;
• either year had a cross-filed (DEM/REP) candidate, whose votes cannot be assigned to one party;
• the race elects more than one seat (Selectable_Options > 1) and DEM and REP ran different numbers of candidates in either year, because the combined party totals then mostly reflect the number of candidates.

In multi-seat races where both parties ran the same number of candidates, each party's total is the sum of all its candidates' votes.

Color coding

Swing badges use directional colors only — green for positive swing, near-black for negative swing. Party colors (blue/red) are deliberately not used on swing indicators to avoid implying a value judgment about the direction of change.

Municipality table sort

The municipality table shows DEM swing once, in a Shift column labeled with the party the municipality moved toward (D +x or R +x). It sorts by DEM swing descending by default — municipalities at the top shifted most toward Democrats; municipalities at the bottom shifted most toward Republicans.

4

Ballots Cast vs. Votes

Ballots cast is the number of physical ballots submitted in a precinct. Each ballot is counted once, regardless of how many races appear on it.

Votes refers to votes recorded for a specific candidate in a specific race. A single ballot contributes one vote to each race the voter participated in.

Why this distinction matters

Summing candidate votes across all candidates in a race to get a precinct "total" would inflate the count. For example, a race with 4 candidates where 1,000 ballots were cast would produce 4,000 total candidate votes — not 1,000. The Ballots columns in the municipality table read total_ballots directly from the data field, accumulated once per precinct, to correctly represent actual voter participation.

Ballots (municipality) = Sum of total_ballots, once per precinct

The source tables report total_ballots on each race's rows, and it can differ by a few ballots between races in the same precinct. The page uses the value on the selected race's rows.

Split precincts

A split precinct has a row for each split (Split_name). When every split of a precinct carries the same Reg_voters and total_ballots, those values are the precinct total repeated on each split, so they are counted once. When the splits carry different values, each split is its own count and the splits are added together.

5

Turnout

Turnout is calculated as total ballots cast divided by the number of registered voters, expressed as a percentage. Both are summed over the precincts that had the selected race on the ballot.

Turnout % = Total ballots cast ÷ Registered voters × 100

If the result is above 100% (more ballots than registered voters in the source data), turnout is not shown for that year.

Turnout reflects participation in the election as a whole — not in any specific race. It is calculated once per precinct and summed across precincts to produce county or municipality totals.

Note on the Turn_Out field: The Turn_Out field in the source data is stored as a decimal (0.25 = 25%). The page multiplies this value by the registered voter count to recover the actual ballot count where total_ballots is not available. For all post-2020 data, total_ballots is used directly.
Disclaimer
This tool is provided for informational and analytical purposes only. Results are official certified data from the Montgomery County Board of Elections. Montgomery County GIS & Mapping Services makes no representations about the completeness or fitness of this tool for any particular purpose.