| 1117 | |
| 1118 | # Add reference line at ELO_BASE |
| 1119 | ax.axhline(ELO_BASE, color="red", linestyle="--", alpha=0.5, linewidth=1, label=f"Base Elo ({ELO_BASE})") |
| 1120 | |
| 1121 | legend = ax.legend(prop=FONT_BOLD, fontsize=12, loc="best") |
| 1122 | legend.set_frame_on(False) |
| 1123 | |
| 1124 | plt.tight_layout() |
| 1125 | safe_game_name = game_name.replace("/", "_").replace(" ", "_") |
| 1126 | self._save_plot(output_dir, f"{safe_game_name}_elo_vs_max_rounds") |
| 1127 | plt.close() |
| 1128 | |
| 1129 | |
| 1130 | class EloOnlyAtRound: |
| 1131 | def __init__( |
| 1132 | self, |
| 1133 | *, |
| 1134 | log_dir: Path, |
| 1135 | max_rounds: int = 15, |
| 1136 | all_games_normalization_scheme: ALL_GAMES_NORMALIZATION_SCHEMES = "none", |
| 1137 | score_type: SCORING_TYPES = "per_round_tertiary", |
| 1138 | regularization: float = 0.01, |
| 1139 | output_dir: Path | None = None, |
| 1140 | games: list[str] | None = None, |
| 1141 | ): |
| 1142 | self.log_dir = log_dir |
| 1143 | self.max_rounds = max_rounds |
| 1144 | self.all_games_normalization_scheme = all_games_normalization_scheme |
| 1145 | self.score_type = score_type |
| 1146 | self.regularization = regularization |
| 1147 | self.output_dir = output_dir |
| 1148 | self.games = games |
| 1149 | |
| 1150 | @staticmethod |
| 1151 | def _save_plot(output_dir: Path, filename_base: str) -> None: |
| 1152 | """Save plot in both PDF and PNG formats.""" |
| 1153 | for fmt in ["pdf", "png"]: |
| 1154 | output_path = output_dir / f"{filename_base}.{fmt}" |
| 1155 | plt.savefig(output_path, format=fmt, bbox_inches="tight", dpi=300 if fmt == "png" else None) |
| 1156 | logger.info(f"Saved plot: {output_path}") |
| 1157 | |
| 1158 | def run(self) -> None: |
| 1159 | """Calculate Elo for only specific rounds from 1 to max_rounds and plot the results.""" |
| 1160 | logger.info(f"Calculating Elo for only specific rounds 1 to {self.max_rounds}") |
| 1161 | |
| 1162 | # Dictionary to store results: {round: {game_name: {player: elo}}} |
| 1163 | results_by_round: dict[int, dict[str, dict[str, float]]] = {} |
| 1164 | |
| 1165 | for round_num in tqdm(range(1, self.max_rounds + 1), desc="Processing specific rounds"): |
| 1166 | builder = ScoreMatrixBuilder( |
| 1167 | all_games_normalization_scheme=self.all_games_normalization_scheme, |
| 1168 | score_type=self.score_type, |
| 1169 | max_round=round_num, |
| 1170 | only_specific_round=True, |
| 1171 | ) |
| 1172 | builder.build(self.log_dir) |
| 1173 | |
| 1174 | results_by_round[round_num] = {} |
| 1175 | |
| 1176 | for game_name, matchups in builder.win_matrix.items(): |