Ejemplo n.º 1
0
def get_player_shot_chart_info(player_name, season_id, season_type):

    # Searching for requested player
    all_nba_players = players.get_players()
    player_dict = [
        player for player in all_nba_players
        if player['full_name'] == player_name
    ][0]

    # Creating the dataframe for the player's career
    career = playercareerstats.PlayerCareerStats(player_id=player_dict['id'])
    career_df = career.get_data_frames()[0]

    # Finding the team that the player played for during the season
    team_id = career_df[career_df['SEASON_ID'] == season_id]['TEAM_ID']

    # Endpoints to acquire the shot chart detail
    shot_chart = shotchartdetail.ShotChartDetail(
        team_id=int(team_id),
        player_id=int(player_dict['id']),
        season_type_all_star=season_type,
        season_nullable=season_id,
        context_measure_simple="FGA").get_data_frames()

    return shot_chart[0]
Ejemplo n.º 2
0
def get_shot_detail_data(player_id):
    if player_id:
        shot = shotchartdetail.ShotChartDetail(
            team_id='0', player_id=player_id,
            context_measure_simple='FGA').get_data_frames()[0]

        shot = shot[shot.LOC_Y <= 417]
        shot = hexagonify(shot.copy())

        shot['min_left'] = shot['SECONDS_REMAINING'] / 60 + shot[
            'MINUTES_REMAINING']
        shot['year'] = shot['GAME_DATE'].map(lambda x: int(x[:4]))
    else:
        shot = pd.DataFrame.from_dict({
            'EVENT_TYPE': ['Made Shot', 'Missed Shot'],
            'LOC_X': [1000, 1000],
            'LOC_Y': [1000, 1000],
            'SHOT_ATTEMPTED_FLAG': [0, 0],
            'SHOT_MADE_FLAG': [0, 0],
            'x': [0, 0],
            'y': [0, 0],
            'min_left': [0, 0],
            'year': [0, 0],
            'SHOT_ZONE_BASIC': ['', ''],
            'SHOT_ZONE_AREA': ['', ''],
            'ACTION_TYPE': ['', ''],
        })

    return shot
Ejemplo n.º 3
0
    def get_player_shot_info(self, player_id, team_id, num_games):
        """Match player id to shot chart information.

        :param int player_id:
            Player ID that is associated with player user provided.

        :param int team_id:
            Team ID that is associated with the player user provided.

        :param int num_games:
            Indicate length of shot info to acquire.

        :returns DataFrame
        :rtype pandas.DataFrame
        """
        try:
            current_shot_chart_info = shotchartdetail.ShotChartDetail(
                league_id='00',
                season_type_all_star='Regular Season',
                team_id=team_id,
                player_id=player_id,
                last_n_games=num_games)

        except requests.exceptions.ConnectionError:
            print("Request failed.")

        else:
            shots = current_shot_chart_info.shot_chart_detail.data['data']
            headers = current_shot_chart_info.shot_chart_detail.data['headers']
            shot_df = pandas.DataFrame(shots, columns=headers)
            return shot_df
Ejemplo n.º 4
0
def get_league_average_shot_data():
    shot_json = shotchartdetail.ShotChartDetail(
        team_id=0,
        player_id=0,
        context_measure_simple='FGA',
        season_nullable='2020-21',
        season_type_all_star='Regular Season')
    shot_data = json.loads(shot_json.get_json())
    la_relevant_data = shot_data['resultSets'][1]
    la_headers = la_relevant_data['headers']
    la_rows = la_relevant_data['rowSet']

    league_average_df = pd.DataFrame(la_rows)
    league_average_df.columns = la_headers

    league_average_zones_df = league_average_df.groupby('SHOT_ZONE_BASIC').agg(
        {
            'FGM': 'sum',
            'FGA': 'sum'
        })
    league_average_zones_df['fg%'] = (
        (league_average_zones_df['FGM'] / league_average_zones_df['FGA']) *
        100).round(2).astype(str) + '%'
    league_average_zones_df['freq%'] = (
        (league_average_zones_df['FGA'] / league_average_zones_df['FGA'].sum())
        * 100).round(2).astype(str) + '%'

    return league_average_zones_df
Ejemplo n.º 5
0
    def get_player_shotchartdetail(player_name, season_id, season_type):

        #player dictionary
        nba_players = players.get_players()
        player_dict = [
            player for player in nba_players
            if player['full_name'] == player_name
        ]

        if len(player_dict) == 0:
            return None, None

        #career dataframe
        career = playercareerstats.PlayerCareerStats(
            player_id=player_dict[0]['id'])
        career_df = json.loads(career.get_json())['resultSets'][0]['rowSet']

        #team id during the season
        team_ids = [
            season[3] for season in career_df if season[1] == season_id
        ]

        #st.write(career_df[0])
        shots = []
        for team_id in team_ids:
            shotchartlist = shotchartdetail.ShotChartDetail(
                team_id=int(team_id),
                player_id=int(player_dict[0]['id']),
                season_type_all_star=season_type,
                season_nullable=season_id,
                context_measure_simple="FGA").get_data_frames()
            shots.extend(shotchartlist)

        return shotchartlist[0], shotchartlist[1]
Ejemplo n.º 6
0
def create_shot_chart(pid, tid, name):
    career = shotchartdetail.ShotChartDetail(team_id=tid,
                                             player_id=pid,
                                             headers=headers)
    shots = career.get_data_frames()[0]

    cmap = plt.cm.get_cmap('gist_heat_r')

    joint_shot_chart = sns.jointplot(shots.LOC_X,
                                     shots.LOC_Y,
                                     stat_func=None,
                                     kind='hex',
                                     space=0,
                                     color=cmap(.2),
                                     cmap=cmap,
                                     gridsize=26,
                                     height=8)
    joint_shot_chart.fig.set_size_inches(12, 11)
    ax = joint_shot_chart.ax_joint
    fig = joint_shot_chart.fig

    ax.set_xlim(-235, 235)
    ax.set_ylim(295, -20)

    ax.set_xlabel('')
    ax.set_ylabel('')
    ax.tick_params(labelbottom='off', labelleft='off')

    ax.set_title('{} FGA, 2018-2019 Regular Season'.format(name), y=1.2)
    return create_court(ax, fig=fig)
