Source code for nba_stats_tracking.tracking

import time
from datetime import date
from typing import Any, Dict, List, Tuple, Union

from dateutil.rrule import DAILY, rrule

from nba_stats_tracking import helpers
from nba_stats_tracking.models.request import PerMode, SeasonType
from nba_stats_tracking.models.tracking import (
    CatchAndShootItem,
    CatchAndShootResults,
    DefenseItem,
    DefenseResults,
    DrivesItem,
    DrivesResults,
    EfficiencyItem,
    EfficiencyResults,
    ElbowTouchesItem,
    ElbowTouchesResults,
    PaintTouchesItem,
    PaintTouchesResults,
    PassingItem,
    PassingResults,
    PlayerOrTeam,
    PossessionsItem,
    PossessionsResults,
    PostTouchesItem,
    PostTouchesResults,
    PullUpItem,
    PullUpResults,
    ReboundingItem,
    ReboundingResults,
    SpeedDistanceItem,
    SpeedDistanceResults,
    TrackingMeasureType,
    TrackingRequestParameters,
)

RESPONSE_MODEL_MAP = {
    TrackingMeasureType.catch_and_shoot: CatchAndShootResults,
    TrackingMeasureType.defense: DefenseResults,
    TrackingMeasureType.drives: DrivesResults,
    TrackingMeasureType.shooting: EfficiencyResults,
    TrackingMeasureType.elbow_touches: ElbowTouchesResults,
    TrackingMeasureType.paint_touches: PaintTouchesResults,
    TrackingMeasureType.passing: PassingResults,
    TrackingMeasureType.possessions: PossessionsResults,
    TrackingMeasureType.post_touches: PostTouchesResults,
    TrackingMeasureType.pull_up: PullUpResults,
    TrackingMeasureType.rebounding: ReboundingResults,
    TrackingMeasureType.speed_distance: SpeedDistanceResults,
}

DATA_ITEM_MAP = {
    TrackingMeasureType.catch_and_shoot: CatchAndShootItem,
    TrackingMeasureType.defense: DefenseItem,
    TrackingMeasureType.drives: DrivesItem,
    TrackingMeasureType.shooting: EfficiencyItem,
    TrackingMeasureType.elbow_touches: ElbowTouchesItem,
    TrackingMeasureType.paint_touches: PaintTouchesItem,
    TrackingMeasureType.passing: PassingItem,
    TrackingMeasureType.possessions: PossessionsItem,
    TrackingMeasureType.post_touches: PostTouchesItem,
    TrackingMeasureType.pull_up: PullUpItem,
    TrackingMeasureType.rebounding: ReboundingItem,
    TrackingMeasureType.speed_distance: SpeedDistanceItem,
}


