示例#1
0
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
示例#2
0
    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
示例#3
0
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
    }
示例#4
0
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
示例#5
0
 def __init__(self, tba_auth_key, year=None):
     self.tba = TBA(tba_auth_key)
     self.all_teams = self.getAllTeams(year=year)  # {team_key -> Team}
示例#6
0
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)]
示例#7
0
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()
示例#8
0
    def __init__(self, authkey, year, team_key=None, event_key=None):
        self.authkey = authkey
        self.year = year

        # TBA data handler
        self.tba = TBA(authkey)
示例#9
0
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