Populate a database with NBA shot data
Switch branches/tags
Nothing to show
Clone or download
Latest commit dbaaf25 Nov 16, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
app nba shots db Apr 1, 2018
bin nba shots db Apr 1, 2018
config nba shots db Apr 1, 2018
db nba shots db Apr 1, 2018
lib nba shots db Apr 1, 2018
log nba shots db Apr 1, 2018
public nba shots db Apr 1, 2018
test nba shots db Apr 1, 2018
tmp nba shots db Apr 1, 2018
vendor nba shots db Apr 1, 2018
.gitignore nba shots db Apr 1, 2018
Gemfile upgrade ruby and gem versions Nov 5, 2018
Gemfile.lock upgrade rack Nov 16, 2018
LICENSE nba shots db Apr 1, 2018
README.md nba shots db Apr 1, 2018
Rakefile nba shots db Apr 1, 2018
config.ru nba shots db Apr 1, 2018
package.json nba shots db Apr 1, 2018


NBA Shots DB

Rails app to populate a PostgreSQL database containing every shot attempted in the NBA since 1996.

Blog post with some analysis of the data: http://toddwschneider.com/posts/nba-vs-ncaa-basketball-shooting-performance/

Data comes from the NBA Stats API. As of March 2018, the database contains ~4.5 million shots from 2,000 players, and takes up 1.5 GB disk space. Database also includes player/season aggregates segmented by shot distance and the distance of the closest defender at the time of the shot. Closest defender info is not available for individual shots, but the aggregates are available in the closest_defender_aggregates table.

NCAA men's college basketball data

NCAA data is available via Sportradar on Google BigQuery. The mbb_pbp_sr table contains men's basketball shot chart data since 2013.

The app/lib/ncaa_shots subfolder of this repo contains additional scripts to process the NCAA shots data and merge it with the NBA data, see here for more info.


Assumes you have Ruby and PostgreSQL installed

git clone git@github.com:toddwschneider/nba-shots-db.git
cd nba-shots-db/
bundle exec rake db:setup


Import all available data (will take a few hours):

bundle exec rake import_all_shots
bundle exec rake jobs:work

Alternatively, import data selectively by going into the Rails console and running, e.g.:

lebron = Player.find_by(display_name: "LeBron James")
lebron.create_shots(season: "2017-18", season_type: "Regular Season")


  season: "2017-18",
  season_type: "Regular Season",
  shot_distance_range: "17-18",
  closest_defender_range: "2-4 Feet - Tight"


  • player#create_shots uses Postgres's COPY command instead of Rails's #create method because COPY is ~10x faster
  • Shots have no natural unique identifier: no external IDs, no guarantee that there's only 1 shot from 1 player at the same second of the same game, etc. Accordingly, player#create_shots deletes and replaces data every time it is run.

See also

BallR: Interactive Shot Charts with R and Shiny


The BallR shot chart app hits the NBA Stats API directly. In the future, it might make sense to expose an API interface from NBA Shots DB, then have BallR use that API instead of the NBA Stats API. In that world, BallR would be able to support more advanced options like career-long charts, team-level shot charts, etc.

BallR also has a college edition that uses the Sportradar data to make college basketball shot charts.