Work originally done on 2018-11-02 - the day after Rose's career high. Code modified on 2019-11-23

Get Data

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
import requests
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

%matplotlib inline

Define functions to access NBA API

In [2]:
header = {'Host': 'stats.nba.com',
 'Connection': 'keep-alive',
 'Accept': 'application/json, text/plain, */*',
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36',
 'Referer': 'https://stats.nba.com/',
 'Accept-Encoding': 'gzip, deflate, br',
 'Accept-Language': 'en-US,en;q=0.9'}

def playergamelogs(PlayerID,DateFrom='',DateTo='',GameSegment='',LastNGames='0',LeagueID='00',
                   Location='',MeasureType='Base',Month='0',OpponentTeamID='0',Outcome='',
                   PORound='0',PaceAdjust='N',PerMode='Totals',Period='0',
                   PlusMinus='N',Rank='N',Season='2018-19',
                   SeasonSegment='',SeasonType='Regular Season',ShotClockRange='',
                   VsConference='',VsDivision=''):
    url = 'https://stats.nba.com/stats/playergamelogs?'
    api_param = {
        'DateFrom' : DateFrom,
        'DateTo' : DateTo,
        'GameSegment' : GameSegment,
        'LastNGames' : LastNGames,
        'LeagueID' : LeagueID,
        'Location' : Location,
        'MeasureType' : MeasureType,
        'Month' : Month,
        'OpponentTeamID' : OpponentTeamID,
        'Outcome' : Outcome,
        'PORound' : PORound,
        'PaceAdjust' : PaceAdjust,
        'PerMode' : PerMode,
        'Period' : Period,
        'PlayerID' : PlayerID,
        'PlusMinus' : PlusMinus,
        'Rank' : Rank,
        'Season' : Season,
        'SeasonSegment' : SeasonSegment,
        'SeasonType' : SeasonType,
        'ShotClockRange' : ShotClockRange,
        'VsConference' : VsConference,
        'VsDivision' : VsDivision,
        }
    response = requests.get(url,params=api_param,headers=header)
    data = response.json()
    return pd.DataFrame(data['resultSets'][0]['rowSet'],columns=data['resultSets'][0]['headers'])

def seasons_string(start,end):
    '''
    creates a list of NBA seasons from start-end
    '''
    years = np.arange(start,end)
    seasons = []
    for year in years:
        string1 = str(year)
        string2 = str(year+1)
        season = '{}-{}'.format(string1,string2[-2:])
        seasons.append(season)
    return seasons

Make API calls:

I'm adding a sleep of 1 seconds after every API call to make sure we do not exceed the rate limit

In [3]:
rose_id = 201565

data_list = []
for season in seasons_string(2008,2019):
    data_list.append(playergamelogs(rose_id,Season=season))
    print(season)
    time.sleep(1.0) 
2008-09
2009-10
2010-11
2011-12
2012-13
2013-14
2014-15
2015-16
2016-17
2017-18
2018-19

Convert list of dataframes to a single dataframe

In [4]:
data = pd.concat(data_list,ignore_index=True)

Data cleaning and aggregation

In [5]:
data['GAME_DATE'] = pd.to_datetime(data['GAME_DATE'])
data['PTS'] = pd.to_numeric(data['PTS'])
data = data.sort_values(by='GAME_DATE')
data = data.set_index('GAME_DATE')
In [6]:
import matplotlib.dates as mdates

Season averages

In [7]:
season_avg = data.groupby('SEASON_YEAR')['PTS'].mean()

Prepare season averages data for plotting

In [8]:
import datetime as dt
x2 = [dt.datetime(2009,2,1),dt.datetime(2010,2,1),dt.datetime(2011,2,1),
     dt.datetime(2012,2,1),dt.datetime(2013,11,1),
     dt.datetime(2015,2,1),dt.datetime(2016,2,1),dt.datetime(2017,2,1),
     dt.datetime(2018,2,1),dt.datetime(2019,2,1)]
y2 = season_avg.tolist()

Plot data:

In [9]:
xlabel = 'Season'
ylabel = 'Points'
title = 'Derrick Rose - Welcome to The 50 Point Club'
name = 'By: DoingTheDishes'
source = 'NBA.COM'
figsize = (1.33*8,8)
bg_color = (0.97,0.97,0.97)

# create figure
fig = plt.figure(figsize=figsize)
# change figure face color
fig.set_facecolor(bg_color)
    
# create labels and title for figure
fig.text(0.01,0.01,name,fontsize=14.0,color='gray',
         horizontalalignment='left',verticalalignment='bottom')
fig.text(0.99,0.01,'Source: '+source,fontsize=14.0,color='gray',
         horizontalalignment='right',verticalalignment='bottom')

fig.text(0.01,0.99,title,fontsize=22.0,
        horizontalalignment='left',weight="bold",verticalalignment='top')

fig.text(0.53,0.048,xlabel,fontsize=16.0,color='black',
               horizontalalignment='center',verticalalignment='center')

fig.text(0.03,0.18+0.77/2,ylabel,fontsize=16.0,color='black',
               horizontalalignment='center',verticalalignment='center',rotation=90)

# add axes - the numbers define the left, bottom, width and height of the axes. The axes is where we plot our data.
ax = fig.add_axes([0.1,0.18,0.85,0.77])
# change the color of the axes
ax.set_facecolor(bg_color)   

# make the figure look a little better
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.axes.tick_params(length=0)
ax.tick_params(labelsize=16)

##################################################
# This is where we do the actual plotting 
x = data.index
ax.plot_date(data.index,data['PTS'],'o',alpha=0.5,markersize=10,color='#008fd5',label='Game to Game')
ax.plot_date(x2, y2,'k+',ms=14,mew=4,label='Season Average')

# Add arrow with the text career high
ax.annotate('Career High', (mdates.date2num(x[-1])-150, 49.5), xytext=(-100, -50),fontsize=16, 
            textcoords='offset points', arrowprops=dict(arrowstyle='-|>',color='k'))

# set the x and y limits
ax.set_xlim([mdates.date2num(x[0])-50,mdates.date2num(x[-1])+50])
ax.set_ylim([-1,55])

# define and rotate the x labels
ax.set_xticklabels(seasons_string(2007,2019));
plt.xticks(rotation=45)

# add legend
leg = ax.legend(loc='upper left',numpoints = 1)
frame = leg.get_frame()
frame.set_facecolor((0.97,0.97,0.97))
frame.set_edgecolor((0.97,0.97,0.97))

# save figure
fig.savefig('Rose.png',bbox_inches='tight',facecolor=fig.get_facecolor(), edgecolor='none')

Work done by Adam Reynolds, Tim Long and Eyal Shafran



Comments

comments powered by Disqus