From 6cae038e84bb31245d3cd79a6ef35a6ea4486af2 Mon Sep 17 00:00:00 2001 From: Ryan Fitz-Gerald Date: Thu, 10 Oct 2024 09:19:51 -0400 Subject: [PATCH] Initial commit --- .gitignore | 3 + data/DistrictEvent_entry.txt | 14 ++ data/DistrictRanking_entry.txt | 32 ++++ get_rankings.py | 294 +++++++++++++++++++++++++++++++++ 4 files changed, 343 insertions(+) create mode 100644 .gitignore create mode 100644 data/DistrictEvent_entry.txt create mode 100644 data/DistrictRanking_entry.txt create mode 100644 get_rankings.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fac383b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.venv +.vscode +results \ No newline at end of file diff --git a/data/DistrictEvent_entry.txt b/data/DistrictEvent_entry.txt new file mode 100644 index 0000000..6d76ca2 --- /dev/null +++ b/data/DistrictEvent_entry.txt @@ -0,0 +1,14 @@ + {'city': 'Allendale Charter Township', + 'country': 'USA', + 'district': {'abbreviation': 'fim', + 'display_name': 'FIRST In Michigan', + 'key': '2025fim', + 'year': 2025}, + 'end_date': datetime.date(2025, 3, 22), + 'event_code': 'miwmi', + 'event_type': 1, + 'key': '2025miwmi', + 'name': 'FIM District West Michigan Event', + 'start_date': datetime.date(2025, 3, 20), + 'state_prov': 'MI', + 'year': 2025}] \ No newline at end of file diff --git a/data/DistrictRanking_entry.txt b/data/DistrictRanking_entry.txt new file mode 100644 index 0000000..7214d91 --- /dev/null +++ b/data/DistrictRanking_entry.txt @@ -0,0 +1,32 @@ +{'event_points': [{'alliance_points': 15, + 'award_points': 0, + 'district_cmp': False, + 'elim_points': 13, + 'event_key': '2024misjo', + 'qual_points': 18, + 'total': 46}, + {'alliance_points': 16, + 'award_points': 10, + 'district_cmp': False, + 'elim_points': 30, + 'event_key': '2024mimid', + 'qual_points': 22, + 'total': 78}, + {'alliance_points': 48, + 'award_points': 15, + 'district_cmp': True, + 'elim_points': 90, + 'event_key': '2024micmp2', + 'qual_points': 66, + 'total': 219}, + {'alliance_points': 0, + 'award_points': 0, + 'district_cmp': True, + 'elim_points': 60, + 'event_key': '2024micmp', + 'qual_points': 0, + 'total': 60}], + 'point_total': 403, + 'rank': 1, + 'rookie_bonus': 0, + 'team_key': 'frc5712'} \ No newline at end of file diff --git a/get_rankings.py b/get_rankings.py new file mode 100644 index 0000000..c7c4cf7 --- /dev/null +++ b/get_rankings.py @@ -0,0 +1,294 @@ +from pathlib import Path +import tbaapiv3client +from tbaapiv3client.rest import ApiException +from pprint import pprint + +from csv import DictWriter + +# Setup Config +config = tbaapiv3client.Configuration( + host='https://www.thebluealliance.com/api/v3', + api_key={ + 'X-TBA-Auth-Key': '7SvEHOaVwj3HXwnSyxLatIDWBMN3QPPvhJxzQ7m9DnuD94OzLUu0yp56YguLa1KF' + }) + +config.verify_ssl = False + + +def get_rankings(api_client: tbaapiv3client.ApiClient, seasons: list[str]) -> list[dict]: + # Create an instance of the API class + api_instance = tbaapiv3client.DistrictApi(api_client) + + rankings = {} + + for season in seasons: + try: + results = api_instance.get_district_rankings(season) + except ApiException as e: + print("Exception when calling DistrictApi->get_district_rankings: %s\n" % e) + else: + for result in results: + team = result.team_key + + if team not in rankings: + rankings[team] = {} + + points_event1 = None + points_event1_na = None + points_event2 = None + points_event2_na = None + + if len(result.event_points) > 0: + event = result.event_points[0] + points_event1 = event.total + points_event1_na = event.qual_points + event.elim_points + event.alliance_points + + + if len(result.event_points) > 1: + event = result.event_points[1] + points_event1 = event.total + points_event1_na = event.qual_points + event.elim_points + event.alliance_points + + rankings[team][season] = { + "rank": result.rank, + "point_total": result.point_total, + "points_event1": points_event1, + "points_event2": points_event2, + "points_event1_na": points_event1_na, + "points_event2_na": points_event2_na + } + + return rankings + +def get_event_teams(api_client: tbaapiv3client.ApiClient, season:str) -> dict[dict]: + + api_district = tbaapiv3client.DistrictApi(api_client) + api_event = tbaapiv3client.EventApi(api_client) + + try: + district_results = api_district.get_district_events(season) + + except ApiException as e: + print("Exception when calling EventApi->get_district_events: %s\n" % e) + else: + event_teams: dict = {} + + for district_result in district_results: + key = district_result.key + name = district_result.name + if 'cmp' not in key: + try: + team_results = api_event.get_event_teams_keys(key) + + except ApiException as e: + print("Exception when calling EventApi->get_event_teams_keys: %s\n" % e) + else: + event_teams[key] = { + 'key': key, + 'name': name, + 'teams': team_results, + 'start date': district_result.start_date, + 'week': district_result.start_date.isocalendar()[1] - 8 + } + + return event_teams + +def write_rank_csv(path: str | Path, rankings: list[dict], seasons:list[str]) -> None: + # Create annual rank CSV + results_list:list[dict] = [] + + for team, ranks in rankings.items(): + result = { + 'team': team + } + + for season in seasons: + value = '' + if season in ranks: + value = ranks[season]['rank'] + + result[season] = value + + results_list.append(result) + + write_result_csv(path, results_list) + +def write_point_total_csv(path: str | Path, rankings: list[dict], seasons:list[str]) -> None: + # Create annual rank CSV + results_list:list[dict] = [] + + for team, ranks in rankings.items(): + result = { + 'team': team + } + + for season in seasons: + value = '' + if season in ranks: + value = ranks[season]['point_total'] + + result[season] = value + + results_list.append(result) + + write_result_csv(path, results_list) + +def write_points_events_csv(path: str | Path, rankings: list[dict], seasons:list[str]) -> None: + # Create annual rank CSV + results_list:list[dict] = [] + + for team, ranks in rankings.items(): + result = { + 'team': team + } + + for season in seasons: + value = '' + if season in ranks: + value = 0 + + if ranks[season]['points_event1'] is not None: + value += ranks[season]['points_event1'] + + if ranks[season]['points_event2'] is not None: + value += ranks[season]['points_event2'] + + result[season] = value + + results_list.append(result) + + write_result_csv(path, results_list) + +def write_result_csv(path: str| Path, results_list:list[dict]) -> None: + if not isinstance(path, Path): + path = Path(path) + + with open(path, 'w', newline='') as f: + writer = DictWriter(f, results_list[0].keys()) + + writer.writeheader() + writer.writerows(results_list) + + +def main(): + + seasons = ['2022fim', '2023fim', '2024fim'] + root_dir = Path('results') + + + with tbaapiv3client.ApiClient(config) as api_client: + rankings = get_rankings(api_client, seasons) + event_teams = get_event_teams(api_client, '2025fim') + + event_summary: list[dict] = [] + + for key, event in event_teams.items(): + rank_sum = 0 + point_total_sum = 0 + point_district_sum = 0 + point_district_na_sum = 0 + + entry_count = 0 + + event_details: list[dict] = [] + + for team in event['teams']: + team_details = { + 'team': team + } + + if team in rankings: + for season in seasons: + rank = '' + point_total = '' + point_district = '' + point_district_na = '' + + if season in rankings[team]: + team_season = rankings[team][season] + + rank = team_season['rank'] + point_total = team_season['point_total'] + point_district = 0 + point_district_na = 0 + + if team_season['points_event1'] is not None: + point_district += team_season['points_event1'] + + if team_season['points_event2'] is not None: + point_district += team_season['points_event2'] + + if team_season['points_event1_na'] is not None: + point_district_na += team_season['points_event1_na'] + + if team_season['points_event2_na'] is not None: + point_district_na += team_season['points_event2_na'] + + rank_sum += rank + point_total_sum += point_total + point_district_sum += point_district + point_district_na_sum += point_district_na + entry_count += 1 + + team_details[f'{season} rank'] = rank + team_details[f'{season} point total'] = point_total + team_details[f'{season} point district'] = point_district + team_details[f'{season} point district no awards'] = point_district + else: + for season in seasons: + team_details[f'{season} rank'] = '' + team_details[f'{season} point total'] = '' + team_details[f'{season} point district'] = '' + team_details[f'{season} point district no awards'] = '' + + event_details.append(team_details) + + + if len(event_details): + # Write Event Details + with open(root_dir / f'{key} details.csv', 'w', newline='') as f: + writer = DictWriter(f, event_details[0]) + + writer.writeheader() + writer.writerows(event_details) + + # Generate Event Summary + rank_avg = '' + point_total_avg = '' + point_district_avg = '' + point_district_na_avg = '' + + if entry_count > 0: + rank_avg = rank_sum / entry_count + point_total_avg = point_total_sum / entry_count + point_district_avg = point_district_sum / entry_count + point_district_na_avg = point_district_na_sum / entry_count + + event_summary.append({ + 'key': key, + 'name': event['name'], + 'start date': event['start date'], + 'week': event['week'], + 'average rank': rank_avg, + 'average point total': point_total_avg, + 'average point district': point_district_avg, + 'average point district no awards': point_district_na_avg, + 'entries': entry_count, + 'team count': len(event['teams']) + }) + + + # Write Event Summary + with open(root_dir / f'event summary.csv', 'w', newline='') as f: + writer = DictWriter(f, event_summary[0].keys()) + + writer.writeheader() + writer.writerows(event_summary) + + #write_rank_csv(root_dir / "season_rankings.csv", rankings, seasons) + #write_point_total_csv(root_dir / "season_point_total.csv", rankings, seasons) + #write_points_events_csv(root_dir / "season_points_events.csv", rankings, seasons) + + +if __name__ == '__main__': + main()