Creating FiveThirtyEight's election prediction chart in Tableau
This article was originally published on Ken Flerlage's website.
Nate Silver’s FiveThirtyEight site always has great visuals and the November US mid-term elections was no exception. As I was catching up on their pre-election projections, one chart in particular caught my eye.
The chart shows the chances of different outcomes of the election, based on their predictive models. There are a number of things I love about the chart, including its general simplicity, colors, and hover actions. So, being a Tableau guy, I just couldn’t resist taking a shot at creating it in Tableau.
Creating it in Tableau
Let’s start by breaking down the chart into its key components and functionality. The main component is the bar chart that shows the chances of different splits of seats won by Republicans and Democrats. This is pretty simple to create, but the bar chart has a number of other more complex features:
- Hovering over the bars cause them to change colors
- Hovering causes labels showing the FiveThirtyEight’s predicted chances
- Hovering causes an arrow at the bottom to grow, showing which party would be gaining seats and how many
While all of these features are very nice, the last was the one that most caught my attention—and would prove to be most challenging in Tableau.
Note: Before I move on, I’ll note that the chart has a few other features I did not mention. There is an 80% confidence band, which I did not create because I didn’t have the data underlying it. The chart also has some BANs on the left and right showing the general chances of each party winning the Senate. I did include those on my chart, but they are simple text boxes, again because I didn’t have the underlying data needed to create these automatically.
Of course, I needed to start with some data. As noted above, the underlying prediction data is not readily available on the site. So, the best I could do was manually collect the chances of each of the different Republican/Democrat splits. My resulting data set was pretty simple.
Creating the basic bar chart was pretty simple, but I immediately ran into a problem labeling the horizontal axis. The original chart has the number of seats for each party stacked by color that indicates party. There is no way that I know of to do this using out-of-the-box axis labels in Tableau, so I leveraged some calculated fields and a dual axis to place those labels exactly where I needed them.
I won’t go into any further detail on this, but feel free to download the workbook to see exactly how it was done.
Next were the bar colors. By default, the original chart colors the bars based on who would control the Senate. If the Republicans maintain at least 50 of the seats, they control the Senate, with the Vice President acting as a tie breaker. So, all bars where Republicans have 50+ seats are red and all others are blue. But when you hover over the chart, the other bar colors are dull, which has the effect of pushing them to the background. I used the new feature of Tableau 2018.3, Set Actions, to address this. I created a set called Record Highlighted then created a Color calculated field that would make the bar red if Republicans have 50+ seats and blue if Democrats have 51+ seats, but would make the color a bolder red or blue if that particular bar was in the set. Finally, I created a set action on the dashboard that would add the record to the set on hover.
Note: My highlighting works slightly differently than the original as my default colors are dulled and the highlight color makes each a bit darker and bolder. I had originally created something that looked exactly like the original but that required the set action to remove all values from the set when clearing the selection. Unfortunately, this caused the screen to be a bit “flashy” as the set actions continually fired. Thus, I settled for a slight compromise, but I think it works pretty well. I’m hopeful that the flashing issue is resolved in a future update to this amazing feature.
As noted earlier, hovering over a bar causes the chance % to show. I could have set up a highlight action then set the labels to only show when highlighted, but the highlight action causes the non-highlighted marks to dull in color. I was already controlling that myself and didn’t want the automatic dulling to occur. To deal with this I just tied onto the existing set actions. I created a calculated field called Chance Label which would show the % only for members of the Record Highlighted set. If the bar is not a member of the set, the calculated field is simply NULL. Thus, when I hover over a bar, the label will appear only for the highlighted bar.
I stated earlier that my favorite part of the FiveThirtyEight chart was the arrow at the bottom that grows as you hover and shows which party would be gaining seats and how many. Creating the first iteration of this was relatively simple—it was just a bar chart that is either red or blue and grows in size based on a filter action sourced from the primary bar chart.
To create the arrow points on each end, I used PowerPoint to create two custom shapes. Each shape is essentially a white rectangle with a transparent triangle cut out of either the left or right. Note: In the images below, the checked area indicates that it is transparent.
Using a dual axis at the end of the bar chart, I was able to create what looks like an arrow point.
But, the original FiveThirtyEight chart used a gradient color from white to red/blue and I wanted to do the same. Unfortunately, Tableau does not allow bar charts to be colored using gradient color palettes. So, I needed to get a bit creative. I decided that I would try to break up the bar chart into 100 separate stacked marks using bins. I created an additional data set which I called Range with just one column and two rows.
Then, I joined that to my original data set and created bins on the Range field, and created a calculated field that divided the original bar size by 100. By placing the bins field on detail, it created 100 individual stacked marks. Since each is 1/100th the size of the original bar, the 100 marks added up to be the same size as the original. Next, using an Index table calculation—computed using the bins—I was able to assign a stepped gradient color to each individual mark. Finally, I used a dual axis and the same custom arrow end shapes to create the arrow point. The gif below attempts to show the individual marks.
Note: My apologies if this is a bit confusing. Feel free to download the workbook if you’d like to see exactly how it works. And let me know if you’d be interested in a more detailed explanation of how to create a gradient colored bar chart.
Bringing it all together
Finally, I pulled everything together on a dashboard. The chart has some reference lines in the background showing party control and the current seat breakdown. Part of the issue with these reference lines is that they span multiple charts, so while I won’t go into detail here, I leveraged Tableau's transparent sheets to push these reference lines to the background. From there, I just aligned the charts, added titles and the BANs. In the end, we have a chart that looks pretty darn close to the original by FiveThirtyEight. Here's an animation showing it in action, but feel free to check out the interactive version on my Tableau Public page.