Georgia Runoff Election

Georgia Runoff Election

This is a blog post I wrote for my internship that can be read here.

On June 16, Georgia held closely watched runoff elections in Republican primaries for governor and U.S. Senate, as well as lieutenant governor, secretary of state, and the 11th Congressional District. There were also runoffs in Democratic primaries for lieutenant governor, secretary of state, and three congressional districts.

Past statewide runoffs have cost Georgia taxpayers as much as $75 million. Turnout in this year’s runoffs fell by 24% statewide – with several races falling by more than 60%. These high costs and low turnout are predictable problems that could have been prevented if Georgia used ranked choice voting (RCV).

Turnout in Key Georgia runoff elections

Primary Initial election turnout Runoff election turnout Turnout change
Governor (GOP) 933,817 709,253 -24.1%
U.S. Senate (GOP) 912,696 702,209 -23.1%
Lieutenant governor (GOP) 889,130 691,624 -22.2%
Lieutenant governor (Dem) 1,030,951 383,845 -62.8%
Secretary of state (GOP) 851,794 667,090 -21.7%
Secretary of state (Dem) 1,028,197 383,830 -62.7%
1st Congressional District (Dem) 57,159 23,813 -58.3%
7th Congressional District (Dem) 49,421 17,221 -65.2%
11th Congressional District (GOP) 80,165 68,915 -14.0%
12th Congressional District (Dem) 61,284 30,139 -50.8%

Georgia held its initial primary elections on May 19. In 27 races where no candidate secured a majority of the vote, Georgia held runoffs between the top two finishers four weeks later.

Runoff elections are supposed to make government more representative by electing candidates with majority support. But in practice, runoffs usually shrink the electorate and come with a significant price tag for taxpayers and campaigns.

In the state’s Democratic primary runoffs, turnout fell so much that several candidates won their runoffs with fewer votes than they received in the May primary – entirely defeating the purpose of the runoff.

Votes for runoff winners

Primary Votes for winner in May primary Votes for winner in June runoff Change
Lieutenant governor (Dem) 426,854 210,660 -50.6%
Secretary of state (Dem) 435,358 242,205 -44.4%
1st Congressional District (Dem) 14,095 12,608 -10.5%
7th Congressional District (Dem) 19,742 11,664 -40.9%
12th Congressional District (Dem) 20,112 16,815 -16.4%

Ranked choice voting offers a better, faster, cheaper alternative. RCV allows voters to rank candidates in order of preference, with an “instant runoff” determining a majority winner when necessary. This means winners are determined on Election Day, when participation is highest and voters still have access to the full range of choices. With RCV, voters wouldn’t need to cast a second ballot for the same offices, and taxpayers wouldn’t have to cover the cost of a second election.

To support RCV in Georgia, visit Better Ballot Georgia today!

Every Opening

Every Opening

Every Opening is a project I made as a final exam for my Artv 10300 class in Spring Quarter 2026 with Professor Jason Salavon. The project features a live rendering of the top 500 most frequent chess openings played by real humans.

Data was obtained from Lichess and used the April 2026 dataset of 90,000,000 games. I built a program to analyze these games into a json file that could then be read by the output file to generate the live graphics of all 500 games.

During this project, I noticed interesting things about the dataset, such as there were at least three one move games. They were 1. e4, 1. d4, and 1. Nf3. At first, I thought something had gone wrong, as in the output file, those games showed a 99%+ win rate for white, wheras all other openings had a roughly 50/50 split. However, I realized those were games that had been started, and then immediately quit by one of the players (99% of the time being the black player).

You can view the innerworkings of the project on my GitHub in the chessdata folder. The project could be remade with a larger dataset if you have the computing power or with a more updated dataset if you like using the parse_lichess_openings.py file. You can see the final product yourself by downloading and running the chess-openings500.html file.