NBA Shot Charts With Node.js and D3.js
The NBA Shot Chart has become iconic in many ways. It’s a quality visualization that gives context to the boring summarized score board data we see everyday. This context is valuable to basketball nerds and lay folks alike. In any event this post is not about the intricacies of basketball but about using Node.js/ d3.js to make cool shot carts.
Getting the data
First off, kudos to Greg Reda for getting a hold of this API that grabs data from NBA.com. He outlines all the details of finding the API, so if you want more of those I advice looking there.
The URL takes a bunch of parameters but the only one you need to concern yourself with is the player id. You can get this id from NBA.com on player specific pages. From there you can adjust the season but I found this didn’t really work for every player and I’m not sure why that is. Nonetheless the 2014-2015 season data worked for every player I tried.
The return of the get request looks OK on a console log but it’s deceiving because the API returns a string. I found this to be a bit insane but It’s not as crazy as I thought on first pass. On examination of the JSON true there are some headers you need to deal with but it’s pretty straight forward. I printed out the contents and just mapped the data I needed like so:
Fortunately, someone was nice enough to tackle most of this problem from that d3 side via this repo. What it gives you is the ability to make a chart like this:
Plotting Problems
The data from the API gives us X values from -250 to 250 and Y values from -20 to 200. The d3 charting library works X from 0 to 50 and Y from 0 to 94. I did some algebra and tried a few values until I got something that looked right, I ended up with this:
Grouping Problems
Once we look at all possible X-Y values we end up with quite a few duplicates. D3 handles that OK but in order to calculate a Z value (this is how many standard deviations a shooting percentage from an X-Y combination is above or below the mean) we need the data grouped already. For this task I used the d3 library:
Unfortunately the key values get stringified in the process resuling in a sensless ’{value},{value}’ set up. Parsing it back out into an array isn’t all too painful. From there I grabbed the mean and standard deviation necessary for calculating the z value.
Calculating the z value from here was just some simple math:
In order to plot the data you need to get this array of objects into your HTML file. This can be accomplished by either making your Node.js code a server and serving it up to the front-end or using something like Browserify. I think Browserify makes the most sense for this kind of project but I had some issues with datalib and Browserify that I am in the process of working out. For this post, I just sent my data via server and plotted it with D3:
What it looks like
One thing I find interesting about this chart is how Oladipo takes a health amount of shots from all over the court. There is not a specific spot that’s getting too much love. That being said he’s not shooting much better than average in all too many places.
Cross-Dunk-Poster-Shimmy
Finishing Up & Future
After trying to pretend like arrays and objects were good enough I wish every programming language had the dataframe data type.
— Jowanza Joseph (@Jowanza) August 17, 2015
I learned quite a bit from tackling this project. The biggest lesson has been that working with data is much easier when you have dataframes. I’ve done a lot of work in R and Python and have recently take up Julia and a problem like this could be done in a much cleaner fashion. That being said, these shotcharts are really cool and getting at the data isn’t hard. I have to praise the d3 and datalib libraries because they made it much easier to accomplish this.
In the coming weeks I will publish a repo that’ll package this all up into something nice and reusable. I wanted to share my learnings and hope it can be of benefit to someone in the interim.