Tutorial: How to Make a Clock Chart in R
Hello everyone,
I hope your 4th of July weekend was as relaxing as mine was. The weather was perfect over in Cape May so I spent a whole weekend grilling, swimming, watching sunsets, picking figs and sitting on the beach. I wanted to give another R tutorial to my paid subscribers today, detailing how I made this clock looking chart from last week’s write-up about game durations in the NFL.
This R tutorial assumes you already have a play-by-play dataset from the 2024 NFL season saved to your local machine. Please reference this tutorial to see how that’s done.
Let’s hop right into it.
1. Download Packages and/or Load Libraries
I’m going to operate like you don’t have any of these R libraries downloaded yet but I’m going to assume you have R and an IDE of your choice (RStudio, Positron, VSCode, etc.) downloaded on your machine. First step is to install and load the packages.
I am also assuming that your computer has the Times New Roman font loaded on it. That font_add command will work for you if you run this on Windows like I am, but you’ll need to change the path if you’re on a Mac or another device. Those if(!RequireNameSpace(…) install.packages(““) lines are only necessary if you don’t have these packages yet but it’s a good way to quickly install them if you need to, and skip them if you don’t. If you’re worked in R before you’ll probably have things like dplyr and tidyr already, but perhaps not have a package like circlize yet.
Setting the background color as white is also something that only us VSCode users will need to include in their code. RStudio users shouldn’t have to.
Step 2: Query the Game Durations
One little peculiarity I’ve noticed with the nflfastR dataset is that the final play of each game’s final play has a time_of_day equal to NA. All this dplyr query is doing here is for each game_id it’s finding the max value in that time_of_day column (always the second to last play from the game) and subtracting the minimum from the time_of_day column (kickoff) from it. That gives us an output in minutes that we can double check:
178 minutes is right around 2.96 hours, 208 minutes is 3.4 hours. That week 1 Packers-Eagles Brazil game was in a primetime slot on Peacock, so it makes sense that it would be longer. I went into the data to triple check this and in ascending order, the first time_of_day for this game is 2024-09-07T00:17:15Z in UNIX time, and the last value is 2024-09-07T03:45:42.460Z. The difference between these two times is 208 minutes.
Step 3: Create our Final DataFrame With a Filter for Regular Season Only Games
This just makes sure we only look at regular season game durations. This is just an arbitrary choice I made when making the viz.
This will display a 32 row tibble with each team’s abbreviation and the number 17 next to it if executed correctly.
Step 4: Query Top 12 Teams by Average Game Duration
Just doing exactly as the title says here.
We’re taking the average value of each game time by team and only keeping the top 12. The lines below the df lines are all for formatting purposes. You may have to adjust things like the logo_y and label_y position later on depending on your device to get them exactly correct. A common issue I ran into is the actual NFL logo png biting into the line graph, so make that logo_y value smaller to avoid that.
Step 5: Load in Team Logos and Colors from nflreadR
Simple as a left join based on the abbreviation for this step.
Step 6: Time to Circlize It
This is an incremental step to show you our progress. Here’s what our circlize plot will look like after this step:
We have our leaders in the 12 o’clock position and the rest of the top 12 are in clockwise order.
Step 7: Add Team Logos
After this step, here’s how the graph will look:
Here’s what I was talking about earlier with the actual team logos cutting into our line graphs. Don’t forget to adjust the logo_y variable above and multiply it by a smaller number if this is happening to your plot.
Step 8: Add Plot Labels
Now we’re really jamming. Here’s how it looks all together now:
Like I said, tweak with the label and logo placements. Mine aren’t perfect here, but that’s okay. Let’s call it a happy little accident.
Step 9: Final Plot with Title and Subtitle
Put whatever center image you want in there, but I put my logo in it to give it the final look of a clock. Here’s the final plot:
And there you have it! Here’s the full code below:
Keep reading with a 7-day free trial
Subscribe to The Spade to keep reading this post and get 7 days of free access to the full post archives.