From f7ea4409269914173df68da5e1549ed12192496e Mon Sep 17 00:00:00 2001 From: maeries <8ij4neqiu@mozmail.com> Date: Fri, 21 Mar 2025 16:07:43 +0100 Subject: [PATCH] added an overview page for every competition --- competition_page.py | 182 ++++++++++++++++++++++++++++++++++++++++++ main.py | 59 +++++++++----- team_page.py | 6 +- world_ranking_list.py | 4 +- 4 files changed, 227 insertions(+), 24 deletions(-) create mode 100644 competition_page.py diff --git a/competition_page.py b/competition_page.py new file mode 100644 index 0000000..adcb53a --- /dev/null +++ b/competition_page.py @@ -0,0 +1,182 @@ +from datetime import datetime +from tools import clean_filename + +def get_competition_page_html(self, competition_id): + competition_data = self.competition_history[competition_id] + full_competition_name = self.get_full_competition_name(competition_id) + html_content = f"""<!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{full_competition_name} - Results</title> + {self.header_snippet} + <style> + body {{ + font-family: Arial, sans-serif; + line-height: 1.6; + margin: 0; + padding: 20px; + max-width: 1200px; + margin: 0 auto; + }} + h1, h2 {{ + color: #333; + animation: fadeInUp 0.5s ease-out forwards; + }} + table {{ + border-collapse: collapse; + width: 100%; + margin-top: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + border-radius: 5px; + overflow: hidden; + animation: fadeInUp 0.5s ease-out forwards; + opacity: 0; + }} + + th, td {{ + padding: 12px 15px; + text-align: left; + }} + + th {{ + background-color: #f2f2f2; + color: #333; + font-weight: bold; + text-transform: uppercase; + border-bottom: 2px solid {self.BORDER_COLOR}; + }} + + tr {{ + background-color: white; + transition: background-color 0.3s ease; + }} + + tr:nth-child(even) {{ + background-color: #f9f9f9; + }} + + tr:hover {{ + background-color: #f5f5f5; + }} + p {{ + animation: fadeInUp 0.5s ease-out forwards; + }} + .chart-container {{ + margin-top: 30px; + display: flex; + justify-content: center; + width: 100%; + animation: fadeInUp 0.5s ease-out forwards; + opacity: 0; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + border-radius: 5px; + overflow: hidden; + background-color: white; + padding: 20px; + box-sizing: border-box; + }} + .chart-container img {{ + max-width: 100%; + height: auto; + }} + a {{ + color: {self.LINK_COLOR}; + text-decoration: none; + transition: color 0.3s ease; + }} + a:hover {{ + color: {self.LINK_COLOR_HOVER}; + text-decoration: none; + }} + .summary-stats {{ + display: flex; + justify-content: space-around; + margin: 20px 0; + flex-wrap: wrap; + animation: fadeInUp 0.5s ease-out forwards; + }} + .stat-box {{ + padding: 15px; + border: 1px solid #ddd; + border-radius: 5px; + margin: 10px; + flex: 1; + min-width: 150px; + text-align: center; + background-color: #f9f9f9; + }} + .stat-value {{ + font-size: 24px; + font-weight: bold; + color: #333; + }} + .stat-label {{ + font-size: 14px; + color: #666; + }} + .positive {{ + color: green; + }} + .negative {{ + color: red; + }} + @keyframes fadeInUp {{ + from {{ + opacity: 0; + transform: translateY(20px); + }} + to {{ + opacity: 1; + transform: translateY(0); + }} + }} + </style> + </head> + <body> + <h1>{full_competition_name} - Results</h1> + <p><a href="../index.html">↠Back to World Ranking</a></p> + """ + + html_content += """ + </div> + + <!-- + <div class="chart-container"> + fancy diagram here + </div> + --> + + <h2>Results</h2> + <table> + <tr> + <th>Placement</th> + <th>Team</th> + <th>Elo Before</th> + <th>Elo Change</th> + </tr> + """ + + # Add rows for each competition + for team in competition_data['results']: + elo_change = team[3] + change_class = "positive" if elo_change > 0 else "negative" if elo_change < 0 else "" + + html_content += f""" + <tr> + <td>{team[0]}</td> + <td><a href="../team/{clean_filename(team[1])}.html">{team[1]}</a></td> + <td>{int(team[2])}</td> + <td class="{change_class}">{'+' if elo_change > 0 else ''}{elo_change:.1f}</td> + </tr>""" + + html_content += """ + </table> + + <p><small>Generated on {}</small></p> + </body> + </html> + """.format(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + + return html_content \ No newline at end of file diff --git a/main.py b/main.py index b585c1e..4bc3d11 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,7 @@ import numpy as np import pandas as pd from matplotlib.colors import LinearSegmentedColormap +from competition_page import get_competition_page_html from team_page import get_team_page_html from tools import * from world_ranking_list import get_world_ranking_html @@ -62,16 +63,21 @@ class EloSystem: """Create output directory if it doesn't exist""" os.makedirs(self.output_directory, exist_ok=True) os.makedirs(os.path.join(self.output_directory, 'images'), exist_ok=True) + os.makedirs(os.path.join(self.output_directory, 'team'), exist_ok=True) + os.makedirs(os.path.join(self.output_directory, 'comp'), exist_ok=True) - def get_competition_name(self, id): - return self.competition_meta_data[self.competition_meta_data["id"] == int(id)]['abbr'].values[0].strip() + def get_competition_name(self, competition_id): + return self.competition_meta_data[self.competition_meta_data["id"] == int(competition_id)]['abbr'].values[0].strip() - def get_competition_date(self, id): - date_string = self.competition_meta_data[self.competition_meta_data["id"] == int(id)]['date'].values[0] + def get_full_competition_name(self, competition_id): + return self.competition_meta_data[self.competition_meta_data["id"] == int(competition_id)]['name'].values[0].strip() + + def get_competition_date(self, competition_id): + date_string = self.competition_meta_data[self.competition_meta_data["id"] == int(competition_id)]['date'].values[0] return datetime.strptime(date_string, "%Y-%m-%d") - def get_competition_type(self, id): - return self.competition_meta_data[self.competition_meta_data["id"] == int(id)]['kind'].values[0].strip() + def get_competition_type(self, competition_id): + return self.competition_meta_data[self.competition_meta_data["id"] == int(competition_id)]['kind'].values[0].strip() def load_and_process_csv_files(self): """Load all CSV files and process them to calculate Elo ratings""" @@ -117,7 +123,7 @@ class EloSystem: 'history': [], 'delta_elo': 0 } - teams_in_competition.append((rank, team_name)) + teams_in_competition.append([rank, team_name, None, None]) except FileNotFoundError: print(f"file {csv_file} not found: skipping") continue @@ -158,18 +164,25 @@ class EloSystem: # Store post-competition Elo ratings and changes for team in teams_in_order: rank = teams_in_order.index(team) + 1 + previous_elo = self.teams[team]['elo'] + elo_change = self.teams[team]['delta_elo'] # Store in team history self.teams[team]['history'].append({ 'date': date.strftime("%Y-%m-%d"), 'competition': self.get_competition_name(competition_id), + 'competition_id': competition_id, 'rank': rank, 'participants': len(teams_in_order), - 'previous_elo': self.teams[team]['elo'], + 'previous_elo': previous_elo, 'new_elo': self.teams[team]['elo'] + self.teams[team]['delta_elo'], - 'elo_change': self.teams[team]['delta_elo'] + 'elo_change': elo_change }) + # Store in competition history + self.competition_history[competition_id]['results'][rank-1][2] = previous_elo + self.competition_history[competition_id]['results'][rank-1][3] = elo_change + self.teams[team]['elo'] = self.teams[team]['elo'] + self.teams[team]['delta_elo'] self.teams[team]['delta_elo'] = 0 @@ -208,22 +221,19 @@ class EloSystem: def generate_website(self): """Generate static HTML website with Elo ratings and visualizations""" - # Create main index page - self.create_world_ranking() - - # # Create team-specific pages - # for team_name in self.teams: - # self.create_team_page(team_name) # If num_processes not specified, use number of CPU cores num_processes = int(mp.cpu_count() / 2) print(f"staring computation on {num_processes} cores") - - # Create a pool of workers pool = mp.Pool(processes=num_processes) + + self.create_world_ranking() + + for competition in self.competition_history: + self.create_competition_page(competition) + pool.map(self.create_team_page, self.teams) - # Create visualizations self.create_visualizations() print(f"Website generated in {self.output_directory}") @@ -253,7 +263,18 @@ class EloSystem: html_content = get_team_page_html(self, team_name, team_data, team_competitions) # Write the HTML file - with open(os.path.join(self.output_directory, f'team_{clean_filename(team_name)}.html'), 'w', + with open(os.path.join(self.output_directory, 'team', f'{clean_filename(team_name)}.html'), 'w', + encoding='utf-8') as f: + f.write(html_content) + + def create_competition_page(self, competition_id): + """Create a dedicated page for a specific team""" + print(f"Generating Competition site for {competition_id}") + + html_content = get_competition_page_html(self, competition_id) + + # Write the HTML file + with open(os.path.join(self.output_directory, 'comp', f'{str(competition_id)}.html'), 'w', encoding='utf-8') as f: f.write(html_content) diff --git a/team_page.py b/team_page.py index e603b7e..e62d74a 100644 --- a/team_page.py +++ b/team_page.py @@ -134,7 +134,7 @@ def get_team_page_html(self, team_name, team_data, team_competitions): </head> <body> <h1>{team_name} - Elo Profile</h1> - <p><a href="index.html">↠Back to Rankings</a></p> + <p><a href="../index.html">↠Back to World Ranking</a></p> <div class="summary-stats"> <div class="stat-box"> @@ -167,7 +167,7 @@ def get_team_page_html(self, team_name, team_data, team_competitions): </div> <div class="chart-container"> - <img src="images/{}_history.png" alt="{} Elo History"> + <img src="../images/{}_history.png" alt="{} Elo History"> </div> <h2>Competition History</h2> @@ -190,7 +190,7 @@ def get_team_page_html(self, team_name, team_data, team_competitions): html_content += f""" <tr> <td>{comp['date']}</td> - <td>{comp['competition']}</td> + <td><a href=../comp/{comp['competition_id']}.html>{comp['competition']}</a></td> <td>{comp['rank']} / {comp['participants']}</td> <td>{int(comp['previous_elo'])}</td> <td>{int(comp['new_elo'])}</td> diff --git a/world_ranking_list.py b/world_ranking_list.py index a530828..4c270a1 100644 --- a/world_ranking_list.py +++ b/world_ranking_list.py @@ -216,7 +216,7 @@ def get_world_ranking_html(self, sorted_teams): html_content += f""" <tr> <td>{rank}</td> - <td><a href="team_{clean_filename(team_name)}.html">{team_name}</a></td> + <td><a href="team/{clean_filename(team_name)}.html">{team_name}</a></td> <td>{int(team_data['elo'])}</td> <td>{team_data['competitions']}</td> </tr>""" @@ -233,7 +233,7 @@ def get_world_ranking_html(self, sorted_teams): </div> <div style="display: flex; justify-content: center;"> - <a href="index.html"><button class="nav-button">Back to Home</button></a> + <a href="../index.html"><button class="nav-button">Back to Home</button></a> </div> </div> </body> -- GitLab