Ejemplo n.º 7
0
def get_player_shots_data(player_full_name):
    pd.set_option("display.max_rows", None)
    nba_players = players.get_players()
    try:
        current_player = [
            player for player in nba_players
            if player["full_name"] == player_full_name
        ][0]
    except:
        return "Player not found."
    if not os.path.isdir(
            str(os.path.dirname(os.path.abspath(__file__))) + "/../data/" +
            str(current_player["id"]) + "/"):
        try:
            os.makedirs(str(os.path.dirname(os.path.abspath(__file__))) +
                        "/../data/" + str(current_player["id"]) + "/",
                        mode=0o777,
                        exist_ok=True)
        except OSError as error:
            print(error)
        player = commonplayerinfo.CommonPlayerInfo(
            player_id=str(current_player["id"]))
        player_df = player.get_data_frames()[0]
        player_df = player_df.loc[:, [
            "FIRST_NAME", "LAST_NAME", "COUNTRY", "HEIGHT", "WEIGHT", "JERSEY",
            "POSITION", "TEAM_ABBREVIATION", "FROM_YEAR", "TO_YEAR"
        ]]
        player_df.to_json(str(os.path.dirname(os.path.abspath(__file__))) +
                          '/../data/' + str(current_player["id"]) +
                          '/player_data.json',
                          orient='records')
        shots = shotchartdetail.ShotChartDetail(team_id=0,
                                                player_id=str(
                                                    current_player["id"]),
                                                context_measure_simple='FGA')
        shots_df = shots.get_data_frames()[0]
        shots_df = shots_df.loc[:, [
            "TEAM_NAME", "PERIOD", "MINUTES_REMAINING", "SECONDS_REMAINING",
            "ACTION_TYPE", "SHOT_TYPE", "SHOT_DISTANCE", "LOC_X", "LOC_Y",
            "SHOT_MADE_FLAG", "GAME_DATE", "HTM", "VTM"
        ]]
        shots_distances = []
        for i in range(shots_df.shape[0]):
            shots_distances += [
                (shots_df.at[i, "LOC_X"]**2 + shots_df.at[i, "LOC_Y"]**2)**0.5
                / 10
            ]
        shots_df.drop(["SHOT_DISTANCE"], axis=1, inplace=True)
        shots_df.insert(5, "SHOT_DISTANCE", shots_distances, True)
        shots_angles = []
        for i in range(shots_df.shape[0]):
            shots_angles += [shots_df.at[i, "LOC_Y"] / shots_df.at[i, "LOC_X"]]
        shots_df.insert(5, "SHOT_ANGLE", shots_angles, True)
        shots_df.drop(["LOC_X", "LOC_Y"], axis=1, inplace=True)
        shots_df.to_json(str(os.path.dirname(os.path.abspath(__file__))) +
                         '/../data/' + str(current_player["id"]) +
                         '/shots_data.json',
                         orient='records')
    return "Player found and data added to database."
Ejemplo n.º 8
0
def get_team_shotchartdetail(team_id, season_id, season_type):   
    # shotchartdetail endpoint
    shotchartlist = shotchartdetail.ShotChartDetail(team_id=int(team_id), 
                                                   player_id=0, 
                                                   season_type_all_star=season_type, 
                                                   season_nullable=season_id,
                                                   context_measure_simple="FGA").get_data_frames()
    
    return shotchartlist[0], shotchartlist[1]
Ejemplo n.º 9
0
def build_basic_shotchart(the_player, season, season_type):
    player_name = players.find_player_by_id(the_player).get('full_name')
    response = shotchartdetail.ShotChartDetail(
        team_id=0,
        player_id=the_player,
        season_nullable=season,
        season_type_all_star=season_type,
        context_measure_simple='FGA')
    df = response.get_data_frames()[0]
    made_shots = df[df['SHOT_MADE_FLAG'] == 1]
    missed_shots = df[df['SHOT_MADE_FLAG'] == 0]
    fig = go.Figure()
    fig.add_trace(
        go.Scatter(
            # made shots
            x=made_shots['LOC_X'],
            y=made_shots['LOC_Y'],
            mode='markers',
            name='Made Shot',
            hoverinfo='skip',
            marker=dict(
                size=5,
                cmax=40,
                cmin=-40,
                color="#008000",
            ),
        ))
    fig.add_trace(
        go.Scatter(
            # missed shots
            x=missed_shots['LOC_X'],
            y=missed_shots['LOC_Y'],
            mode='markers',
            name='Missed Shot',
            hoverinfo='skip',
            marker=dict(
                size=5,
                cmax=40,
                cmin=-40,
                color="#FF0000",
            ),
        ))
    draw_court(fig)
    fig.update_layout(title={
        'text': player_name + " , " + str(season),
        'y': 1,
        'x': 0.42,
        'xanchor': 'center',
        'yanchor': 'top'
    },
                      xaxis_title='Basic Shot Chart',
                      font=dict(family="Rockwell", size=15, color="#000000"),
                      dragmode=False)
    return fig
def get_player_shotchartdetail(player, season_id, season_type):
    # career df
    career_df = playercareerstats.PlayerCareerStats(
        player_id=player).get_data_frames()[0]

    # team id during the season
    team_id = career_df[career_df['SEASON_ID'] == season_id]['TEAM_ID']

    # shotchardtdetail endpoint
    shotchartlist = shotchartdetail.ShotChartDetail(
        team_id=int(team_id),
        player_id=int(player),
        season_type_all_star=season_type,
        season_nullable=season_id,
        context_measure_simple="FGA").get_data_frames()

    return shotchartlist[0], shotchartlist[1]
Ejemplo n.º 11
0
def get_team_shot_data(df, team_id, game_id):
    shot_json = shotchartdetail.ShotChartDetail(
        team_id=team_id,
        player_id=0,
        game_id_nullable=game_id,
        context_measure_simple='FGA',
        season_nullable='2020-21',
        season_type_all_star='Regular Season')

    shot_data = json.loads(shot_json.get_json())
    relevant_data = shot_data['resultSets'][0]
    headers = relevant_data['headers']
    rows = relevant_data['rowSet']

    shots_df = pd.DataFrame(rows)
    shots_df.columns = headers
    return shots_df
Ejemplo n.º 12
0
def scrape_shots_by_player_id(id):
    response = shotchartdetail.ShotChartDetail(
        team_id=0,
        player_id=id,
        season_nullable='2020-21',
        season_type_all_star='Regular Season')
    response_json = response.get_json()
    data = json.loads(response_json)
    shot_list = data["resultSets"][0]["rowSet"]
    for shot in shot_list:
        new_shot = Shot(nba_player_id=shot[3],
                        x=shot[17] + 250,
                        y=shot[18] + 60,
                        shot_zone=f'{shot[13]} - {shot[14]}',
                        shot_made_flag=shot[20])
        db.session.add(new_shot)
        db.session.commit()
        db.session.flush()
