nbastatpy 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nbastatpy might be problematic. Click here for more details.
- nbastatpy/__init__.py +1 -0
- nbastatpy/game.py +153 -0
- nbastatpy/player.py +507 -0
- nbastatpy/season.py +578 -0
- nbastatpy/team.py +436 -0
- nbastatpy/utils.py +98 -0
- nbastatpy-0.1.6.dist-info/LICENSE +21 -0
- nbastatpy-0.1.6.dist-info/METADATA +67 -0
- nbastatpy-0.1.6.dist-info/RECORD +10 -0
- nbastatpy-0.1.6.dist-info/WHEEL +4 -0
nbastatpy/team.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
import nba_api.stats.endpoints as nba
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import requests
|
|
6
|
+
from bs4 import BeautifulSoup
|
|
7
|
+
from nba_api.stats.static import teams
|
|
8
|
+
|
|
9
|
+
from nbastatpy.utils import Formatter, PlayTypes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Team:
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
team_abbreviation: str,
|
|
16
|
+
season_year: str = None,
|
|
17
|
+
playoffs=False,
|
|
18
|
+
permode: str = "PerGame",
|
|
19
|
+
):
|
|
20
|
+
"""
|
|
21
|
+
Initializes a Team object.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
- team_abbreviation (str): The abbreviation of the NBA team.
|
|
25
|
+
- season_year (str, optional): The season year. If not provided, the current season year will be used.
|
|
26
|
+
- playoffs (bool, optional): Specifies whether the team's statistics are for playoffs. Default is False.
|
|
27
|
+
- permode (str, optional): The mode for the team's statistics. Default is "PerGame".
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
- permode (str): The formatted permode for the team's statistics.
|
|
31
|
+
- season_year (str): The season year.
|
|
32
|
+
- info (dict): The information about the team.
|
|
33
|
+
- season (str): The formatted season.
|
|
34
|
+
- season_type (str): The type of season (Regular Season or Playoffs).
|
|
35
|
+
"""
|
|
36
|
+
self.permode = PlayTypes.PERMODE[
|
|
37
|
+
permode.replace("_", "").replace("-", "").upper()
|
|
38
|
+
]
|
|
39
|
+
if season_year:
|
|
40
|
+
self.season_year = season_year
|
|
41
|
+
else:
|
|
42
|
+
self.season_year = Formatter.get_current_season_year()
|
|
43
|
+
|
|
44
|
+
self.info = teams.find_team_by_abbreviation(team_abbreviation)
|
|
45
|
+
|
|
46
|
+
self.season = Formatter.format_season(self.season_year)
|
|
47
|
+
self.season_type = "Regular Season"
|
|
48
|
+
if playoffs:
|
|
49
|
+
self.season_type = "Playoffs"
|
|
50
|
+
|
|
51
|
+
for attr_name, value in self.info.items():
|
|
52
|
+
setattr(self, attr_name.lower(), self.info.get(attr_name, None))
|
|
53
|
+
|
|
54
|
+
def get_logo(self):
|
|
55
|
+
"""
|
|
56
|
+
Retrieves and returns the logo of the NBA team in svg format.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
PIL.Image.Image: The logo image of the NBA team.
|
|
60
|
+
"""
|
|
61
|
+
pic_url = f"https://cdn.nba.com/logos/nba/{self.id}/primary/L/logo.svg"
|
|
62
|
+
pic = requests.get(pic_url)
|
|
63
|
+
self.logo = pic.content
|
|
64
|
+
return self.logo
|
|
65
|
+
|
|
66
|
+
def get_roster(self) -> List[pd.DataFrame]:
|
|
67
|
+
"""
|
|
68
|
+
Retrieves the roster of the team for the specified season.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
List[pd.DataFrame]: A list of pandas DataFrames containing the roster data.
|
|
72
|
+
"""
|
|
73
|
+
self.roster = nba.CommonTeamRoster(
|
|
74
|
+
self.id,
|
|
75
|
+
season=self.season,
|
|
76
|
+
).get_data_frames()
|
|
77
|
+
return self.roster
|
|
78
|
+
|
|
79
|
+
def get_salary(self) -> pd.DataFrame:
|
|
80
|
+
"""
|
|
81
|
+
Retrieves the salary information for the team from hoopshype.com.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
pandas.DataFrame: A DataFrame containing the salary information for the team.
|
|
85
|
+
"""
|
|
86
|
+
tm_name = "_".join(self.full_name.split(" ")).lower()
|
|
87
|
+
year = self.season.split("-")[0]
|
|
88
|
+
season_string = year + "-" + str(int(year) + 1)
|
|
89
|
+
self.salary_url = f"https://hoopshype.com/salaries/{tm_name}/{season_string}/"
|
|
90
|
+
|
|
91
|
+
result = requests.get(self.salary_url)
|
|
92
|
+
soup = BeautifulSoup(result.content, features="html.parser")
|
|
93
|
+
tables = soup.find_all("table")
|
|
94
|
+
|
|
95
|
+
rows = [[cell.text.strip() for cell in row.find_all('td')] for row in tables[0].find_all('tr')]
|
|
96
|
+
|
|
97
|
+
if not rows[0]:
|
|
98
|
+
rows.pop(0)
|
|
99
|
+
if not rows:
|
|
100
|
+
raise(ValueError(f"Season data unavailable for: {season_string}"))
|
|
101
|
+
self.salary_df = pd.DataFrame(rows[1:], columns=rows[0])
|
|
102
|
+
self.salary_df["Season"] = self.salary_df.columns[1].replace("/", "_")
|
|
103
|
+
self.salary_df.columns = ["Player", "Salary", "Adjusted Salary", "Season"]
|
|
104
|
+
|
|
105
|
+
return self.salary_df
|
|
106
|
+
|
|
107
|
+
def get_year_by_year(self) -> pd.DataFrame:
|
|
108
|
+
"""
|
|
109
|
+
Retrieves the year-by-year statistics for the team.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
pd.DataFrame: The year-by-year statistics for the team.
|
|
113
|
+
"""
|
|
114
|
+
self.year_by_year = nba.TeamYearByYearStats(
|
|
115
|
+
team_id=self.id, per_mode_simple=self.permode
|
|
116
|
+
).get_data_frames()[0]
|
|
117
|
+
return self.year_by_year
|
|
118
|
+
|
|
119
|
+
def get_general_splits(self) -> pd.DataFrame:
|
|
120
|
+
"""
|
|
121
|
+
Retrieves the general splits data for the team.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
pd.DataFrame: The general splits data for the team.
|
|
125
|
+
"""
|
|
126
|
+
drop_cols = [
|
|
127
|
+
"TEAM_GAME_LOCATION",
|
|
128
|
+
"GAME_RESULT",
|
|
129
|
+
"SEASON_MONTH_NAME",
|
|
130
|
+
"SEASON_SEGMENT",
|
|
131
|
+
"TEAM_DAYS_REST_RANGE",
|
|
132
|
+
]
|
|
133
|
+
self.general_splits = pd.concat(
|
|
134
|
+
nba.TeamDashboardByGeneralSplits(
|
|
135
|
+
team_id=self.id,
|
|
136
|
+
season=self.season,
|
|
137
|
+
season_type_all_star=self.season_type,
|
|
138
|
+
per_mode_detailed=self.permode,
|
|
139
|
+
).get_data_frames()
|
|
140
|
+
).drop(columns=drop_cols)
|
|
141
|
+
return self.general_splits
|
|
142
|
+
|
|
143
|
+
def get_shooting_splits(self) -> pd.DataFrame:
|
|
144
|
+
"""
|
|
145
|
+
Retrieves shooting splits data for the team.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
pd.DataFrame: The shooting splits data for the team.
|
|
149
|
+
"""
|
|
150
|
+
self.shooting_splits = pd.concat(
|
|
151
|
+
nba.TeamDashboardByShootingSplits(
|
|
152
|
+
team_id=self.id,
|
|
153
|
+
season=self.season,
|
|
154
|
+
season_type_all_star=self.season_type,
|
|
155
|
+
per_mode_detailed=self.permode,
|
|
156
|
+
).get_data_frames()
|
|
157
|
+
)
|
|
158
|
+
return self.shooting_splits
|
|
159
|
+
|
|
160
|
+
def get_leaders(self) -> pd.DataFrame:
|
|
161
|
+
"""
|
|
162
|
+
Retrieves the franchise leaders data for the team.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
pd.DataFrame: The franchise leaders data for the team.
|
|
166
|
+
"""
|
|
167
|
+
self.leaders = nba.FranchiseLeaders(team_id=self.id).get_data_frames()[0]
|
|
168
|
+
return self.leaders
|
|
169
|
+
|
|
170
|
+
def get_franchise_players(self) -> pd.DataFrame:
|
|
171
|
+
"""
|
|
172
|
+
Retrieves the franchise players for the team.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
pd.DataFrame: A DataFrame containing the franchise players' data.
|
|
176
|
+
"""
|
|
177
|
+
self.franchise_players = nba.FranchisePlayers(
|
|
178
|
+
team_id=self.id
|
|
179
|
+
).get_data_frames()[0]
|
|
180
|
+
return self.franchise_players
|
|
181
|
+
|
|
182
|
+
def get_season_lineups(self) -> pd.DataFrame:
|
|
183
|
+
"""
|
|
184
|
+
Retrieves the season lineups for the team.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
pd.DataFrame: A DataFrame containing the season lineups data.
|
|
188
|
+
"""
|
|
189
|
+
self.season_lineups = nba.LeagueDashLineups(
|
|
190
|
+
team_id_nullable=self.id,
|
|
191
|
+
season=self.season,
|
|
192
|
+
season_type_all_star=self.season_type,
|
|
193
|
+
per_mode_detailed=self.permode,
|
|
194
|
+
).get_data_frames()[0]
|
|
195
|
+
self.season_lineups["season"] = self.season
|
|
196
|
+
self.season_lineups["season_type"] = self.season_type
|
|
197
|
+
|
|
198
|
+
return self.season_lineups
|
|
199
|
+
|
|
200
|
+
def get_opponent_shooting(self) -> pd.DataFrame:
|
|
201
|
+
"""
|
|
202
|
+
Retrieves the opponent shooting statistics for the team.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
pd.DataFrame: DataFrame containing the opponent shooting statistics.
|
|
206
|
+
"""
|
|
207
|
+
self.opponent_shooting = nba.LeagueDashOppPtShot(
|
|
208
|
+
team_id_nullable=self.id,
|
|
209
|
+
season=self.season,
|
|
210
|
+
season_type_all_star=self.season_type,
|
|
211
|
+
per_mode_simple=self.permode,
|
|
212
|
+
).get_data_frames()[0]
|
|
213
|
+
self.opponent_shooting["season"] = self.season
|
|
214
|
+
self.opponent_shooting["season_type"] = self.season_type
|
|
215
|
+
|
|
216
|
+
return self.opponent_shooting
|
|
217
|
+
|
|
218
|
+
def get_player_clutch(self) -> pd.DataFrame:
|
|
219
|
+
"""
|
|
220
|
+
Retrieves the clutch statistics for the players of the team.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
pd.DataFrame: A DataFrame containing the clutch statistics for the players of the team.
|
|
224
|
+
"""
|
|
225
|
+
self.player_clutch = nba.LeagueDashPlayerClutch(
|
|
226
|
+
team_id_nullable=self.id,
|
|
227
|
+
season=self.season,
|
|
228
|
+
season_type_all_star=self.season_type,
|
|
229
|
+
per_mode_detailed=self.permode,
|
|
230
|
+
).get_data_frames()[0]
|
|
231
|
+
self.player_clutch["season"] = self.season
|
|
232
|
+
self.player_clutch["season_type"] = self.season_type
|
|
233
|
+
|
|
234
|
+
return self.player_clutch
|
|
235
|
+
|
|
236
|
+
def get_player_shots(self) -> pd.DataFrame:
|
|
237
|
+
"""
|
|
238
|
+
Retrieves the player shots data for the team.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
pd.DataFrame: The player shots data for the team.
|
|
242
|
+
"""
|
|
243
|
+
self.player_shots = nba.LeagueDashPlayerPtShot(
|
|
244
|
+
team_id_nullable=self.id,
|
|
245
|
+
season=self.season,
|
|
246
|
+
season_type_all_star=self.season_type,
|
|
247
|
+
per_mode_simple=self.permode,
|
|
248
|
+
).get_data_frames()[0]
|
|
249
|
+
self.player_shots["season"] = self.season
|
|
250
|
+
self.player_shots["season_type"] = self.season_type
|
|
251
|
+
|
|
252
|
+
return self.player_shots
|
|
253
|
+
|
|
254
|
+
def get_player_shot_locations(self) -> pd.DataFrame:
|
|
255
|
+
"""
|
|
256
|
+
Retrieves the shot locations data for the players of the team.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
pd.DataFrame: A DataFrame containing the shot locations data for the players.
|
|
260
|
+
"""
|
|
261
|
+
self.player_shot_locations = nba.LeagueDashPlayerShotLocations(
|
|
262
|
+
team_id_nullable=self.id,
|
|
263
|
+
season=self.season,
|
|
264
|
+
season_type_all_star=self.season_type,
|
|
265
|
+
per_mode_detailed=self.permode,
|
|
266
|
+
).get_data_frames()[0]
|
|
267
|
+
self.player_shot_locations["season"] = self.season
|
|
268
|
+
self.player_shot_locations["season_type"] = self.season_type
|
|
269
|
+
|
|
270
|
+
return self.player_shot_locations
|
|
271
|
+
|
|
272
|
+
def get_player_stats(self) -> pd.DataFrame:
|
|
273
|
+
"""
|
|
274
|
+
Retrieves the player statistics for the team.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
pd.DataFrame: A DataFrame containing the player statistics.
|
|
278
|
+
"""
|
|
279
|
+
self.player_stats = nba.LeagueDashPlayerStats(
|
|
280
|
+
team_id_nullable=self.id,
|
|
281
|
+
season=self.season,
|
|
282
|
+
season_type_all_star=self.season_type,
|
|
283
|
+
per_mode_detailed=self.permode,
|
|
284
|
+
).get_data_frames()[0]
|
|
285
|
+
self.player_stats["season"] = self.season
|
|
286
|
+
self.player_stats["season_type"] = self.season_type
|
|
287
|
+
|
|
288
|
+
return self.player_stats
|
|
289
|
+
|
|
290
|
+
def get_player_point_defend(self) -> pd.DataFrame:
|
|
291
|
+
"""
|
|
292
|
+
Retrieves the player point defense data for the team.
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
pd.DataFrame: The player point defense data for the team.
|
|
296
|
+
"""
|
|
297
|
+
self.player_point_defend = nba.LeagueDashPtDefend(
|
|
298
|
+
team_id_nullable=self.id,
|
|
299
|
+
season=self.season,
|
|
300
|
+
season_type_all_star=self.season_type,
|
|
301
|
+
per_mode_simple=self.permode,
|
|
302
|
+
).get_data_frames()[0]
|
|
303
|
+
self.player_point_defend["season"] = self.season
|
|
304
|
+
self.player_point_defend["season_type"] = self.season_type
|
|
305
|
+
|
|
306
|
+
return self.player_point_defend
|
|
307
|
+
|
|
308
|
+
def get_player_hustle(self) -> pd.DataFrame:
|
|
309
|
+
"""
|
|
310
|
+
Retrieves the hustle stats for the players of the team.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
pd.DataFrame: A DataFrame containing the hustle stats for the players.
|
|
314
|
+
"""
|
|
315
|
+
self.player_hustle = nba.LeagueHustleStatsPlayer(
|
|
316
|
+
team_id_nullable=self.id,
|
|
317
|
+
season=self.season,
|
|
318
|
+
season_type_all_star=self.season_type,
|
|
319
|
+
).get_data_frames()[0]
|
|
320
|
+
self.player_hustle["season"] = self.season
|
|
321
|
+
self.player_hustle["season_type"] = self.season_type
|
|
322
|
+
|
|
323
|
+
return self.player_hustle
|
|
324
|
+
|
|
325
|
+
def get_lineup_details(self) -> pd.DataFrame:
|
|
326
|
+
"""
|
|
327
|
+
Retrieves the lineup details for the team.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
pd.DataFrame: The lineup details for the team.
|
|
331
|
+
"""
|
|
332
|
+
self.lineup_details = nba.LeagueLineupViz(
|
|
333
|
+
team_id_nullable=self.id,
|
|
334
|
+
season=self.season,
|
|
335
|
+
season_type_all_star=self.season_type,
|
|
336
|
+
minutes_min=1,
|
|
337
|
+
per_mode_detailed=self.permode,
|
|
338
|
+
).get_data_frames()[0]
|
|
339
|
+
self.lineup_details["season"] = self.season
|
|
340
|
+
self.lineup_details["season_type"] = self.season_type
|
|
341
|
+
|
|
342
|
+
return self.lineup_details
|
|
343
|
+
|
|
344
|
+
def get_player_on_details(self) -> pd.DataFrame:
|
|
345
|
+
"""
|
|
346
|
+
Retrieves the player on-court details for the team.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
pd.DataFrame: A DataFrame containing the player on-court details.
|
|
350
|
+
"""
|
|
351
|
+
self.player_on_details = nba.LeaguePlayerOnDetails(
|
|
352
|
+
team_id=self.id,
|
|
353
|
+
season=self.season,
|
|
354
|
+
season_type_all_star=self.season_type,
|
|
355
|
+
per_mode_detailed=self.permode,
|
|
356
|
+
).get_data_frames()[0]
|
|
357
|
+
self.player_on_details["season"] = self.season
|
|
358
|
+
self.player_on_details["season_type"] = self.season_type
|
|
359
|
+
|
|
360
|
+
return self.player_on_details
|
|
361
|
+
|
|
362
|
+
def get_player_matchups(self, defense=False) -> pd.DataFrame:
|
|
363
|
+
"""
|
|
364
|
+
Retrieves player matchups for the team.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
defense (bool, optional): If True, retrieves defensive matchups. If False, retrieves offensive matchups. Defaults to False.
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
pd.DataFrame: DataFrame containing player matchups for the team.
|
|
371
|
+
"""
|
|
372
|
+
if defense:
|
|
373
|
+
self.player_matchups = nba.LeagueSeasonMatchups(
|
|
374
|
+
def_team_id_nullable=self.id,
|
|
375
|
+
season=self.season,
|
|
376
|
+
season_type_playoffs=self.season_type,
|
|
377
|
+
per_mode_simple=self.permode,
|
|
378
|
+
).get_data_frames()[0]
|
|
379
|
+
else:
|
|
380
|
+
self.player_matchups = nba.LeagueSeasonMatchups(
|
|
381
|
+
off_team_id_nullable=self.id,
|
|
382
|
+
season=self.season,
|
|
383
|
+
season_type_playoffs=self.season_type,
|
|
384
|
+
per_mode_simple=self.permode,
|
|
385
|
+
).get_data_frames()[0]
|
|
386
|
+
|
|
387
|
+
self.player_matchups["season"] = self.season
|
|
388
|
+
self.player_matchups["season_type"] = self.season_type
|
|
389
|
+
|
|
390
|
+
return self.player_matchups
|
|
391
|
+
|
|
392
|
+
def get_player_passes(self) -> pd.DataFrame:
|
|
393
|
+
"""
|
|
394
|
+
Retrieves the player passes data for the team.
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
pd.DataFrame: The player passes data for the team.
|
|
398
|
+
"""
|
|
399
|
+
self.player_passes = pd.concat(
|
|
400
|
+
nba.TeamDashPtPass(
|
|
401
|
+
team_id=self.id,
|
|
402
|
+
season=self.season,
|
|
403
|
+
season_type_all_star=self.season_type,
|
|
404
|
+
per_mode_simple=self.permode,
|
|
405
|
+
).get_data_frames()
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
group_cols = ["PASS_FROM", "PASS_TO"]
|
|
409
|
+
self.player_passes["GROUP_SET"] = self.player_passes[group_cols].apply(
|
|
410
|
+
Formatter.combine_strings, axis=1
|
|
411
|
+
)
|
|
412
|
+
self.player_passes = self.player_passes.drop(columns=group_cols)
|
|
413
|
+
return self.player_passes.reset_index(drop=True)
|
|
414
|
+
|
|
415
|
+
def get_player_onoff(self) -> pd.DataFrame:
|
|
416
|
+
"""
|
|
417
|
+
Retrieves the on-off court details for the players of the team.
|
|
418
|
+
|
|
419
|
+
Returns:
|
|
420
|
+
pd.DataFrame: A DataFrame containing the on-off court details for the players.
|
|
421
|
+
"""
|
|
422
|
+
self.player_onoff = pd.concat(
|
|
423
|
+
nba.TeamPlayerOnOffDetails(
|
|
424
|
+
team_id=team.id,
|
|
425
|
+
season=self.season,
|
|
426
|
+
season_type_all_star=self.season_type,
|
|
427
|
+
per_mode_detailed=self.permode,
|
|
428
|
+
).get_data_frames()[1:]
|
|
429
|
+
)
|
|
430
|
+
return self.player_onoff.reset_index(drop=True)
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
if __name__ == "__main__":
|
|
434
|
+
team_name = "MIL"
|
|
435
|
+
team = Team(team_name, season_year="2024", playoffs=True)
|
|
436
|
+
print(team.get_salary())
|
nbastatpy/utils.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PlayTypes:
|
|
7
|
+
|
|
8
|
+
PERMODE = {
|
|
9
|
+
"PERGAME": "PerGame",
|
|
10
|
+
"PER36": "Per36",
|
|
11
|
+
"TOTALS": "Totals",
|
|
12
|
+
"PERMINUTE": "PerMinute",
|
|
13
|
+
"PERMIN": "PerMinute",
|
|
14
|
+
"PERPOSSESSION": "Per100Possessions",
|
|
15
|
+
"PERPOSS": "Per100Possessions",
|
|
16
|
+
"PER100POSSESSIONS": "Per100Possessions",
|
|
17
|
+
"PERPLAY": "PerPlay",
|
|
18
|
+
"PER100PLAYS": "Per100Plays",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
PLAYTYPES = {
|
|
22
|
+
"TRANSITION": "Transition",
|
|
23
|
+
"ISOLATION": "Isolation",
|
|
24
|
+
"ISO": "Isolation",
|
|
25
|
+
"PRBALLHANDLER": "PRBallHandler",
|
|
26
|
+
"PRROLLMAN": "PRRollman",
|
|
27
|
+
"POSTUP": "Postup",
|
|
28
|
+
"SPOTUP": "Spotup",
|
|
29
|
+
"HANDOFF": "Handoff",
|
|
30
|
+
"CUT": "Cut",
|
|
31
|
+
"OFFSCREEN": "OffScreen",
|
|
32
|
+
"PUTBACKS": "OffRebound",
|
|
33
|
+
"OFFREBOUND": "OffRebound",
|
|
34
|
+
"MISC": "Misc",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
TRACKING_TYPES = {
|
|
38
|
+
"SPEEDDISTANCE": "SpeedDistance",
|
|
39
|
+
"SPEED": "SpeedDistance",
|
|
40
|
+
"DISTANCE": "SpeedDistance",
|
|
41
|
+
"POSSESSIONS": "Possessions",
|
|
42
|
+
"CATCHSHOOT": "CatchShoot",
|
|
43
|
+
"PULLUPSHOT": "PullUpShot",
|
|
44
|
+
"PULLUP": "PullUpShot",
|
|
45
|
+
"DEFENSE": "Defense",
|
|
46
|
+
"DRIVES": "Drives",
|
|
47
|
+
"DRIVE": "Drives",
|
|
48
|
+
"PASSING": "Passing",
|
|
49
|
+
"ELBOWTOUCH": "ElbowTouch",
|
|
50
|
+
"ELBOW": "ElbowTouch",
|
|
51
|
+
"POSTTOUCH": "PostTouch",
|
|
52
|
+
"POST": "PostTouch",
|
|
53
|
+
"PAINTTOUCH": "PaintTouch",
|
|
54
|
+
"PAINT": "PaintTouch",
|
|
55
|
+
"EFFICIENCY": "Efficiency",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
DEFENSE_TYPES = {
|
|
59
|
+
"OVERALL": "Overall",
|
|
60
|
+
"THREE": "3 Pointers",
|
|
61
|
+
"THREES": "3 Pointers",
|
|
62
|
+
"TWOS": "2 Pointers",
|
|
63
|
+
"TWO": "2 Pointers",
|
|
64
|
+
"LESSTHAN6FT": "Less Than 6Ft",
|
|
65
|
+
"LESSTHAN10FT": "Less Than 10Ft",
|
|
66
|
+
"GREATERTHAN15FT": "Greater Than 15Ft",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Formatter:
|
|
71
|
+
|
|
72
|
+
def get_current_season_year() -> str:
|
|
73
|
+
current_datetime = datetime.now()
|
|
74
|
+
current_season_year = current_datetime.year
|
|
75
|
+
if current_datetime.month <= 9:
|
|
76
|
+
current_season_year -= 1
|
|
77
|
+
return current_season_year
|
|
78
|
+
|
|
79
|
+
def format_season(season_year: int) -> str:
|
|
80
|
+
return "{}-{}".format(int(season_year), str(int(season_year) + 1)[2:])
|
|
81
|
+
|
|
82
|
+
def format_game_id(game_id) -> str:
|
|
83
|
+
return str(game_id).zfill(10)
|
|
84
|
+
|
|
85
|
+
def combine_strings(row) -> str:
|
|
86
|
+
return next(value for value in row if pd.notna(value))
|
|
87
|
+
|
|
88
|
+
def check_playtype(play: str, playtypes: dict) -> str:
|
|
89
|
+
|
|
90
|
+
play = play.replace("_", "").replace("-", "").upper()
|
|
91
|
+
|
|
92
|
+
if play == "ALL":
|
|
93
|
+
return list(set(playtypes.values()))
|
|
94
|
+
|
|
95
|
+
if play not in set(playtypes.keys()):
|
|
96
|
+
raise ValueError(f"Playtype: {play} not found")
|
|
97
|
+
|
|
98
|
+
return playtypes[play]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 aberghammer-analytics
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: nbastatpy
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: An easy-to-use wrapper for nba_api to easily find data for a player, game, team, or season
|
|
5
|
+
Home-page: https://github.com/aberghammer-analytics/NBAStatPy
|
|
6
|
+
Keywords: basketball,data,nba,sports,stats
|
|
7
|
+
Maintainer: Anthony Berghammer
|
|
8
|
+
Maintainer-email: aberghammer.analytics@gmail.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Requires-Dist: bs4 (>=0.0.2,<0.0.3)
|
|
16
|
+
Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
|
17
|
+
Requires-Dist: nba_api (>=1.4.1,<2.0.0)
|
|
18
|
+
Requires-Dist: pandas (>=2.2.2,<3.0.0)
|
|
19
|
+
Requires-Dist: pillow (>=10.3.0,<11.0.0)
|
|
20
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
21
|
+
Requires-Dist: rich (>=13.7.1,<14.0.0)
|
|
22
|
+
Project-URL: Documentation, https://github.com/aberghammer-analytics/NBAStatPy/blob/main/README.md
|
|
23
|
+
Project-URL: Repository, https://github.com/aberghammer-analytics/NBAStatPy
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# NBAStatPy
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
This is an easy-to-use wrapper for the `nba_api` package. The goal is to be able to easily access and find data for a player, game, team, or season.
|
|
31
|
+
|
|
32
|
+
The data is accessed through a class based on how you're searching for it. A quickstart example is shown below. Currently there are 4 classes:
|
|
33
|
+
|
|
34
|
+
- `Game`
|
|
35
|
+
- `Player`
|
|
36
|
+
- `Season`
|
|
37
|
+
- `Team`
|
|
38
|
+
|
|
39
|
+
## Quickstart
|
|
40
|
+
|
|
41
|
+
To get started you can import the class that represents the data you're searching for.
|
|
42
|
+
|
|
43
|
+
```{python}
|
|
44
|
+
from nbastatpy.player import Player
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then you build a player using either an ID from stats.nba.com or the player's name. When you're building the player object you can add additional search data like season, data format, or playoffs vs. regular season.
|
|
48
|
+
|
|
49
|
+
```{python}
|
|
50
|
+
player = Player(
|
|
51
|
+
"Giannis",
|
|
52
|
+
season="2020",
|
|
53
|
+
playoffs=True,
|
|
54
|
+
permode="PerGame"
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Once you have the player object, you can get different datasets based on the criteria. For instance, you can get the awards the player has won by doing the following:
|
|
59
|
+
|
|
60
|
+
```{python}
|
|
61
|
+
player.get_awards()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This returns a pandas dataframe with the awards won by the player each year.
|
|
65
|
+
|
|
66
|
+
There are a lot of endpoints and various arguments for more complex queries like tracking and synergy datasets.
|
|
67
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
nbastatpy/__init__.py,sha256=LhTkEQMCuJU5UMrQliKi4z3HtuMxxDY5_79ZJ0IB5PU,18
|
|
2
|
+
nbastatpy/game.py,sha256=RSUgATPk6xBj6kFqtQ74IfnjdwMUuRhaZWEflO84Qjk,4631
|
|
3
|
+
nbastatpy/player.py,sha256=NHa0WTuw9301mfPSSsXTWg87_xGS8GjP1Fh1JYkTK8s,17311
|
|
4
|
+
nbastatpy/season.py,sha256=0zEWb_iBcsKe42wsU9ISxbUl6HU2Tbt1DISRJXFyj_A,19732
|
|
5
|
+
nbastatpy/team.py,sha256=gjjIJc4JoYAjmJII9Mw1FDrDMl0AJjFMgVeIEvPnNNg,15250
|
|
6
|
+
nbastatpy/utils.py,sha256=mFH1SqQUWR_Vpl154urgvOZWf5HtflIrlj1eGNzhCeY,2739
|
|
7
|
+
nbastatpy-0.1.6.dist-info/LICENSE,sha256=TZeVWgOOMmZI_Puv-mvmD8h35JL78SyVE5A6JVISLV0,1078
|
|
8
|
+
nbastatpy-0.1.6.dist-info/METADATA,sha256=KPD6Y4p63u4q-Cq8cDJrRc-1pr6Fzh9irMbXvTiXgJQ,2355
|
|
9
|
+
nbastatpy-0.1.6.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
|
10
|
+
nbastatpy-0.1.6.dist-info/RECORD,,
|