def format_alliance(tba_client: tbapy.TBA, event_id, team_ids): '''format alliance team data into something reasonable to look at (mainly for embeds)''' event_oprs = tba_client.event_oprs(event_id)["oprs"] oprs = {i: event_oprs[i] for i in team_ids} out = "" for team in team_ids: team_data = tba_client.team(team, simple=True) out += "* {} [{}] -- OPR: {}\n".format(team_data['nickname'], team_data['team_number'], round(oprs[team])) return out
def get_event_field_statistics(self, event_key, field_name, calculations=['mean'], field_position_based=False, categorical_value=None, exclude_playoffs=True): """ Returns a dictionary of calculated statistics (mean/med/min/max/stdev/count) for a given field (ex. totalPoints) for all teams at an event Required Parameters: event_key: str: = the event to get team field statistics from field_name: str = the TBA field under scoring_breakdown to get calculations for (ex. totalPoints) Optional Parameters: calculations: list<str> = list of calculations to perform on a team's field values. mean, med, min, max, stdev, count. default=['mean'] field_position_based: boolean = whether the field is categorized in TBA based on robot_position. default=False categorical_value: str = the categorical value to count. default=None exclude_playoffs: boolean = whether to exclude playoff matches from calculations. default = True Returns: calculated_event_statistics: dict = Returns (possibly nested) dictionary holding the calculated statistic(s) for a given field for each team at the event. If field is position based, team_keys are keys. ex.) {'frc2521': 0.76, ...} If not, Outer key is the calculation name and inner keys are team keys ex.) {mean: {'frc2521': 100, ...}} """ if event_key is None: print("A TBA event key is needed to perform this calculation") return if field_position_based and len(calculations) > 1: print( f"A a list of calculations {calculations} was given but only the proportion of times that the" f" categorical_value was recorded in each of the teams' matches will be returned") tba = TBA(self.authkey) event_team_keys = [team.key for team in tba.event_teams(event_key, simple=True)] # Creates (maybe nested) dictionary holding the calculated statistic(s) for a given field for each team at the event all_teams_statistics = dict.fromkeys(calculations, {}) if not field_position_based else dict() for team_key in event_team_keys: calculated_statistics = get_field_statistic(self.authkey, team_key, self.year, field_name, calculations, field_position_based, categorical_value, exclude_playoffs, event_key=event_key) if field_position_based: all_teams_statistics[team_key] = calculated_statistics else: for calculation_type in calculated_statistics.keys(): all_teams_statistics[calculation_type][team_key] = calculated_statistics[calculation_type] return all_teams_statistics
def get_match_ids(tba_client: tbapy.TBA, event_name, year=2019, comp_level="qm"): '''get all match ids in a dict in order of how they were played''' event_id = get_event_id(event_name, year) return { m["match_number"]: m for m in tba_client.event_matches(event_id, simple=True) if m["comp_level"] == comp_level }
def check_matches_exist(authkey, year, team_key=None, event_key=None, exclude_playoffs=False): tba = TBA(authkey) if event_key is not None and team_key is None: if exclude_playoffs and len( get_qualification_matches( tba.event_matches(event=event_key))) == 0: return False elif not exclude_playoffs and len( tba.event_matches(event=event_key)) == 0: return False else: return True if team_key is not None and event_key is None: if exclude_playoffs and len( get_qualification_matches( tba.team_matches(team=team_key, year=year))) == 0: return False elif len(tba.team_matches(team=team_key, year=year)) == 0: return False else: return True elif team_key is not None and event_key is not None: print('Make sure to only specify team_key OR event_key, not both') return None
def __init__(self, tba_auth_key, year=None): self.tba = TBA(tba_auth_key) self.all_teams = self.getAllTeams(year=year) # {team_key -> Team}
class TBA_Request: def __init__(self, tba_auth_key, year=None): self.tba = TBA(tba_auth_key) self.all_teams = self.getAllTeams(year=year) # {team_key -> Team} def getAllTeams(self, year=None): tba_teams = self.tba.teams(year=year, simple=True) teams = {} # team key -> Team alert_indicies = [ math.floor(j * len(tba_teams) * 0.1) for j in list(range(11)) ] for i, tba_team in enumerate(tba_teams): team = Team(tba_team.team_number) team.loadTBAData(tba_team) teams[team.key] = team if i in alert_indicies or i + 1 == len(tba_teams): print("{}% teams loaded.".format( int((i + 1) / len(tba_teams) * 100))) return teams def getEventsKeys(self, year, current_only=False, must_include_teams=None): events = self.tba.events(year, simple=True) event_keys = [event.key for event in events] if current_only: event_keys = [ event.key for event in events if event.start_date <= getCurrentDate() and event.end_date >= getCurrentDate() ] if must_include_teams: n_event_keys = [] for event_key in event_keys: event_team_keys = self.tba.event_teams(event_key, keys=True) if any( [team in must_include_teams for team in event_team_keys]): n_event_keys.append(event_key) event_keys = n_event_keys return event_keys def getEvents(self, year, current_only=False, must_include_teams=None): event_keys = self.getEventsKeys(year, current_only=current_only, must_include_teams=must_include_teams) return [self.getEvent(event_key) for event_key in event_keys] def getEvent(self, event_key): ev = Event(event_key) ev.loadTBA(self.tba, self.all_teams) return ev def filterTeamList(self, team_dict=None, state=None, country=None, min_number=None, max_number=None, event_code=None): if team_dict == None: team_dict = self.all_teams team_list = teamsDictToList(team_dict) if state != None: team_list = [team for team in team_list if team.state == state] if country != None: team_list = [team for team in team_list if team.country == country] if min_number != None: team_list = [ team for team in team_list if team.team_number >= min_number ] if max_number != None: team_list = [ team for team in team_list if team.team_number <= max_number ] if event_code != None: event_team_keys = self.tba.event_teams(event_code, keys=True) team_list = [ team for team in team_list if team.key in event_team_keys ] return teamsListToDict(team_list) def initTeamAttribute(self, key, value): for team in self.all_teams: self.all_teams[team].attrs[key] = value def getRankedTeamListByAttr(self, key, reverse=True, n=10): if n == None: n = len(self.all_teams) return [ v for k, v in sorted([ team for team in self.all_teams.items() if key in team[1].attrs ], key=lambda team: team[1].attrs[key], reverse=reverse) ][:min(len(self.all_teams), n)]
class TBADataHelper: """ Class for performing aggregate and OPR calculations on match data fetched from TBA APIv3 Constructor arguments: year: int = The year to get data from """ def __init__(self, authkey, year, team_key=None, event_key=None): self.authkey = authkey self.year = year # TBA data handler self.tba = TBA(authkey) def get_team_field_statistics(self, team_key, field_name, calculations=['mean'], field_position_based=False, categorical_value=None, exclude_playoffs=True, event_key=None): """ Returns a dictionary of calculated statistics mean/med/min/max/stdev/count for a given field (ex. totalPoints) - If the field is categorized in TBA based on robot position(ex. endgameRobot2, etc.), the field_position_based and categorical_value parameters need to be specified. The percentage of times that categorical_value was recorded for the team will be returned in decimal form. Required Parameters: team_key: str = the team key ('frc'+ TEAM_NUMBER) to get calculations for field_name: str = the TBA field under scoring_breakdown to get calculations for (ex. totalPoints) Optional Parameters: calculations: list<str> = list of calculations to perform on a team's field values. mean, med, min, max, stdev, count. default=['mean'] field_position_based: boolean = whether the field is categorized in TBA based on robot_position. default=False categorical_value: str = the categorical value to count. default=None exclude_playoffs: boolean = whether to exclude playoff matches from calculations. default = True event_key: str: = specify an event_key if you only want to perform calculations on matches played at a certain event. default=None Returns: calculated_statistics: dict = Dictionary of keys corresponding to the calculation name and values corresponding to the calculated value ex.) {mean: 77, max: 154, ...} """ if team_key is None: print("A TBA team key is needed to perform this calculation") return return get_field_statistic(self.authkey, team_key, self.year, field_name, calculations, field_position_based, categorical_value, exclude_playoffs, event_key) def get_team_OPR_statistic(self, team_key, field='totalPoints', calculations=['mean'], exclude_playoffs=True): """ Returns a dictionary of the mean/med/min/max/stdev/count of a team's OPR at every competition they've attended Parameters: team_key: str = the team key ('frc'+ TEAM_NUMBER) to get calculations for field: str = the TBA field to calculate contribution for. default='totalPoints' calculations: list<str> = list of calculations to perform on a team's field values. mean, med, min, max, stdev, count. default=['mean'] exclude_playoffs: boolean = whether to exclude playoff matches from calculations. default = True Returns: calculated_statistics: dict = Dictionary of keys corresponding to the calculation name and values corresponding to their value ex.) {mean: 56, max: 56, ...} """ if team_key is None: print("A TBA team key is needed to perform this calculation") return # List of tuples of format (event_key, event_CC for team) all_event_CCs = [] for event in self.tba.team_events(team=team_key, year=self.year, keys=True): # Only calculate event CCs for events that have had matches if check_matches_exist(self.authkey, 2019, event_key=event, exclude_playoffs=exclude_playoffs): # HOTFIX: Events that aren't stored in TBA with standardized conventions (such as offseason events) # will break event OPR calculations. Such events will be skipped over try: event_CCs = event_OPR(self.authkey, event, field, exclude_playoffs) except: print("Error in calculating CCs for event_key:", event) continue # Skip over any teams that didn't play any matches in their event try: all_event_CCs.append((event, event_CCs.calculate_contribution()[team_key])) except KeyError: print("Team: ", team_key, "didn't play any matches") continue else: continue # Associates a calculation keyword to its appropriate function calculation_map = {'mean': mean, 'med': median, 'max': max, 'min': min, 'stdev': stdev, 'count': len} # Dictionary of {calculation keyword:value} pairs to be returned calculated_statistics = {} # Perform statistical calculations on list of event CCs for calculation in calculations: try: calculated_statistics[calculation] = calculation_map[calculation]([x[1] for x in all_event_CCs]) except: print( "Make sure your calculation is either max, min, mean, med, count, or stdev. If using stdev, there may not be more than 1 event CC yet") return calculated_statistics def get_event_field_statistics(self, event_key, field_name, calculations=['mean'], field_position_based=False, categorical_value=None, exclude_playoffs=True): """ Returns a dictionary of calculated statistics (mean/med/min/max/stdev/count) for a given field (ex. totalPoints) for all teams at an event Required Parameters: event_key: str: = the event to get team field statistics from field_name: str = the TBA field under scoring_breakdown to get calculations for (ex. totalPoints) Optional Parameters: calculations: list<str> = list of calculations to perform on a team's field values. mean, med, min, max, stdev, count. default=['mean'] field_position_based: boolean = whether the field is categorized in TBA based on robot_position. default=False categorical_value: str = the categorical value to count. default=None exclude_playoffs: boolean = whether to exclude playoff matches from calculations. default = True Returns: calculated_event_statistics: dict = Returns (possibly nested) dictionary holding the calculated statistic(s) for a given field for each team at the event. If field is position based, team_keys are keys. ex.) {'frc2521': 0.76, ...} If not, Outer key is the calculation name and inner keys are team keys ex.) {mean: {'frc2521': 100, ...}} """ if event_key is None: print("A TBA event key is needed to perform this calculation") return if field_position_based and len(calculations) > 1: print( f"A a list of calculations {calculations} was given but only the proportion of times that the" f" categorical_value was recorded in each of the teams' matches will be returned") tba = TBA(self.authkey) event_team_keys = [team.key for team in tba.event_teams(event_key, simple=True)] # Creates (maybe nested) dictionary holding the calculated statistic(s) for a given field for each team at the event all_teams_statistics = dict.fromkeys(calculations, {}) if not field_position_based else dict() for team_key in event_team_keys: calculated_statistics = get_field_statistic(self.authkey, team_key, self.year, field_name, calculations, field_position_based, categorical_value, exclude_playoffs, event_key=event_key) if field_position_based: all_teams_statistics[team_key] = calculated_statistics else: for calculation_type in calculated_statistics.keys(): all_teams_statistics[calculation_type][team_key] = calculated_statistics[calculation_type] return all_teams_statistics def get_event_OPRs(self, event_key, field='totalPoints', exclude_playoffs=True): """ Returns a dictionary containing the OPR of all teams at an event. Parameters: event_key: str: = the event to get team OPRs from field: str = the TBA/FIRSTApi field to calculate contribution for. default='totalPoints' Changing this will result in something other than OPRs being returned. Don't touch unless you know what you're doing exclude_playoffs: boolean = whether to exclude playoff matches from calculations. default = True Returns: calculated_contributions: dictionary = Keys are TBA team_keys with values being the team's OPR at the event ex.) {frc2521: 65, frc254: 148, ...} """ if event_key is None: print("A TBA event key is needed to perform this calculation") return event_CCs = event_OPR(self.authkey, event_key, field, exclude_playoffs) return event_CCs.calculate_contribution()
def __init__(self, authkey, year, team_key=None, event_key=None): self.authkey = authkey self.year = year # TBA data handler self.tba = TBA(authkey)
def get_field_statistic(authkey, team_key, year, field_name, calculations=[], field_position_based=False, categorical_value=None, exclude_playoffs=True, event_key=None): # TBA data handler tba = TBA(authkey) # Get list of team matches from TBA if event_key: matches = tba.team_matches(team=team_key, event=event_key) else: matches = tba.team_matches(team=team_key, year=year) matches = get_qualification_matches( matches) if exclude_playoffs else matches # Only keep matches that have been played matches = get_played_matches(matches) # Handles fields that are measured through a robot's position, ex. endgame location if field_position_based: if categorical_value is None: print( "You must specify a categorical_value to count occurrences of. See docstring for more info" ) return field_values = [] for match in matches: # Finds the robot's position number in TBA robot_position = str(get_robot_number(match, team_key)) field_values.append(match['score_breakdown'][get_alliance_color( match, team_key)][field_name + robot_position]) return round( field_values.count(categorical_value) / len(field_values), 3) if len(field_values) != 0 else None # Creates a list of all the values for a particular field in every match a team played field_values = [ match["score_breakdown"][get_alliance_color(match, team_key)][field_name] for match in matches ] # Associates a calculation keyword to its appropriate function calculation_map = { 'mean': mean, 'med': median, 'max': max, 'min': min, 'stdev': stdev, 'count': len } # If the field values are integers, return the average value. If they are strings, return the value that occurs most often # Dictionary of {calculation keyword:value} pairs to be returned calculated_statistics = {} # Perform statistical calculations on list of field values # print(field_values) for calculation in calculations: calculated_statistics[calculation] = calculation_map[calculation]( field_values) return calculated_statistics