Ejemplo n.º 13
0
def scrape_shots_by_player_id(id):
    response = shotchartdetail.ShotChartDetail(
        team_id=0, player_id=id, season_nullable='2020-21',
        season_type_all_star='Regular Season', timeout=None
    )
    response_json = response.get_json()
    directory = 'app/player_shot_data'
    file = f"{id}.txt"
    if os.path.isdir(directory):
        path = os.path.join(directory, file)
        text_file = open(f"{path}", "w")
        text_file.write(f"{response_json}")
        text_file.close()
    else:
        directory = os.mkdir('app/player_shot_data')
        path = os.path.join(directory, file)
        text_file = open(f"{directory}/{id}.txt", "w")
        text_file.write(f"{response_json}")
        text_file.close()
Ejemplo n.º 14
0
def get_player_shotchartdetail(player_name, season_id, season_progress):

    # player dictionary
    nba_players = players.get_players()
    player_dict = [player for player in nba_players if player['full_name'] == player_name][0]

    # career dataframe
    career = playercareerstats.PlayerCareerStats(player_id=player_dict['id'])
    career_df = career.get_data_frames()[0]

    # team id during the season
    team_id = career_df[career_df['SEASON_ID'] == season_id]['TEAM_ID']

    # shotchartdetail endpoints
    shotchartlist = shotchartdetail.ShotChartDetail(team_id=int(team_id),
                                                    player_id=int(player_dict['id']),
                                                    season_type_all_star=season_progress,
                                                    season_nullable=season_id,
                                                    context_measure_simple='FGA').get_data_frames()

    return shotchartlist[0], shotchartlist[1]
Ejemplo n.º 15
0
    def getJSON(self):


        print('Gathering JSON . . .')
        playerJSON = shotchartdetail.ShotChartDetail(
            team_id = self.teamId,
            player_id = self.playerId,
            context_measure_simple = self.metric,
            season_nullable = self.season,
            season_type_all_star = self.type
        )

        playerData = json.loads(playerJSON.get_json())
        playerData = playerData['resultSets'][0]

        self.headers = playerData['headers']
        self.rows = playerData['rowSet']

        self.df = pd.DataFrame(self.rows)
        self.df.columns = self.headers

        self.chart()
Ejemplo n.º 16
0

# Get player ID
def get_player_id(first, last):
    first = first.lower()
    last = last.lower()
    for p in players:
        if p['firstName'].lower() == first and p['lastName'].lower() == last:
            return p['playerId']
    return -1


# JSON request for 2020 Kuz
shot_json = shotchartdetail.ShotChartDetail(
    team_id=get_team_id('los angeles lakers'),
    player_id=get_player_id('kyle', 'kuzma'),
    context_measure_simple='FGA',
    season_nullable='2019-20',
    season_type_all_star='Regular Season')

# Converting data into dictionary, getting relevant data
shot_data = json.loads(shot_json.get_json())
relevant_data = shot_data['resultSets'][0]
headers = relevant_data['headers']
rows = relevant_data['rowSet']

# Create pandas data frame
kuz_data = pd.DataFrame(rows)
kuz_data.columns = headers


# Drawing basketball court
Ejemplo n.º 17
0

#Clean and join with top 40
roles = df.iloc[1:]
roles = roles[['Name', 'Offensive Archetype', 'Defensive Role']]
final = pd.merge(fin, roles, how='left', left_on='Name', right_on='Name')


# In[ ]:


#Building Mitchell Robinson shot chart: web scrape through NBA stats API
from nba_api.stats.endpoints import shotchartdetail
import simplejson as json

response = shotchartdetail.ShotChartDetail(team_id=0,player_id=1629011,season_nullable='2019-20',season_type_all_star='Regular Season')
content = json.loads(response.get_json())


# In[ ]:


#Set JSON as DataFrame
results = content['resultSets'][0]
headers = results['headers']
rows = results['rowSet']
mitch = pd.DataFrame(rows)
mitch.columns = headers

#Write to csv file
mitch.to_csv('~/Desktop/mitch.csv', index=False)
Ejemplo n.º 18
0
from nba_api.stats.endpoints import shotchartdetail
import json
import requests
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle, Arc
from matplotlib.offsetbox import OffsetImage
import urllib.request

#find the id matching team you want at https://github.com/bttmly/nba/blob/master/data/teams.json
#find the id of player on nba.stats.com

response = shotchartdetail.ShotChartDetail(
    team_id=1610612749,
    player_id=203507,
    season_nullable='2020-21',
    season_type_all_star='Regular Season')

content = json.loads(response.get_json())
#transform content into dataframe
results = content['resultSets'][0]
headers = results['headers']
rows = results['rowSet']
df = pd.DataFrame(rows)
df.columns = headers

#write to csv file
df.to_csv("giannis.csv", index=False)

sns.set_style("white")
Ejemplo n.º 19
0
from nba_api.stats.endpoints import shotchartdetail
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os
from court import draw_court

pd.set_option('display.max_rows', None)
player = shotchartdetail.ShotChartDetail(player_id='1628366',
                                         team_id='1610612740')
table = player.get_data_frames()[0]
#print(table.LOC_X)

sns.set_style("white")
sns.set_color_codes()
# plt.figure(figsize=(12,11))
# draw_court(outer_lines=True)
# plt.scatter(table.LOC_X, table.LOC_Y,s=10)
# plt.xlim(300,-300)
# plt.ylim(-100,500)
# plt.show()

cmap = plt.cm.gist_heat_r
joint_chart = sns.jointplot(table.LOC_X,
                            table.LOC_Y,
                            stat_func=None,
                            kind='hex',
                            space=0,
                            color=cmap(0.2),
                            cmap=cmap)
joint_chart.fig.set_size_inches(12, 11)
Ejemplo n.º 20
0
restricted_list = []
restricted_player_list = []
paint_list = []
paint_player_list = []

for player_roster in roster:

    name = player_roster
    #print('\n\n', name, '\n\n')

    playerid = get_playerid(name)

    response = shotchartdetail.ShotChartDetail(
        team_id=0,
        player_id=playerid,
        context_measure_simple='FGA',  # FGA/FG3A are made & missed
        #season_type_all_star = 'Regular Season',
        season_nullable='2020-21'
        #period = '4',
    )

    content = json.loads(response.get_json())

    # transform contents into dataframe
    results = content['resultSets'][0]
    headers = results['headers']
    rows = results['rowSet']
    fg_attempt = pd.DataFrame(rows)
    fg_attempt.columns = headers

    # all field goal attempts
    fg_attempt['LOC_X'] = -1 * fg_attempt['LOC_X']
