Here’s what I want on election night: A complete list of all Harris’s paths to victory and a complete list of all Trump’s paths. Then as each path becomes impossible, I can cross it off and see possibilities narrowing down.
Of course the meaning of “all Harris’s paths to victory” depends on your background assumptions. For starters, I assumed that the seven oft-cited “battleground states” (PA, GA, NC, MI, WI, AZ, NV) are up for grabs and that all other states (and districts) will fall as expected, where “as expected” means “to the candidate who is currently ahead in the RealClearPolitics polling average”. This leaves 20 paths to victory for Harris and 21 for Trump, as shown:
Here’s exactly what this means: If Harris wins any one of her 20 combinations, she wins the race. If she fails to win any of them, she loses.
So for example, if Trump wins Pennsylvania early, I can cross off Harris’s top 10 rows, leaving her 10 paths to victory. If she loses Georgia, I cross off another 7 and she’s down to 3 paths.
Incidentally, there are also three paths to a tie, as indicated here:
Of course you might not believe that only seven states are up for grabs. So for my second pass, I assumed that seventeen “states” are up for grabs. These are the states that appear, from the RealClearPolitics averages, to be at least barely contestable. They are TX, FL, PA, OH, GA, NC, MI, VA, AZ, WI, MN, NV, NM, NH, ME, NB-2, and ME-2. (The latter two are actually congressional districts, not states.)
Now (unless I’ve made a mistake somewhere) Harris has 1922 paths to victory. Rather than post a 1922 line chart, here is a link to a 37-page pdf document. I plan to have this in front of me on election night.
We used to have an system where votes were cast and counted on Election Day, with observers. As it is, it is unlikely that we will have a winner on election night, and unlikely that everyone will accept the outcome as fair.
As this struck me as an interesting tool to have I decided to try and write a python program that would allow one to tweak the assumptions and easily generate the paths.
I started out by trying to reproduce your results. This was easy for the 7-state example where I got the same list but I am getting 2392 paths for the the 17-state example. Before starting to compare the differences between your list of paths and mine I wanted to check your assumptions around the 2 congressional districts you include.
I assume these are Nebraska (NE not NB) and Maine. Nebraska has 5 votes in the EC and Maine 4. Are you assuming that Trump will get 4 of the 5 votes for Nebraska and Harris 3 of the 4 votes for Maine and in each case there is a single vote that could go either way?
Update from @2
I now see that you assume both Maine-at-large and the congressional district are marginal seats and have changed my code accordingly.
I still have more paths (2059) for Harris than you. I think this may partially because my program calculates that Harris wins if she captures a minimum of 80 EC seats while your spreadsheet shows a combination of states (such as TX,FL,NM,NH) where she wins by winning only 79 seats.
Can you let me know how many seats you calculated (and used in your spreadsheet) that Harris needs to win as this will help with my debugging and enable me to compare my results with your more accurately.
Rob Rawlings (#2 and #3): I assumed that all of Nebraska except the one district goes for Trump. For Maine, I assumed that the statewide 2 votes are in play (hence the column for ME) and that one of the two congressional districts is in play (hence the column for ME-2), but not the other.
Again, this came from looking at RealClearPolitics polling averages and keeping only the 17 states/districts where the gap did not seem overwhelming.
You are of course right about Nebraska.
In case it helps your verifications, here are all the electoral votes I assumed were in play:
TX 40
FL 30
PA 19
OH 17
GA 16
NC 16
MI 15
VA 13
AZ 11
WI 10
MN 10
NV 6
NM 5
NH 4
ME 2
NEB2 1
ME2 1
If you continue to get a different number than I got, I’m happy to collaborate on figuring out where one of us went wrong — or to hear what you figure out if you settle it on your own.
Rob Rawlings again: Oh! I somehow overlooked your question about 79 versus 80. Yes, I believe that with my assumptions she needs 79, and that’s what I used.
Rob Rawlings (yet again!): If you look at the RCP electoral map, it currently gives Harris 215. I took away Maine, New Hampshire, New Mexico and Virginia (which they have as “Leans Harris”), leaving her with 215-24 = 191. To get from 191 to 270, she should need 79.
Thanks.
I had been treating Maine as having 3 state-wide votes (in-play) and 1 congressional votes (also in play). I have now adjusted to 2 state-wide votes (in-play) , 1 congressional vote (in play) and 1 congressional vote (for Harris.
If I also assume Harris needs 79 to win then I now also get 1922 paths!
I can’t work out why 79 rather than 80 is required to win – but will take a look at that later.
Rob: In case it helps you, I get 1646 paths for Trump under the same assumptions that led to 1922 for Harris.
I just ran for Trump and I also get 1646 (He would need to win 139 votes in those in-play states).
Also, I corrected the issue calculating the required votes needed by Harris and it is now 79 the same as you state.
Given that we have got the same results from totally independent methods I think we can have a high degree of confidence that the results are correct.
Rob Rawlings:
Excellent. Thanks for sharing this.
I have code now where you can enter the number of votes you think Harris (or Trump) has locked up, and the names of the states you think are in play. But it’s all done from the command line, whereas it would probably be nicer to be able to drag states from one column to another. I’ll be on an airplane tomorrow and traveling without my computer for a few days thereafter, so I’m not sure when or if I’ll get to this. But if you want to beat me to it, I’ll be delighted. (And if you don’t beat me to it, I’ll be delighted for the alternate reason of learning that you have other (presumably good) things to distract you!).
My version is based on a list I constructed for each state (or congressional district) containing:
state_name
state_abbrev
#_of_votes
who_is_winning
margin
(for example: ‘New Hampshire’, ‘NH’, 4, ‘Harris’,4).
On the command line I just enter either Trump/Harris and the margin used to determine if the state is in-play or not:
python3 election_paths.py Trump 8
will generate Trump’s paths for the 17 states used in your second pass that all have margins of 8% or less in my list. Downside is that if the margins change and the list if in-play states change I will have to redo the list.
I think it would be pretty easy to build a front end where the in-play states are selectable, and the margin can be chosen by a slide bar. I may even try that tomorrow!
Is your program also python?
My code is written in Mathematica. I can also write php but have never learned python (though it’s pretty clear to me that my life is poorer for that).
Just to prove how exciting my life is I added the GUI (with quite a bit of help from chatGPT)
Its here for anyone that wants to try it: https://drive.google.com/drive/u/0/folders/1cHmC_Taymt1EWKLreQPLam1EHDU-peJQ
I think it only uses standard python libraries so should run as long as python is installed:
python3 election_paths.py
I added 2 input params
python3 election_paths.py –list TX,FL,PA,OH,GA,NC,MI,VA,AZ,WI,MN,NV,NM,NH,ME,ME1,NE2 (to allow command line inputs of states)
and
python3 election_paths.py –file (to enter a list os comma-separated states in a file). I included a file called 17inplay.txt to preload the 17 states used in your second pass.
the paths are written to a file called paths.txt in the same directory from which the program is run
Rob: This works perfectly for me.
Maybe the next iteration (if any) should let me click both the states I consider “in play” and the states I consider “certain Harris” (or “certain Trump”), rather than relying on hard-coding to distinguish the latter two.
I’ll have fun playing with this. Maybe an even bigger plus is that this will inspire me to start learning python, probably by unraveling your code. Thank you!
I’m glad it worked!
I see that to be truly useful in real-time it will be necessary to allocate states to either Harris or Trump dynamically (If FL comes in early for either candidate it will be necessary to take it out of the in-play list and assign into the winning candidate).
Let me work on V2 over the weekend.
Rob —- Okay, now I am totally mystified.
Your program worked perfectly for me for a while. Now all of a sudden it says “0 paths” no matter what input I give it. I can’t figure out what’s changed. I erase your paths.txt and states.txt, so there is no obvious relic of past runs, but I still always get 0 paths. I’ve erased election_paths.py and redownloaded it just in case it had been somehow corrupted, but the same thing continues to happen.
I absolutely can’t figure out what’s changed, but I’m willing to bet that somehow it’s my fault.
Followup to #17: After many many tries I’ve just gotten a non-zero result, but it’s certainly wrong.
I chose Trump, and highlighted AK, AL, CA, CO, TX, WA.
The result returned is 2 paths. Here is the content of paths.txt:
Paths
“[‘CA’, ‘TX’, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”]”
“[‘CA’, ”, ‘WA’, ‘CO’, ‘AL’, ‘AK’, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”]”
AND — I just got it to give me the correct 1922 for our repeated example, but then it reverted to giving me 0 for many others (including our seven-state example, which it was most definitely getting correct before).
Rob: Here is what I now think:
1) Your code (which I have not made an effort to follow) contains this line:
if cnt >= 79:
This suggests that it is incorporating the assumption that our candidate is exactly 79 votes short of victory, which is of course true in our 17-state example but not in general otherwise. So I suspect this is a source of error.
2) When I first played with your code, I started with our 17-state example and got the right answer. Then I tried some other examples and got plausible answers.
3) My MEMORY tells me that I also tried our 7-state example and got the right answer, but when I came back later and tried the same example, I get “zero paths”. This led me to rack my brains about what might have changed, but it seems most plausible to me that my memory is false, and I never actually did try this example and have it work.
4) So I suspect there is a (probably quite minor) error in your code, centered around the appearance of that 79.
5) I still love yuor GUI.
AHA! And sure enough, when I change that 79 to a 44, I get the right answer for the 7-state example!! So I suspect you need a non-constant expression there. I also suspect that expression is “270-Total”. When I change it to 270-Total, I get correct results for both the 17- and 7-state examples.
I should have spent a bit more time testing!
That ‘if cnt >= 79:’ was an artifact of when I was trying to debug which I then forget to remove. It will cause the program to fail whenever the required vote is less than 79 (including the 7-state example you started with). I had tested this earlier but (I suspect) messed it up when trying to fix an issue where the paths generated were not in the same order (biggest state to smallest by votes) as in your pdf of paths).
Are you aware of any combinations of state and candidate where the requirement is > 79 and you still get 0 paths?
If this is the issue then it can be fixed by changing the code from:
if cnt >= 79:
paths.append(p)
to:
if cnt >= 0:
paths.append(p)
Anyway, I will correct this along with adding the enhanced interface which will allow each state (by clicking) to be either red (R)/blue (D)/yellow(InPlay).
I will also test with a few more combinations of states before reposting!
A couple of small observations:
1) If I put just one small state up for grabs, I find that both candidates have zero paths. This seemed wrong, because whichever way that state goes, *somebody* has to win. Then I realized this is caused by the fact that you are assuming PA and NC are ties, and not counting them toward either Trump’s total or Harris’s. This ended up giving several additional counterintuitive results, so I altered your code and gave NC to Trump and PA to Harris. Now I’m mostly happy.
2) Even with my change, so all states are allocated, if I choose NO yellow states at all, it tells me that Trump and Harris both have zero paths to victory. This can’t be right, but it’s presumably just an edge case and not symptomatic of any real problem.
I’ve now created the version where all states can be allocated to either Harris/Trump/InPlay (for some reason what I had thought was a relatively minor change taxed my brain more than I had expected!)
I need to stop now but will clean up the code, test some more and post tomorrow.
For the issue you list:
1) will go away as “tie” will no longer exist.
2) I will test that in the new version but I suspect its because in that case either Trump or Harris are guaranteed to have won so the concept of paths to winning would be redundant. I can add a message to explain why no paths were found in that situation.
Rob:
Entirely awesome!
One suggestion—-you might have buttons for things like “Assign to Harris any state where RCP says she’s currently at least 4 points ahead”, so one doesn’t have to do this manually. I expect it would be either impossible or too much work to pull the ahead-by numbers from the RCP site, so they’d have to be hardcoded (as they currently are) and users can update them manually from time to time.
But with or without this, I repeat that this is awesome.
I uploaded v2.
It only has one input parameter now and can be runs either as:
python3 election_paths_v2.py
(input file = states.txt)
or
python3 election_paths_v2.py –file states_17inplay.txt
(to aid testing I uploaded 4 files:
states.txt
states_17inplay.txt
states_7inplay.txt
states_allblue.txt)
I added some popups for scenarios where a candidate has enough votes to win without the in-play states , or cannot win even with all the inplay states.
I also created a simple utility:
build_states_list.py to autogenerate states.txt
to run:
build_states_list.py –pc 8 –file states_8pc.txt (defaults to state.txt if no file is specified)
All states with a margin equal to or less than 8% will be set as inplay and the rest to whichever candidate is ahead.
(It would be quite easy to add this functionality via a button on the main program I think)
I just looked at some online sites and find this one that has up-to-date data available in a downloadable spreadsheet.
https://www.electoral-vote.com/evp2024/Pres/pres_polls.csv
Spreadsheets are easy to download and process in Python so I think it may be possible to automate the data gathering process.
IGNORE WHAT’s BELOW. It was because I had failed to download states.txt.
Original (now obsolete) post:
Rob: When I try to run election_paths_v2.py, I get the following error:
line 26, in read_states
yellow_states = lines[2].strip().split(‘,’)
~~~~~^^^
IndexError: list index out of range
Okay—I’m playing with the new version and it appears to be getting all correct answers and doing everything I’d dreamed of (except the automated data gathering). I like the interface.
I’ve written two simple unix scripts that convert your paths.txt to html and to a csv file better suited for importing to Excel. You’re welcome to these scripts if you want them, though I’m guessing it would take you approximately zero time to write their equivalents yourself.
However, it looks like your new version does not generate the paths.txt file that your old version generated, which renders my scripts irrelevant…..It would be nice to get that feature back.
I just uploaded a utility called:
build_states_list_webdata.py
that reads the spreadsheet from https://www.electoral-vote.com/ and generates a states.txt file
to run:
python 3 build_states_list_webdata.py –pc – file
I haven’t looked at the data very closely but it looks reasonable. One issue I see is that it doesn’t have data for the congressional districts which will still have to be maintained manually.
On the paths.txt issue.
That is generated in my environment.
Are you saying that is not generated or the format has changed ?
The first few lines for 17states is:
“[‘TX’, ‘FL’, ‘PA’, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”]”
“[‘TX’, ‘FL’, ”, ‘OH’, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”]”
“[‘TX’, ‘FL’, ”, ”, ‘GA’, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”, ”]”
I;n not aware of having changed it.
just uploaded election_paths_v2_1.py that should write paths.csv in a way that excel and open office can open properly.
I have not downloaded v2_1 yet, but here is what happens with v2:
I’ve just run an example where there are 792 paths. The file paths.txt is not created. The only output is written to the screen, and here is that output in full:
ddd 270.0 191 79.0 159
path [‘FL’, ‘PA’, ‘GA’, ‘NC’, ‘MI’, ‘VA’, ‘AZ’, ‘MN’, ‘WI’, ‘NV’, ‘NM’, ‘NH’, ‘ME’, ‘ME1’, ‘NE2’] [‘MI’, ‘NC’, ‘PA’, ‘FL’]
(so only one path is shown).
Addendum: v2 continues to behave as described above, but v2_1 produces paths.csv, which looks fine.
I can only imagine I must screwed up the v2 that I uploaded – are there any issues with v2_1?
BTW: I’m close with a version 3 that will have buttons to 1) reset all the states based on a new margin (selected from a drop down) and 2) download and refresh the data from the elections_path dataset.
I’m having a few issues with the GUI not behaving as I expected – but hopefully have it by tomorrow
No issues with v2_1 !
V3 updated.
to run:
python3 election_paths_v3.py –file state_data.txt
I have added functionality:
– to mark as in-play all states >= a margin value selected from a drop down
– to download and use data from https://www.electoral-vote.com/evp2024/Pres/pres_polls.csv
I have taken most of the hard-coded data out of the program and put it in the input file.
A couple of issues:
– The status of states can still be toggled between Dem/Rep/InPlay. This status is lost and reset when the data is refreshed using the new functionality. I can see a case for keeping it even after a refresh but decided it was simpler to go with this approach.
– I’ve started to notice that its taking quite a while to generate the paths when a lot of states are in play. I will take a look to see if this algorithm can be optimized.
I uploaded election_paths_v31.py which is the same as v3, but with some minor memory usage tweaks. I couldn’t really find any ways to optimize the algorithm – any attempts to limit the number of paths that needed to be checked always took up more time than they saved so I abandoned that approach and had no new ideas. This version manages memory better and is less likely to crash with out of memory conditions when there are lots if inplay states.
This is probably the final version unless I get any specific request – I’ll see on election night how useful it is.
Uploaded election_paths_v4.py with some features I think add value.
– When you click on a state to change its color it will be excluded from refresh functionality until you hit the “clear click” button
– Purely visual – but I added the margin to each state
Finally nailed the performance issue – runs really fast now
election_paths_v5.py
Rob: I don’t see v5 on your page. Also v4 doesn’t run; the message is “No module named requests”.
Apologies – I had uploaded v5 it to the wrong directory. Fixed now.
I suspect it will also get the requests error – this is related to the additional code to get the data from the web – but I moved the code so you should only get this when when you hit the “refresh from website” button and not on startup.
The error can be fixed by running:
pip install requests (I’m hoping you have the pip utility installed in your environment).
I also uploaded a file called state_data_orig .txt which is set up for the original 17 in-play states scenario
this can be run by:
python3 election_paths_v5.py –file state_data_orig.txt
Rob, objects like state_votes that exist to map one value to another should generally be Python dict objects so you don’t have to iterate through every element just to look up one value.
state_votes = { ‘DC’: 3, ‘HI’: 4, … }
state_votes[‘DC’] # 3
I’m interested in making a Javascript version so people can easily use it on their phones. In my version, there would be some ability to call a state (like Texas) for a particular candidate, but then also say how miraculous it would be for it to go the other way. Then the paths to victory can be sorted by how many miracle points they require, from least-miraculous to most.
@41 Thanks David,
Yeah, I started out using dict objects but at some point as I was going for speed of development over elegance of code (and to some extent performance) I switched to lists which I find much easier to manipulate even at the price of those ugly list look-ups. I think it would be quite easy to switch back to dict objects now the code it done – I may do it just to get more comfortable with them. The whole program ended up as a bit of a hack and could use a good code cleanup.
Good luck with your version!
Out of curiosity – did you run my latest code in your environment?
I have worked on my version all day. It requires about 300 lines of Javascript and I put it up here:
http://tmphax.com/election2024
You can get a result of 1922 paths if you set the Tiebreaker to “Likely Republican” (meaning the Trump will win due to unfaithful electors or a congressional vote if he winds up with 269 votes) and also click the “Allow leaning districts to vote either way” checkbox.
I think my assignment of the 10 “leaning” states are slightly different than Dr. Landsburg’s. The polls must have changed.
Check it out and feel free to view the source!
@42 Rob: I tried to run your version for a little bit, but I’m using Windows and “pip install pandas” in MSYS2 did not work, nor did “pacman -S $MINGW_PACKAGE_PREFIX-python3-pandas”. Adding extra libraries is always a liability!
I liked the way you present the status of the states!
One area that I couldn’t reconcile was why even with the 17 states you have listed as “toss-up”, “Leans Republican” or “Leans Democratic” set to the same as Steve’s it was necessary to toggle the tiebreaker option to get the 1922 paths for Harris. It should be 1922 even when avoiding a tie.
When I ran for Trump I got 2730 with Tiebreaker being a tossup and 1709 with Tiebreaker likely Republican – both different from Steve’s results of 1646. Its quite possible I’m setting it up wrong.
Could I request an enhancement to move the path count to the top rather the bottom of the list of paths to avoid having to scroll down past all the paths to see the count every time one makes a change?
Also, how do I view the source code ? I’m not familiar with javascript.
@44 Thanks, Rob, I made the changes you suggested!
You can click right-click on any website and click “View page source” to see its source code. Then you look for “” tags or other signs of Javascript, and that would lead you to my source code here:
https://tmphax.com/election2024/script.js
In this election, victory requires 270 electoral votes OR (269 electoral votes AND winning the tiebreaker procedures). I realized that’s mathematically equivalent to just making “Tiebreaker” be a district with a single vote, and putting it and the end so the depth-first-search algorithm only uses it as a last resort.
Steve is trying to compute the number of paths for a clean victory where the candidate gets 270 or more votes in the actual electoral college. For now, to reproduce Steve’s results on my app, you have to set “Tiebreaker” to be “Likely” for the party opposite of the one whose victory paths you are calculating, so that it never contributes a vote to your selected party. I was able to reproduce the 1646 number.
I think I’ll redo the UI for how ties are handled, and just put a checkbox for “Show electoral college ties” or something.
Just added a slightly amended version to:
https://drive.google.com/drive/u/0/folders/1cHmC_Taymt1EWKLreQPLam1EHDU-peJQ
It fixed a bug and added some sort options to the list of states (Margin/a-z/ev votes)
to run:
python3 election_paths_v5_1`.py –file state_data_orig.txt
@44 David.
Just to confirm I also see the 1646 number for Trump on your script now. I don’t think I had the TieBreaker set up correctly yesterday.
Just uploaded a version created with pyinstaller that should eliminate any issues with dependencies.
to run:
./election_paths_v5_1 –file state_data_orig.txt
Roger: “We used to have an system where votes were cast and counted on Election Day, with observers. As it is, it is unlikely that we will have a winner on election night, and unlikely that everyone will accept the outcome as fair.”
Yes, like 2000. What utopia are you imagining? Some time when America great and votes were all counted on the day they were cast.
Such a thing would be easier to accomplish if Republicans did not insist on waiting until after election day until postal vote can be processed, if not counted. Talk about creating a problem, then complaining about the [problem you just created.
It is unlikely that everyone will accept the outcome as fair. Trump and his supporters will accept the result if he wins. If he does not, very many of his supporters will not accept the result. That could all be resolved almost instantly if trump himself accepted the result. If Trump acknowledged defeat, in the case he lost, then there would be no problem. We all know that this will not happen. Trump will not accept defeat. He still has not accepted defeat for 2020.
You have not endorsed either candidate directly. Fair enough.
You have declared that Harris is mores delusional than Trump.
That I do not get.
Trump displays on a daily basis a lack of understanding of economic principles. He thinks tariffs generate income. Harris claims price gauging is harmful. Harris suggest some form of price control to avoid price gauging, which is ill defined. Trump declares tariffs, which he thinks generates income.
Apart from their economic ideas, it is clear that Trump undermines the rule of law. Only under Trump do we face the possibility of all civil servants being dismissed and replaced with lackeys. We know this will not happen with Harris. We have good reason to believe this will happen with Trump.
We know, under Biden, that the President distances himself from DOJ. and DOJ distances itself from prosecutions that have political implications. Trump himself has assured us that such separations will not apply to him. Trump has told us directly that he will direct DOJ personally.
We know that if we elect Trump, we are abandoning the rule of law. He has told us this.
What I find difficult to understand is that you, Landsburg, do not outright declare for Harris. Not only that, but suggest Trump is the best option. You mut know that choosing injecting bleach vs price controls is no at all a fair comparison.
Please, give us an economists view. Who has the best economic understanding?
#50. “You have not endorsed either candidate directly.” I was wrong, I see you have come out for Harris.
Harold (#50): Yes, I much prefer Harris to Trump. This doesn’t change the fact (discussed on other threads) that her views on price gouging are about as delusional as any one of the 60,000 or so delusional things that Trump believes.
Hi, I found this a really interesting question and challenge. I saw that Rob Rawlings thought as much, too! If you have any interest, I created an html version using javascript. It’s not very pleasant to look at, and it’s not the most elegantly coded, but I think this will do exactly what you were hoping for, including crossing them out as you go along.
https://circumspectus.com/election/pathways.html
Chris Oldman: This is great. Thanks for sharing it.