I’ve finally completed a first draft of an interactive shot chart visualization for NBA players, with the inclusion of a couple filters and metrics that allows a user to slice the data. This wasn’t a small task. In fact, most of the heavy work occurred in the backend to get all the data in an analyze-able format.
But I’m some people might be interested in how to create their own shot charts. Here’s how I did it, with an explanation of the choices I encountered and the technologies I utilized along the way.
Creating a visual
On a conceptual level, making a shot chart requires 3 distinct tasks:
- Drawing a basketball court
- Obtaining the x-y coordinates of shots
- Drawing the x-y coordinates on the basketball court. Summarize to areas or zones if desired.
How you accomplish these 3 things are really up to you.
I chose SVG, or Scalable Vector Graphics, as my drawing technology. SVG is an emerging web standard, and most modern browsers can interpret SVG natively. This means if you want to distribute your shot chart over the internet, your users don’t have to download any plugins (unlike Flash or Java), and you don’t have to code in a separate, non-browser language.
Like its name implies, another great thing about SVG is the ability to scale graphics without getting fuzzy. If you’ve ever tried to make a static image file larger, you’ll have noticed the image looking less crisp around the edges. With SVG, you have the ability to scale up or down a graphic without sacrificing resolution.
If you’re unfamiliar with SVG, I’d encourage you to download a program called Inkscape, which is an open-source application similar to Adobe Illustrator that allows you to create SVG-based files.
Obtaining X-Y coordinates
As I mentioned earlier, this is the hardest part of the task. This is out of the scope of knowing how to do a visualization, but if you’re interested in how I got this data, I basically created my own parsing codebase that not only allowed me to extract X-Y coordinates, but also combined that with the play-by-play data.
If you’re interested, you can find the code at https://github.com/kpascual/nbascrape. Honestly, it’s kind of a mess. I’d rather you skip the hassle and pick up the final outputted data at http://vorped.com/bball.
In terms of file format, I use JSON, because I find it more lightweight to traverse than CSV or XML. Which brings me to my last technology…
With SVG, you can draw a basketball court pretty easily. With a shot chart’s X-Y coordinates, you know where you need to place the shots on the court you just drew. Now to programmatically place the shots on the court (which you wouldn’t want to do manually for tens or hundreds of shots), you’d need to use a scripting language.
Initially I used RaphaelJS to place shots on the basketball court. But recently, I have switched over to using another library called d3. Both are perfectly fine, but I found d3 to be more adept at manipulating SVG elements on-the-fly, which becomes very important when creating interactive visualizations. If you want to create static shot charts, either library will suffice.
What I love about d3 is the simplicity of its API. Though the syntax can be a little weird, its weirdness enables you to write succinct code, abstracting away all the coding mechanics of how things have to happen, and allowing you to focus more what you want to visualization to do and look like.
Those are the technologies I used to create the shot chart visualizations. However, I wanted to take it a step further, and allow user interaction. I think a lot of the shot chart visualizations out there are great, but I feel what’s missing is the ability for users to do their own explorations.
My choices of technologies all hinged upon my need to have user interaction. All of these are web standards within the browser, and even in this world of mobile apps, I still believe the browser will continue to be the primary app for the interactive with the web.
With this visualization as a foundation, I still have plans to allow even more exploration of shot chart data by implementing more data. Here are some upcoming features I hope to accomplish:
- Filtering by multiple games or periods (dependent on an update to the CrossFilter project)
- Adding filters by shot type (i.e. jumpers vs. hook shots vs. bank shots)
- Showing assisted vs. non-assisted shots
- Zone FG % compared to player’s historical averages
- Zone FG % compared to players at their position
- Porting the visualization over to entire teams, and not just players… maybe even five-man units?
I’ve got a few other really fun ideas floating around in my mind, but if you have any yourself, please feel free to share with me below.