Ejemplo n.º 21
0
def make_chart(request):
    if request.method == 'GET':
        date = datetime.datetime.today().strftime('%m-%d-%Y')
        response = {}
        plt.clf()
        teamID = '0'
        theme = request.GET['theme']
        #type = request.GET['type']
        seasonType = request.GET['seasonType']
        playerID = request.GET['playerID']
        season = request.GET['season']
        #gameID = request.GET['gameID']
        info = shotchartdetail.ShotChartDetail(
            player_id=playerID,
            team_id=teamID,
            season_type_all_star=seasonType,
            season_nullable=season,
            context_measure_simple='FG_PCT',
        )
        info = info.get_json()
        shotChartData = json.loads(info)
        shots = shotChartData['resultSets'][0]['rowSet']
        shotHeaders = shotChartData['resultSets'][0]['headers']
        avg = shotChartData['resultSets'][1]['rowSet']
        avgHeaders = shotChartData['resultSets'][1]['headers']

        if (shots):
            shot_df = pd.DataFrame(shots, columns=shotHeaders)
            la_df = pd.DataFrame(avg, columns=avgHeaders)

            fig = plt.figure(figsize=(12, 10))

            plot = nba.plot.grantland_shotchart(shotchart=shot_df,
                                                leagueaverage=la_df,
                                                season=season,
                                                seasonType=seasonType)
            plt.text(0,
                     -8,
                     'data by: stats.nba.com ' + date,
                     fontsize=7,
                     horizontalalignment='center',
                     verticalalignment='center')
            plt.text(0,
                     -9,
                     'chart by: ballviz.com',
                     fontsize=7,
                     horizontalalignment='center',
                     verticalalignment='center')

            stringIObytes = io.BytesIO()
            plt.savefig(stringIObytes,
                        format='png',
                        bbox_inches='tight',
                        pad_inches=0.1,
                        dpi=300)
            stringIObytes.seek(0)
            base64_data = base64.b64encode(stringIObytes.read())

            base64_data = base64_data.decode("utf8")

            response = {'dataFound': True, 'imageData': base64_data}

        else:
            response = {'dataFound': False, 'imageData': ''}

        response = json.dumps(response)
        return HttpResponse(response)  # Sending a success response
    else:
        return HttpResponse("Request method is not a GET")
Ejemplo n.º 22
0
    logo_team = 'MIL'
    logo_url = "https://d2p3bygnnzw9w3.cloudfront.net/req/202001161/tlogo/bbr/" + logo_team + ".png"
    team_pic = urllib.request.urlretrieve(logo_url)
    team_logo = plt.imread(team_pic[0])


def get_player_id(first, last):
    for player in players:
        if player['firstName'] == first and player['lastName'] == last:
            return player['playerId']
    return -1


shot_json = shotchartdetail.ShotChartDetail(
    team_id=get_team_id(f'{selected_team}'),
    player_id=get_player_id(f'{name}', f'{lastname}'),
    context_measure_simple='PTS',
    season_nullable='2018-19',
    season_type_all_star='Regular Season')

shot_data = json.loads(shot_json.get_json())

relevant_data = shot_data['resultSets'][0]
headers = relevant_data['headers']
shots = relevant_data['rowSet']

# Create pandas DataFrame
player_data = pd.DataFrame(shots)
player_data.columns = headers


def create_court(ax, color):
Ejemplo n.º 23
0
import numpy as np
import pandas as pd
from matplotlib import pyplot
import json
# import nba_api
from nba_api.stats.endpoints import shotchartdetail
from nba_api.stats.static import teams, players

l = players.find_players_by_first_name("LeBron")
print(l)
z = teams.find_teams_by_nickname("LAL")
print(z)


res = shotchartdetail.ShotChartDetail(0, 2544)
content = json.loads(res.get_json())

results = content['resultSets'][0]
headers = results['headers']
rows = results['rowSet']
df = pd.DataFrame(rows)
df.columns = headers

df.to_csv("f.csv", index=False)



custom_headers = {
    'Host': 'stats.nba.com',
    'Connection': 'keep-alive',
    'Cache-Control': 'max-age=0',
Ejemplo n.º 24
0
            'SHOT_ZONE_BASIC','SHOT_ZONE_AREA','SHOT_ZONE_RANGE','SHOT_DISTANCE',
            'LOC_X','LOC_Y','SHOT_MADE_FLAG','HTM','VTM']

First = True

# For each season
for Season in Seasons:
    # For each team
    for ID in TeamIDs:
        # We'll grab the shot chart data for the team, extract the relevant
        # columns from the dataframe, then append the most recently retrieved
        # data onto the running dataframe.
        if First:
            First = False
            NBAShots = shotchartdetail.ShotChartDetail(team_id = ID,
                            player_id = 0,
                            season_nullable = Season,
                            context_measure_simple = 'FGA')
            if len(NBAShots.get_data_frames()[0]) != 0:
                NBAShots_DF = [df for df in NBAShots.get_data_frames() if df['GRID_TYPE'][0] == 'Shot Chart Detail'][0][Columns].copy()
                NBAShots_DF['Season'] = Season
                del NBAShots
            else:
                First = True
        else:
            Temp = shotchartdetail.ShotChartDetail(team_id = ID,
                            player_id = 0,
                            season_nullable = Season,
                            context_measure_simple = 'FGA')
            if len(Temp.get_data_frames()[0]) != 0:
                Temp_DF = [df for df in Temp.get_data_frames() if df['GRID_TYPE'][0] == 'Shot Chart Detail'][0][Columns].copy()
                Temp_DF['Season'] = Season
Ejemplo n.º 25
0
import numpy as np
import pandas as pd 
import json

#import nba api
from nba_api.stats.endpoints import leaguegamefinder
from nba_api.stats.endpoints import shotchartdetail
from nba_api.stats.static import teams, players

nba_teams = teams.get_teams()
gsw = [team for team in nba_teams if team['abbreviation'] == 'GSW'][0]
gsw_id = gsw['id']

gamefinder = leaguegamefinder.LeagueGameFinder(team_id_nullable=gsw_id)
games = gamefinder.get_data_frames()[0]
games.head()

gsw_shotchart = shotchartdetail.ShotChartDetail(team_id=gsw_id, player_id=0, season_nullable="2017-18")
gsw_shotchart_json = json.loads(gsw_shotchart.get_json())

