From 94007bb7b1bf0bc429d5c33ec7ab17114fae6ae8 Mon Sep 17 00:00:00 2001 From: Marius Heidenreich <marius.heidenreich@tu-dortmund.de> Date: Sun, 16 Mar 2025 04:08:54 +0100 Subject: [PATCH] claude bessere plots --- main.py | 126 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 53 deletions(-) diff --git a/main.py b/main.py index d1ef53f..2eadb03 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,7 @@ class EloSystem: self.output_directory = output_directory self.teams = {} # Dictionary to store team Elo ratings self.match_history = [] # List to store all match results for history tracking + self.competition_history = {} # Dictionary to store competition results self.initialize_output_directory() def initialize_output_directory(self): @@ -63,7 +64,7 @@ class EloSystem: 'competitions': 0, 'history': [] } - teams_in_competition.append(team_name) + teams_in_competition.append((rank, team_name)) except StopIteration: # File is empty continue @@ -79,6 +80,7 @@ class EloSystem: team_name = row[1].strip() if len(row) > 1 else row[0].strip() else: # If no explicit ranking, use row index + rank = len(teams_in_competition) + 1 team_name = row[0].strip() # Initialize the team if not seen before @@ -88,20 +90,36 @@ class EloSystem: 'competitions': 0, 'history': [] } - teams_in_competition.append(team_name) + teams_in_competition.append((rank, team_name)) + + # Sort teams by rank + teams_in_competition.sort(key=lambda x: x[0]) + + # Store competition results + date = datetime.now().strftime("%Y-%m-%d") # Use current date as competition date + self.competition_history[competition_name] = { + 'date': date, + 'results': teams_in_competition + } + + # Extract just team names in order + team_names = [team[1] for team in teams_in_competition] # Update competition count for each team - for team_name in teams_in_competition: + for team_name in team_names: self.teams[team_name]['competitions'] += 1 # Update Elo ratings based on this competition's results - self.update_elo_for_competition(teams_in_competition, competition_name) + self.update_elo_for_competition(team_names, competition_name) def update_elo_for_competition(self, teams_in_order, competition_name): """Update Elo ratings for all teams in a competition""" # For each team, compare with teams ranked below them date = datetime.now().strftime("%Y-%m-%d") # Use current date as competition date + # Store pre-competition Elo ratings + pre_competition_elo = {team: self.teams[team]['elo'] for team in teams_in_order} + for i in range(len(teams_in_order)): for j in range(i + 1, len(teams_in_order)): team_a = teams_in_order[i] @@ -110,6 +128,21 @@ class EloSystem: # Team A is ranked higher than Team B self.update_elo_pair(team_a, team_b, 1, 0, competition_name, date) + # Store post-competition Elo ratings and changes + for team in teams_in_order: + elo_change = self.teams[team]['elo'] - pre_competition_elo[team] + rank = teams_in_order.index(team) + 1 + + # Store in team history + self.teams[team]['history'].append({ + 'date': date, + 'competition': competition_name, + 'rank': rank, + 'previous_elo': pre_competition_elo[team], + 'new_elo': self.teams[team]['elo'], + 'elo_change': elo_change + }) + def update_elo_pair(self, team_a, team_b, score_a, score_b, competition_name, date): """Update Elo ratings for a pair of teams based on their match outcome""" # Get current Elo ratings @@ -139,13 +172,10 @@ class EloSystem: } self.match_history.append(match_info) - # Update team Elo ratings and history + # Update team Elo ratings self.teams[team_a]['elo'] = new_rating_a self.teams[team_b]['elo'] = new_rating_b - self.teams[team_a]['history'].append({'date': date, 'elo': new_rating_a, 'competition': competition_name}) - self.teams[team_b]['history'].append({'date': date, 'elo': new_rating_b, 'competition': competition_name}) - def expected_score(self, rating_a, rating_b): """Calculate the expected score for a player with rating_a against a player with rating_b""" return 1 / (1 + math.pow(10, (rating_b - rating_a) / 400)) @@ -227,7 +257,7 @@ class EloSystem: </head> <body> <h1>Team Elo Rankings</h1> - <p>Rankings based on {len(self.match_history)} matches from {self.count_competitions()} competitions.</p> + <p>Rankings based on {len(self.competition_history)} competitions.</p> <div class="chart-container"> <img src="images/top_teams_elo.png" alt="Top Teams Elo Chart"> @@ -277,9 +307,8 @@ class EloSystem: if team_data['history']: self.create_team_elo_history_chart(team_name) - # Get matches involving this team - team_matches = [match for match in self.match_history - if match['team_a'] == team_name or match['team_b'] == team_name] + # Filter history for this team's competitions + team_competitions = sorted(team_data['history'], key=lambda x: x['date'], reverse=True) html_content = f"""<!DOCTYPE html> <html lang="en"> @@ -360,6 +389,12 @@ class EloSystem: font-size: 14px; color: #666; }} + .positive {{ + color: green; + }} + .negative {{ + color: red; + }} </style> </head> <body> @@ -377,21 +412,19 @@ class EloSystem: </div> """ - # Calculate win rate if applicable - if team_matches: - wins = sum(1 for match in team_matches - if (match['team_a'] == team_name and match['score_a'] > match['score_b']) - or (match['team_b'] == team_name and match['score_b'] > match['score_a'])) - win_rate = (wins / len(team_matches)) * 100 + # Calculate average ranking if available + if team_competitions: + avg_rank = sum(comp['rank'] for comp in team_competitions) / len(team_competitions) + best_rank = min(comp['rank'] for comp in team_competitions) html_content += f""" <div class="stat-box"> - <div class="stat-value">{len(team_matches)}</div> - <div class="stat-label">Total Matches</div> + <div class="stat-value">{avg_rank:.1f}</div> + <div class="stat-label">Avg. Placement</div> </div> <div class="stat-box"> - <div class="stat-value">{win_rate:.1f}%</div> - <div class="stat-label">Win Rate</div> + <div class="stat-value">{best_rank}</div> + <div class="stat-label">Best Placement</div> </div> """ @@ -402,40 +435,31 @@ class EloSystem: <img src="images/{}_history.png" alt="{} Elo History"> </div> - <h2>Match History</h2> + <h2>Competition History</h2> <table> <tr> <th>Date</th> <th>Competition</th> - <th>Opponent</th> - <th>Result</th> + <th>Placement</th> + <th>Elo Before</th> + <th>Elo After</th> <th>Elo Change</th> </tr> """.format(self.clean_filename(team_name), team_name) - # Add rows for each match - for match in sorted(team_matches, key=lambda x: x['date'], reverse=True): - if match['team_a'] == team_name: - opponent = match['team_b'] - old_elo = match['old_elo_a'] - new_elo = match['new_elo_a'] - result = "Win" if match['score_a'] > match['score_b'] else "Loss" - else: - opponent = match['team_a'] - old_elo = match['old_elo_b'] - new_elo = match['new_elo_b'] - result = "Win" if match['score_b'] > match['score_a'] else "Loss" - - elo_change = new_elo - old_elo - change_color = "green" if elo_change > 0 else "red" + # Add rows for each competition + for comp in team_competitions: + elo_change = comp['elo_change'] + change_class = "positive" if elo_change > 0 else "negative" if elo_change < 0 else "" html_content += f""" <tr> - <td>{match['date']}</td> - <td>{match['competition']}</td> - <td><a href="team_{self.clean_filename(opponent)}.html">{opponent}</a></td> - <td>{result}</td> - <td style="color: {change_color}">{'+' if elo_change > 0 else ''}{elo_change:.1f}</td> + <td>{comp['date']}</td> + <td>{comp['competition']}</td> + <td>{comp['rank']}</td> + <td>{int(comp['previous_elo'])}</td> + <td>{int(comp['new_elo'])}</td> + <td class="{change_class}">{'+' if elo_change > 0 else ''}{elo_change:.1f}</td> </tr>""" html_content += """ @@ -515,15 +539,15 @@ class EloSystem: team_history.sort(key=lambda x: x['date']) dates = [entry['date'] for entry in team_history] - elo_values = [entry['elo'] for entry in team_history] + elo_values = [entry['new_elo'] for entry in team_history] # Create line chart plt.plot(range(len(dates)), elo_values, marker='o', linestyle='-', color='blue') # Add competition labels for i, entry in enumerate(team_history): - plt.annotate(entry['competition'], - (i, entry['elo']), + plt.annotate(entry['competition'] + f" (#{entry['rank']})", + (i, entry['new_elo']), textcoords="offset points", xytext=(0, 10), ha='center', @@ -541,10 +565,6 @@ class EloSystem: dpi=100) plt.close() - def count_competitions(self): - """Count the number of unique competitions""" - return len(set(match['competition'] for match in self.match_history)) - def clean_filename(self, filename): """Clean a string to make it suitable for use as a filename""" # Replace spaces and special characters @@ -556,7 +576,7 @@ def main(): import argparse parser = argparse.ArgumentParser(description='Process competition results and generate Elo rankings website') - parser.add_argument('--input', default='data', help='Directory containing CSV result files') + parser.add_argument('--input', default='csv_files', help='Directory containing CSV result files') parser.add_argument('--output', default='elo_website', help='Output directory for the website') args = parser.parse_args() -- GitLab