[docs]def get_tracking_results_for_stat_measure( measure_type: TrackingMeasureType, season: str, season_type: SeasonType, player_or_team: PlayerOrTeam, **kwargs, ) -> Dict: """ Makes API call to `NBA Advanced Stats <https://www.stats.nba.com/>`_ and returns JSON response results :param measure_type: Stat measure type to get stats for :param season: Format YYYY-YY ex 2019-20 :param season_type: Season type to get stats for :param player_or_team: get stats for player or team :param str DateFrom: (optional) Format - MM/DD/YYYY :param str DateTo: (optional) Format - MM/DD/YYYY :param str OpponentTeamID: (optional) nba.com team id :param `~nba_stats_tracking.models.request.PerMode` PerMode: (optional) Defaults to totals. :return: response json :rtype: dict """ url = "https://stats.nba.com/stats/leaguedashptstats" parameters = TrackingRequestParameters( PtMeasureType=measure_type, Season=season, SeasonType=season_type, PlayerOrTeam=player_or_team, **kwargs, ) response_json = helpers.get_json_response( url, parameters.dict(by_alias=True, exclude_none=True) ) # stats will be contained in first item of resultSets return response_json["resultSets"][0]
[docs]def get_tracking_stats( measure_type: TrackingMeasureType, seasons: List[str], season_types: List[SeasonType], player_or_team: PlayerOrTeam, **kwargs, ) -> List[Any]: """ Gets stat measure tracking stats for filter Returns list of ResultItem with stats for each player/team :param measure_type: Stat measure type to get stats for :param seasons: List of seasons. Format YYYY-YY ex 2019-20 :param season_types: List of season types. :param player_or_team: get stats for player or team :param str DateFrom: (optional) Format - MM/DD/YYYY :param str DateTo: (optional) Format - MM/DD/YYYY :param str OpponentTeamID: (optional) nba.com team id :param `~nba_stats_tracking.models.request.PerMode` PerMode: (optional) Defaults to totals. """ all_season_stats = [] for season in seasons: for season_type in season_types: # Making too many requests in a short period can result in timeouts. Add a delay between requests time.sleep(2) results = get_tracking_results_for_stat_measure( measure_type, season, season_type, player_or_team, **kwargs ) stats = RESPONSE_MODEL_MAP[measure_type](**results) for stat in stats.results: stat.season = f"{season} {season_type}" all_season_stats += stats.results return all_season_stats
[docs]def aggregate_full_season_tracking_stats_for_seasons( measure_type: TrackingMeasureType, seasons: List[str], season_types: List[SeasonType], player_or_team: PlayerOrTeam, **kwargs, ) -> Tuple[List[Any], Any]: """ Aggregates full season stats for stat measure for desired filters. Returns list of ResultItem for stats for each team/player and ResultItem with league totals. :param measure_type: Stat measure type to get stats for :param seasons: List of seasons. Format YYYY-YY ex 2019-20 :param season_types: List of season types. :param player_or_team: get stats for player or team :param str OpponentTeamID: (optional) nba.com team id """ stats_by_season = get_tracking_stats( measure_type, seasons, season_types, player_or_team, **kwargs ) stats = sum_tracking_totals(player_or_team, measure_type, stats_by_season) league_totals = sum_tracking_totals("league", measure_type, stats) return stats, league_totals
[docs]def generate_tracking_game_logs( measure_type: TrackingMeasureType, player_or_team: PlayerOrTeam, date_from: date, date_to: date, **kwargs, ) -> List[Any]: """ Generates game logs for all games between two dates for desired filters Returns list of game log ResultItem :param measure_type: Stat measure type to get stats for :param player_or_team: get stats for player or team :param date_from: start date :param date_to: end date :param dict team_id_game_id_map: (optional) dict mapping team id to game id. When getting game logs for multiple separate filters for the same date it is recommended that you pass this in to avoid making the same request multiple times :param dict team_id_opponent_team_id_map: (optional) dict mapping team id to opponent team id. When getting game logs for multiple separate filters for the same date it is recommended that you pass this in to avoid making the same request multiple times :param dict player_id_team_id_map: (optional) dict mapping player id to team id. When getting game logs for multiple separate filters for the same date it is recommended that you pass this in to avoid making the same request multiple times """ team_id_game_id_map = kwargs.get("team_id_game_id_map") team_id_opponent_team_id_map = kwargs.get("team_id_opponent_team_id_map") player_id_team_id_map = kwargs.get("player_id_team_id_map") get_player_id_team_id_map = player_id_team_id_map is None get_team_id_maps = ( team_id_game_id_map is None or team_id_opponent_team_id_map is None ) game_logs = [] for dt in rrule(DAILY, dtstart=date_from, until=date_to): if get_team_id_maps: ( team_id_game_id_map, team_id_opponent_team_id_map, ) = helpers.get_team_id_maps_for_date(dt) if len(team_id_game_id_map.values()) != 0: if get_player_id_team_id_map: player_id_team_id_map = helpers.get_player_team_map_for_date(dt) date_game_id = list(team_id_game_id_map.values())[0] season = helpers.get_season_from_game_id(date_game_id) season_type = helpers.get_season_type_from_game_id(date_game_id) tracking_game_logs = get_tracking_stats( measure_type, [season], [season_type], player_or_team, # User per game here because it gives results to more decimal places PerMode=PerMode.per_game, # camel case to match request param key DateFrom=dt.strftime("%m/%d/%Y"), DateTo=dt.strftime("%m/%d/%Y"), ) if player_or_team == PlayerOrTeam.player: # need to add team id for player because results only have last team id, # which may not be the team for which they played the game for game_log in tracking_game_logs: game_log.team_id = player_id_team_id_map[game_log.player_id] for game_log in tracking_game_logs: game_log.game_id = team_id_game_id_map[game_log.team_id] game_log.opponent_team_id = team_id_opponent_team_id_map[ game_log.team_id ] game_logs += tracking_game_logs return game_logs
[docs]def sum_tracking_totals( entity_type: str, measure_type: TrackingMeasureType, *args ) -> Union[List[Any], Any]: r""" Sums totals for given dicts and grouped by entity type Returns list of ResultItem with totals for each entity or ResultItem if entity type is league :param entity_type: Options are Player, Team or league :param measure_type: Stat measure type to get stats for :param \*args: Variable length argument list of ResultItem to be summed up """ if entity_type == PlayerOrTeam.player: entity_key = "player_id" elif entity_type == PlayerOrTeam.team: entity_key = "team_id" elif entity_type == "league": totals = DATA_ITEM_MAP[measure_type](TEAM_ID="00", TEAM_ABBREVIATION="LEAGUE") for items in args: for item in items: totals += item return totals else: return [] totals = {} for items in args: for item in items: entity_id = item[entity_key] if entity_id not in totals.keys(): totals[entity_id] = item else: totals[entity_id] += item return list(totals.values())