results = gsw_shotchart_json['resultSets'][0]
headers = results['headers']
rows = results['rowSet']
df = pd.DataFrame(rows)
df.columns = headers
df.to_csv("gsw.csv", index=None)
Ejemplo n.º 26
0
def fg_dist(player_or_teams, plot_flag = 0, fg_attempt_filter = 100):
	
	current_players_id_list, current_players_list = CommonAllPlayers_func.create_currentplayers_lists(teams = player_or_teams)

	if current_players_list == []: 

		current_players_list = [player_or_teams]

	players_filtered_list = []
	furthest_makes_list = []
	avg_makes_list = []
	fg_make_shotdist_list = []

	# fig_box, ax_box = plt.subplots()

	for name in current_players_list:

		playerid = CommonAllPlayers_func.get_playerid(name)

		response = shotchartdetail.ShotChartDetail(
		team_id = 0, 
		player_id = playerid,
		context_measure_simple = 'FGA', # FGA/FG3A are made & missed
		#season_type_all_star = 'Regular Season',
		season_nullable = '2020-21'
		#period = '4',
		)

		time.sleep(0.1)

		content = json.loads(response.get_json())

		# transform contents into dataframe
		results = content['resultSets'][0]
		headers = results['headers']
		rows = results['rowSet']
		fg_attempt = pd.DataFrame(rows)

		if fg_attempt.empty == False and fg_attempt.shape[0] >= fg_attempt_filter:

			fg_attempt.columns = headers

			# all field goal attempts
			fg_attempt['LOC_X'] = -1 * fg_attempt['LOC_X']
			fg_attempt['shot_dist'] = ((fg_attempt['LOC_X'] ** 2 + fg_attempt['LOC_Y'] ** 2) ** 0.5) / (5 / 6 * 12)

			# all successful field goals
			fg_make = fg_attempt.loc[fg_attempt['SHOT_MADE_FLAG'] == 1]
			fg_make_shotdist_list.append(fg_make['shot_dist'].tolist())

			# all unsuccessful field goals
			fg_miss = fg_attempt.loc[fg_attempt['SHOT_MADE_FLAG'] == 0]

			furthest_make_ft = fg_make['shot_dist'].max() #/ (5 / 6 * 12)
			avg_make_ft = fg_make['shot_dist'].mean() #/ (5 / 6 * 12)

			players_filtered_list.append(name)
			furthest_makes_list.append(furthest_make_ft)
			avg_makes_list.append(avg_make_ft)

			# if plot_flag == 1:

			# 	plt.boxplot(fg_make['shot_dist'])
			# 	plt.pause(0.05)

		else:

			continue

	if plot_flag == 1:

		fig_box, ax_box = plt.subplots()

		plt.boxplot(x = fg_make_shotdist_list, whis = (0, 100))

		corner3_dist = 22
		arc3_dist = 23.75
		#plt.axhline(corner3_dist)
		plt.axhline(arc3_dist)

		ax_box.set_xticklabels(players_filtered_list)
		plt.xticks(rotation = 20)
		plt.title('FG Distance [ft], ' + player_or_teams)

		#ax_box.legend('Arc 3 Point Line')

		plt.show()

	shot_range_df = pd.DataFrame(list(zip(players_filtered_list, furthest_makes_list, avg_makes_list)), 
	               columns = ['Player', 'Furthest FG', 'Average Distance FG']) 

	shot_range_df.sort_values(by = ['Average Distance FG'], inplace = True)

	# if plot_flag == 1:

	# 	fig_bar, ax_bar = plt.subplots()

	# 	#plt.bar(shot_range_df['Player'], shot_range_df['Average Distance FG'])
	# 	plt.boxplot(shot_range_df['Average Distance FG'])

	# 	plt.show()

	return shot_range_df
Ejemplo n.º 27
0
def compute_league_averages(zone, x):
    area = zone[0]
    # print("The area is " + area)
    dict = {
        '(R)': 'Right Side(R)',
        '(C)': 'Center(C)',
        '(L)': 'Left Side(L)',
        '(RC)': 'Right Side Center(RC)',
        '(LC)': 'Left Side Center(LC)'
    }
    side = dict[zone[1]]

    filenames = {
        ('Right Corner 3', 'Right Side(R)'): 'rightcorner3.txt',
        ('Left Corner 3', 'Left Side(L)'): 'leftcorner3.txt',
        ('Mid-Range', 'Left Side(L)'): 'midrangeleft.txt',
        ('Mid-Range', 'Left Side Center(LC)'): 'midrangeleftcenter.txt',
        ('Mid-Range', 'Center(C)'): 'midrangecenter.txt',
        ('Mid-Range', 'Right Side Center(RC)'): 'midrangerightcenter.txt',
        ('Mid-Range', 'Right Side(R)'): 'midrangeright.txt',
        ('Above the Break 3', 'Left Side Center(LC)'):
        'abovethebreak3leftcenter.txt',
        ('Above the Break 3', 'Center(C)'): 'abovethebreak3center.txt',
        ('Above the Break 3', 'Right Side Center(RC)'):
        'abovethebreak3rightcenter.txt',
        ('Restricted Area', 'Center(C)'): 'restrictedareacenter.txt',
        ('In The Paint (Non-RA)', 'Right Side(R)'): 'inthepaintright.txt',
        ('In The Paint (Non-RA)', 'Center(C)'): 'inthepaintcenter.txt',
        ('In The Paint (Non-RA)', 'Left Side(L)'): 'inthepaintleft.txt'
    }
    input_list = [area, side]
    filename = filenames[tuple(input_list)]
    # print("The side is " + side)
    total_makes = 0
    total_shots = 0
    for player in players[x:x + 1]:
        # print(player[''])
        team_id = player['teamId']
        player_id = player['playerId']
        context_measure_simple = 'FGA'
        season_nullable = '2020-21'
        season_type_all_start = 'Regular Season'
        # print("TEAM ID: " + str(team_id))
        # print("PLAYER ID: " + str(player_id))
        # print("CONTEXT MEASURE SIMPLE: " + context_measure_simple)
        # print("SEASON NUMBER: " + season_nullable)
        # print("SEASON TYPE: " + season_type_all_start)
        player_shot_json = shotchartdetail.ShotChartDetail(
            team_id=team_id,
            player_id=player_id,
            context_measure_simple=context_measure_simple,
            season_nullable=season_nullable,
            season_type_all_star=season_type_all_start)
        player_shot_data = json.loads(player_shot_json.get_json())
        player_relevant_data = player_shot_data['resultSets'][0]
        headers = player_relevant_data['headers']
        rows = player_relevant_data['rowSet']

        player_data = pd.DataFrame(rows)
        # print(player_data.head())
        # print(player_data.columns)
        if (player_data.shape[0] != 0):
            player_data.columns = headers
            # print(player_data.head())
            # print(player_data.columns)
            #player_data.to_csv('lameloballbefore.csv', index=False)
            player_data = player_data.loc[
                (player_data['SHOT_ZONE_BASIC'] == area)
                & (player_data['SHOT_ZONE_AREA'] == side)]
            #player_data.to_csv('lameloball.csv', index=False)
            total_shots += player_data.shape[0]
            total_makes += player_data["SHOT_MADE_FLAG"].sum()

    file = open(filename, 'a')
    res = str(total_makes) + ' ' + str(total_shots) + '\n'
    file.write(res)
    file.close()
Ejemplo n.º 28
0
from nba_api.stats.endpoints import shotchartdetail
import pandas as pd
import json
import pandas as pd
import plotly.graph_objs as go
from kawhi_shot import court_shapes

response = shotchartdetail.ShotChartDetail(
        team_id=0,
        player_id=201142,
        season_nullable='2020-21',
        season_type_all_star='Regular Season'
)
kd_data = json.loads(response.get_json())

# transform the JSON into Pandas dataframe
results = kd_data['resultSets'][0]
headers = results['headers']
rows = results['rowSet']
kd_df = pd.DataFrame(rows)
kd_df.columns = headers

# write new dataframe to csv file
kd_df.to_csv(r'/home/aram/Downloads/kd.csv', index=False)

kd_df = pd.read_csv('/home/aram/Downloads/kd.csv', encoding='Latin-1')

trace_shot = go.Scatter(
        x = kd_df['LOC_X'],
        y = kd_df['LOC_Y'],
        mode = 'markers',
Ejemplo n.º 29
0
def player_shotchart(player, season = 0, fg_type = 'FGA', season_type = 'Regular Season', period = 0, plot_flag = 1, twitter_flag = 1, bin_edge_count = 15, plot_fg = 'all', savefig_flag = 0):

	# start timer
	start_time = time.time()

	# import pickled dictionaries
	league_make_bybin = pickle.load(open('playermake_2003-04.pkl', 'rb'))
	league_attempt_bybin = pickle.load(open('playerattempt_2003-04.pkl', 'rb'))
	
	league_make_sum_bybin = np.zeros([bin_edge_count, bin_edge_count])
	league_attempt_sum_bybin = np.zeros([bin_edge_count, bin_edge_count])

	for key in league_make_bybin:

		league_make_sum_bybin = np.add(league_make_sum_bybin, league_make_bybin[key])
		league_attempt_sum_bybin = np.add(league_attempt_sum_bybin, league_attempt_bybin[key])

	league_avg_eff_bybin = np.divide(league_make_sum_bybin, league_attempt_sum_bybin)

	# print title
	print('--------------------\n', player[0], '\n', season, '\n--------------------', '\n\n', sep = '')

	# get player ID from name input
	playerid = get_playerid(player)

	# retrieve data
	response = shotchartdetail.ShotChartDetail(
		context_measure_simple = 'FGA',
		period = period,
		player_id = playerid,
		season_type_all_star = season_type,
		team_id = 0, 
		season_nullable = season)

	content = json.loads(response.get_json())

	# transform contents into dataframe
	results = content['resultSets'][0]
	headers = results['headers']
	rows = results['rowSet']
	fg_attempt = pd.DataFrame(rows)
	fg_attempt.columns = headers

	# mirror x, NBA's data is reversed
	fg_attempt['LOC_X'] = -1 * fg_attempt['LOC_X']

	# calculate distance of fg
	fg_attempt['shot_dist'] = (fg_attempt['LOC_X'] ** 2 + fg_attempt['LOC_Y'] ** 2) ** 0.5

	# create identifier for shot zones
	fg_attempt['shot_id'] = fg_attempt['SHOT_ZONE_BASIC'] + fg_attempt['SHOT_ZONE_AREA'] + fg_attempt['SHOT_ZONE_RANGE']

	# all successful field goals
	fg_make = fg_attempt.loc[fg_attempt['SHOT_MADE_FLAG'] == 1]

	# all unsuccessful field goals
	fg_miss = fg_attempt.loc[fg_attempt['SHOT_MADE_FLAG'] == 0]

	# successful field goal statistics
	furthest_ft = round(fg_make['shot_dist'].max() / (5 / 6 * 12), 1)
	avg_ft = round(fg_make['shot_dist'].mean() / (5 / 6 * 12), 1)
	std_ft = round(fg_make['shot_dist'].std() / (5 / 6 * 12), 1)
	var_ft = round(fg_make['shot_dist'].var() / (5 / 6 * 12), 1)

	# create summary table of stats
	stats_headers = [['Furthest', 'Average', 'Standard Deviation', 'Variance'], [furthest_ft, avg_ft, std_ft, var_ft]]
	print('SHOT DISTANCE:\n', tabulate(stats_headers, headers = 'firstrow', tablefmt = 'fancy_grid'), sep = '')

	# categorize field goals by NBA-defined zones
	make_dict, miss_dict = ShotChartZones_Func.create_dict_shotzones_df(fg_make, fg_miss)

	print('\n\n', 'MADE FIELD GOALS:\n', fg_make)

	# shotid_make_gb = fg_attempt.groupby(['shot_id'])['SHOT_MADE_FLAG'].sum()
	# shotid_attempt_gb = fg_attempt.groupby(['shot_id'])['SHOT_ATTEMPTED_FLAG'].sum()
	# player_eff_byzone = shotid_make_gb / shotid_attempt_gb

	# create plots
	if plot_flag == 1:

		# create figures with shot charts
		fig_court1, ax_court1 = plt.subplots()

		ax, x_min, x_max, y_min, y_max = NBA_court_zones.draw_NBA_court(
			color = 'white',
			lw = 2,
			zones_flag = 0)

		if twitter_flag == 1:

			tweet.add_twitterhandle(fig_court1)

		fig_court2, ax_court2 = plt.subplots()
		
		ax, x_min, x_max, y_min, y_max = NBA_court_zones.draw_NBA_court(
			color = 'white',
			lw = 2,
			zones_flag = 0)

		if twitter_flag == 1:

			tweet.add_twitterhandle(fig_court2)

		fig_court3, ax_court3 = plt.subplots()
		
		ax, x_min, x_max, y_min, y_max = NBA_court_zones.draw_NBA_court(
			color = 'white',
			lw = 2,
			zones_flag = 0)

		if twitter_flag == 1:

			tweet.add_twitterhandle(fig_court3)

		# create dataframes of makes, misses, and all
		fg_make_loc = fg_make[['LOC_X', 'LOC_Y']].copy().reset_index(drop = True)
		fg_miss_loc = fg_miss[['LOC_X', 'LOC_Y']].copy().reset_index(drop = True)
		fg_attempt_loc = fg_attempt[['LOC_X', 'LOC_Y']].copy().reset_index(drop = True)

		# bin succcessful field goals by location
		court_bin_make, xedges_make, yedges_make, binnumber_make = stats.binned_statistic_2d(
			x = fg_make_loc['LOC_X'],
			y = fg_make_loc['LOC_Y'],
			values = None,
			statistic = 'count',
			bins = bin_edge_count,
			range = ((x_min, x_max), (y_min, y_max))
			)

		# bin all field goals by location
		court_bin_attempt, xedges_attempt, yedges_attempt, binnumber_attempt = stats.binned_statistic_2d(
			x = fg_attempt_loc['LOC_X'],
			y = fg_attempt_loc['LOC_Y'],
			values = None,
			statistic = 'count',
			bins = bin_edge_count,
			range = ((x_min, x_max), (y_min, y_max))
			)

		court_bin_make = court_bin_make.flatten()
		court_bin_attempt = court_bin_attempt.flatten()
		fga_filter = np.sort(court_bin_attempt)[-bin_edge_count]
		commonbins = np.where(court_bin_attempt < fga_filter, 0, court_bin_attempt)

		center_x = []
		center_y = []

		# need to find center of each bin to then plot a shape at
		for i in range(0, len(xedges_make) - 1):

			center_x.append((xedges_make[i] + xedges_make[i + 1]) / 2)
			center_y.append((yedges_make[i] + yedges_make[i + 1]) / 2)


		# count of all field goals in each bin
		fg_eff = commonbins

		# loop through bins
		for bin_i in range(0, len(fg_eff)):

			# divide successful field goal count by attempted field goal count for each bin
			if commonbins[bin_i] == 0:

				fg_eff[bin_i] = 2.01

			else:

				fg_eff[bin_i] = court_bin_make[bin_i] / commonbins[bin_i]

		fg_eff = np.reshape(fg_eff, (bin_edge_count, bin_edge_count))
		fg_eff_diff = np.subtract(fg_eff, league_avg_eff_bybin)
		# print(fg_eff_diff)
		fg_eff_masked = np.ma.masked_greater(fg_eff, 1)
		fg_eff_masked_lgavg = np.ma.masked_greater(fg_eff_diff, 1)
		fg_eff_masked_lgavg = np.ma.masked_invalid(fg_eff_masked_lgavg)

		# select color map and quantity of colors
		cmap_discrete = plt.cm.get_cmap('bwr', 10)

		# mesh grid based on bin edges
		xedges, yedges = np.meshgrid(xedges_make, yedges_make)
		plot_eff2 = ax_court2.pcolormesh(xedges, yedges, fg_eff_masked.T, cmap = cmap_discrete)
		cbar2 = plt.colorbar(plot_eff2, ax = ax_court2)

		xcenters, ycenters = np.meshgrid(center_x, center_y)
		attempts_reshaped = np.reshape(court_bin_attempt, (bin_edge_count, bin_edge_count)).T

		np.nan_to_num(fg_eff_diff, copy = False, nan = 1.01)

		cmap_bounds = [-0.1, -0.05, 0.05, 0.1]
		cmap_colors = ['steelblue', 'lightblue', 'grey', 'orange', 'red']
		cmap_reps = ['-0.1', '-0.05', '0.0', '0.05', '0.1']

		fg_eff_diff_cmap = fg_eff_diff
		fg_eff_diff_cmap = np.where(fg_eff_diff <= cmap_bounds[0], cmap_bounds[0], fg_eff_diff_cmap)
		fg_eff_diff_cmap = np.where((fg_eff_diff <= cmap_bounds[1]) & (fg_eff_diff > cmap_bounds[0]), cmap_bounds[1], fg_eff_diff_cmap)
		fg_eff_diff_cmap = np.where((fg_eff_diff < cmap_bounds[2]) & (fg_eff_diff > cmap_bounds[1]), 0.0, fg_eff_diff_cmap)
		fg_eff_diff_cmap = np.where((fg_eff_diff < cmap_bounds[3]) & (fg_eff_diff >= cmap_bounds[2]), cmap_bounds[2], fg_eff_diff_cmap)
		fg_eff_diff_cmap = np.where((fg_eff_diff_cmap >= cmap_bounds[3]) & (fg_eff_diff_cmap <= 1), cmap_bounds[3], fg_eff_diff_cmap)

		fg_eff_diff_cmap_str = fg_eff_diff_cmap.astype(str)
		fg_eff_diff_cmap_str = np.where(fg_eff_diff_cmap_str == cmap_reps[0], cmap_colors[0], fg_eff_diff_cmap_str)
		fg_eff_diff_cmap_str = np.where(fg_eff_diff_cmap_str == cmap_reps[1], cmap_colors[1], fg_eff_diff_cmap_str)
		fg_eff_diff_cmap_str = np.where(fg_eff_diff_cmap_str == cmap_reps[2], cmap_colors[2], fg_eff_diff_cmap_str)
		fg_eff_diff_cmap_str = np.where(fg_eff_diff_cmap_str == cmap_reps[3], cmap_colors[3], fg_eff_diff_cmap_str)
		fg_eff_diff_cmap_str = np.where(fg_eff_diff_cmap_str == cmap_reps[4], cmap_colors[4], fg_eff_diff_cmap_str)
		fg_eff_diff_cmap_str = fg_eff_diff_cmap_str.T
	
		for column in range(0, bin_edge_count):

			for row in range(0, bin_edge_count):

				if fg_eff.T[row, column] > 1:

					pass

				else:

					ax_court3.scatter(x = xcenters[row, column],
						y = ycenters[row, column],
						s = 10 * attempts_reshaped[row, column],
						c = fg_eff_diff_cmap_str[row, column],
						marker = 'h')

		if plot_fg == 'makes':

			# plot successful field goals
			ax_court1.scatter(fg_make['LOC_X'], fg_make['LOC_Y'], c = 'green', marker = 'o', alpha = 1, s = 10)

		elif plot_fg == 'misses':

			# plot unsuccessful field goals
			ax_court1.scatter(fg_miss['LOC_X'], fg_miss['LOC_Y'], c = 'red', marker = 'x', alpha = 0.8, s = 10)

		else:

			# plot all field goals
			ax_court1.scatter(fg_make['LOC_X'], fg_make['LOC_Y'], c = 'green', marker = 'o', alpha = 1, s = 10)
			ax_court1.scatter(fg_miss['LOC_X'], fg_miss['LOC_Y'], c = 'red', marker = 'x', alpha = 0.6, s = 10)

		# set titles
		ax_court1.set(title = player[0] + ', ' + season)
		ax_court2.set(title = player[0] + ', FG%, ' + season)
		ax_court3.set(title = player[0] + ', ' + season)

		# set background colors
		ax_court1.set_facecolor('black')
		ax_court2.set_facecolor('black')
		ax_court3.set_facecolor('black')

		# remove axes ticks
		ax_court1.set_xticks([])
		ax_court1.set_yticks([])
		ax_court2.set_xticks([])
		ax_court2.set_yticks([])
		ax_court3.set_xticks([])
		ax_court3.set_yticks([])

		add_hexlegend.add_legend_shotchart(ax_court3)

		if savefig_flag == 1:

			# specify file type
			image_type = '.jpeg'

			# specify file name
			fig1_name = player[0] + '_' + season + '_shotchart' + image_type
			fig2_name = player[0] + '_' + season + '_shotchartEff' + image_type
			fig3_name = player[0] + '_' + season + '_shotchartEff2' + image_type
			fig_court3.set_size_inches(10, 8)

			# save file
			fig_court1.savefig(fig1_name, dpi = 1000, bbox_inches = 'tight')
			fig_court2.savefig(fig2_name, dpi = 1000, bbox_inches = 'tight')
			fig_court3.savefig(fig3_name, dpi = 500, bbox_inches = 'tight')



		print('\n--- %s seconds ---\n' % (time.time() - start_time))

		plt.show()

	return fg_make
Ejemplo n.º 30
0
def AnotacionesJugador(p_id, season, gametype):
    def draw_court(ax=None, color='black', lw=2, outer_lines=False):
        # If an axes object isn't provided to plot onto, just get current one
        if ax is None:
            ax = plt.gca()

        # Create the various parts of an NBA basketball court

        # Create the basketball hoop
        # Diameter of a hoop is 18" so it has a radius of 9", which is a value
        # 7.5 in our coordinate system
        hoop = Circle((0, 0),
                      radius=7.5,
                      linewidth=lw,
                      color=color,
                      fill=False)

        # Create backboard
        backboard = Rectangle((-30, -7.5), 60, -1, linewidth=lw, color=color)

        # The paint
        # Create the outer box 0f the paint, width=16ft, height=19ft
        outer_box = Rectangle((-80, -47.5),
                              160,
                              190,
                              linewidth=lw,
                              color=color,
                              fill=False)
        # Create the inner box of the paint, widt=12ft, height=19ft
        inner_box = Rectangle((-60, -47.5),
                              120,
                              190,
                              linewidth=lw,
                              color=color,
                              fill=False)

        # Create free throw top arc
        top_free_throw = Arc((0, 142.5),
                             120,
                             120,
                             theta1=0,
                             theta2=180,
                             linewidth=lw,
                             color=color,
                             fill=False)
        # Create free throw bottom arc
        bottom_free_throw = Arc((0, 142.5),
                                120,
                                120,
                                theta1=180,
                                theta2=0,
                                linewidth=lw,
                                color=color,
                                linestyle='dashed')
        # Restricted Zone, it is an arc with 4ft radius from center of the hoop
        restricted = Arc((0, 0),
                         80,
                         80,
                         theta1=0,
                         theta2=180,
                         linewidth=lw,
                         color=color)

        # Three point line
        # Create the side 3pt lines, they are 14ft long before they begin to arc
        corner_three_a = Rectangle((-220, -47.5),
                                   0,
                                   140,
                                   linewidth=lw,
                                   color=color)
        corner_three_b = Rectangle((220, -47.5),
                                   0,
                                   140,
                                   linewidth=lw,
                                   color=color)
        # 3pt arc - center of arc will be the hoop, arc is 23'9" away from hoop
        # I just played around with the theta values until they lined up with the
        # threes
        three_arc = Arc((0, 0),
                        475,
                        475,
                        theta1=22,
                        theta2=158,
                        linewidth=lw,
                        color=color)

        # Center Court
        center_outer_arc = Arc((0, 422.5),
                               120,
                               120,
                               theta1=180,
                               theta2=0,
                               linewidth=lw,
                               color=color)
        center_inner_arc = Arc((0, 422.5),
                               40,
                               40,
                               theta1=180,
                               theta2=0,
                               linewidth=lw,
                               color=color)

        # List of the court elements to be plotted onto the axes
        court_elements = [
            hoop, backboard, outer_box, inner_box, top_free_throw,
            bottom_free_throw, restricted, corner_three_a, corner_three_b,
            three_arc, center_outer_arc, center_inner_arc
        ]

        if outer_lines:
            # Draw the half court line, baseline and side out bound lines
            outer_lines = Rectangle((-250, -47.5),
                                    500,
                                    470,
                                    linewidth=lw,
                                    color=color,
                                    fill=False)
            court_elements.append(outer_lines)

        # Add the court elements onto the axes
        for element in court_elements:
            ax.add_patch(element)

        return ax

    response = shotchartdetail.ShotChartDetail(team_id=0,
                                               player_id=p_id,
                                               season_nullable=season,
                                               season_type_all_star=gametype)

    content = json.loads(response.get_json())

    # transform contents into dataframe
    results = content['resultSets'][0]
    headers = results['headers']
    rows = results['rowSet']
    shot_df = pd.DataFrame(rows)
    shot_df.columns = headers

    ssl._create_default_https_context = ssl._create_unverified_context
    # we pass in the link to the image as the 1st argument
    pic = urllib.request.urlretrieve(
        f"http://stats.nba.com/media/players/230x185/{p_id}.png",
        f"{p_id}.png")

    # urlretrieve returns a tuple with our image as the first
    # element and imread reads in the image as a
    # mutlidimensional numpy array so matplotlib can plot it
    harden_pic = plt.imread(pic[0])

    # get our colormap for the main kde plot
    # Note we can extract a color from cmap to use for
    # the plots that lie on the side and top axes
    cmap = plt.cm.gist_heat_r

    # n_levels sets the number of contour lines for the main kde plot
    joint_shot_chart = sns.jointplot(shot_df.LOC_X,
                                     shot_df.LOC_Y,
                                     stat_func=None,
                                     kind='kde',
                                     space=0,
                                     color=cmap(0.1),
                                     cmap=cmap,
                                     n_levels=50)

    joint_shot_chart.fig.set_size_inches(12, 11)

    # A joint plot has 3 Axes, the first one called ax_joint,
    # It's the one we want to draw our court onto and adjust some other settings
    ax = joint_shot_chart.ax_joint
    draw_court(ax, color="gray", lw=1)

    # Adjust the axis limits and orientation of the plot in order
    # to plot half court, with the hoop by the top of the plot
    ax.set_xlim(-250, 250)
    ax.set_ylim(422.5, -47.5)

    # Get rid of axis labels and tick marks
    ax.set_xlabel('')
    ax.set_ylabel('')
    ax.tick_params(labelbottom='off', labelleft='off')

    # Add Data Scource and Author
    ax.text(-250, 445, 'Data Source: stats.nba.com', fontsize=12)

    # Add Harden's image to the top right
    # First create our OffSetImage by passing in our image
    # and set the zoom level to make the image small enough
    # to fit on our plot
    img = OffsetImage(harden_pic, zoom=0.6)
    # Pass in a tuple of x,y coordinates to set_offset
    # to place the plot where you want, I just played around
    # with the values until I found a spot where I wanted
    # the image to be
    img.set_offset((625, 621))
    # add the image
    ax.add_artist(img)

    plt.show()