Skip to content

Commit edac183

Browse files
committed
Enh(metrics): Make Elo plot appearance blend in to paper
1 parent 43b3849 commit edac183

1 file changed

Lines changed: 61 additions & 33 deletions

File tree

codeclash/analysis/metrics/elo2.py

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77

88
import matplotlib.pyplot as plt
99
import numpy as np
10+
from matplotlib.ticker import AutoMinorLocator
1011
from scipy.optimize import minimize
1112
from scipy.stats import kendalltau, spearmanr
1213
from tqdm import tqdm
1314

1415
from codeclash.analysis.metrics.elo import get_scores
1516
from codeclash.analysis.significance import calculate_p_value
16-
from codeclash.analysis.viz.utils import MODEL_TO_DISPLAY_NAME
17+
from codeclash.analysis.viz.utils import FONT_BOLD, MODEL_TO_DISPLAY_NAME
1718
from codeclash.constants import LOCAL_LOG_DIR, RESULT_TIE
1819
from codeclash.utils.log import add_file_handler, get_logger
1920

@@ -546,6 +547,9 @@ def create_elo_plots(self, output_dir: Path) -> None:
546547
all_indices = np.argsort(all_elos)[::-1]
547548
player_order = [all_players[i] for i in all_indices]
548549

550+
# Translate to display names
551+
display_names = [MODEL_TO_DISPLAY_NAME.get(p, p) for p in player_order]
552+
549553
# Create mapping from player to y-position
550554
player_to_pos = {p: i for i, p in enumerate(player_order)}
551555

@@ -596,8 +600,8 @@ def create_elo_plots(self, output_dir: Path) -> None:
596600
zorder=3,
597601
)
598602

599-
ax.set_xlabel("Elo Rating", fontsize=11, fontweight="bold")
600-
ax.set_title(game_name, fontsize=14, fontweight="bold")
603+
ax.set_xlabel("Elo Rating", fontproperties=FONT_BOLD, fontsize=14)
604+
ax.set_title(game_name, fontproperties=FONT_BOLD, fontsize=16)
601605
ax.grid(True, axis="x", alpha=0.3)
602606

603607
# Add value labels inside bars near x=0, include ±1σ when available
@@ -606,14 +610,14 @@ def create_elo_plots(self, output_dir: Path) -> None:
606610
label = f"{elo:.0f}"
607611
if has_sigma and sig > 0:
608612
label = f"{elo:.0f} ± {sig:.0f}"
609-
ax.text(20, pos, label, va="center", ha="left", fontsize=13, fontweight="bold", color="white")
613+
ax.text(20, pos, label, va="center", ha="left", fontproperties=FONT_BOLD, fontsize=14, color="white")
610614

611615
# Add reference line at ELO_BASE
612616
ax.axvline(ELO_BASE, color="red", linestyle="--", alpha=0.5, linewidth=1)
613617

614618
# Set y-axis labels on the first subplot
615619
axes[0].set_yticks(range(len(player_order)))
616-
axes[0].set_yticklabels(player_order, fontsize=13)
620+
axes[0].set_yticklabels(display_names, fontproperties=FONT_BOLD, fontsize=14)
617621
axes[0].invert_yaxis()
618622

619623
plt.tight_layout()
@@ -690,10 +694,12 @@ def create_validation_plots(self, output_dir: Path, regularization: float = 0.01
690694
bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.8),
691695
)
692696

693-
ax.set_xlabel("BT Strength", fontsize=10)
694-
ax.set_ylabel("Negative Log-Likelihood", fontsize=10)
695-
ax.set_title(f"{player}", fontsize=11, fontweight="bold")
696-
ax.legend(fontsize=8, loc="upper right")
697+
ax.set_xlabel("BT Strength", fontproperties=FONT_BOLD, fontsize=12)
698+
ax.set_ylabel("Negative Log-Likelihood", fontproperties=FONT_BOLD, fontsize=12)
699+
display_name = MODEL_TO_DISPLAY_NAME.get(player, player)
700+
ax.set_title(display_name, fontproperties=FONT_BOLD, fontsize=14)
701+
legend = ax.legend(prop=FONT_BOLD, fontsize=10, loc="upper right")
702+
legend.set_frame_on(False)
697703
ax.grid(True, alpha=0.3)
698704

699705
# Hide unused subplots
@@ -768,20 +774,24 @@ def _create_rank_matrix_plot(
768774

769775
rank_matrix = (rank_matrix / self.n_bootstrap) * 100
770776

771-
fig, ax = plt.subplots(figsize=(max(10, n * 0.8), max(8, n * 0.6)))
777+
# Translate player names to display names
778+
display_names = [MODEL_TO_DISPLAY_NAME.get(p, p) for p in players]
779+
780+
fig, ax = plt.subplots(figsize=(6, 6))
772781
im = ax.imshow(rank_matrix, cmap="YlOrRd", aspect="auto", vmin=0, vmax=100)
773782

774783
ax.set_xticks(range(n))
775-
ax.set_xticklabels(players, rotation=45, ha="right", fontsize=10)
784+
ax.set_xticklabels(display_names, rotation=45, ha="right", fontproperties=FONT_BOLD, fontsize=10)
776785
ax.set_yticks(range(n))
777-
ax.set_yticklabels([f"Rank {i + 1}" for i in range(n)], fontsize=10)
786+
ax.set_yticklabels([f"Rank {i + 1}" for i in range(n)], fontproperties=FONT_BOLD, fontsize=10)
787+
ax.yaxis.set_minor_locator(AutoMinorLocator())
778788

779-
ax.set_xlabel("Model", fontsize=12, fontweight="bold")
780-
ax.set_ylabel("Rank", fontsize=12, fontweight="bold")
789+
ax.set_xlabel("Model", fontproperties=FONT_BOLD, fontsize=12)
790+
ax.set_ylabel("Rank", fontproperties=FONT_BOLD, fontsize=12)
781791
ax.set_title(
782792
f"Rank Distribution ({self.bootstrap_type} bootstrap, {self.n_bootstrap} samples)",
793+
fontproperties=FONT_BOLD,
783794
fontsize=14,
784-
fontweight="bold",
785795
)
786796

787797
for i in range(n):
@@ -790,11 +800,18 @@ def _create_rank_matrix_plot(
790800
if value > 0:
791801
text_color = "white" if value > 50 else "black"
792802
ax.text(
793-
j, i, f"{value:.1f}%", ha="center", va="center", color=text_color, fontsize=9, fontweight="bold"
803+
j,
804+
i,
805+
f"{value:.1f}%",
806+
ha="center",
807+
va="center",
808+
color=text_color,
809+
fontproperties=FONT_BOLD,
810+
fontsize=12,
794811
)
795812

796813
cbar = plt.colorbar(im, ax=ax)
797-
cbar.set_label("Percentage (%)", fontsize=11, fontweight="bold")
814+
cbar.set_label("Percentage (%)", fontproperties=FONT_BOLD, fontsize=14)
798815

799816
plt.tight_layout()
800817
self._save_plot(output_dir, f"{self.game}_rank_matrix_{self.bootstrap_type}")
@@ -806,7 +823,10 @@ def _create_elo_violin_plot(
806823
"""Create a violin plot showing the distribution of Elo scores for each model."""
807824
elo_data = [elo_samples[p] for p in players]
808825

809-
fig, ax = plt.subplots(figsize=(max(10, len(players) * 0.8), 8))
826+
# Translate player names to display names
827+
display_names = [MODEL_TO_DISPLAY_NAME.get(p, p) for p in players]
828+
829+
fig, ax = plt.subplots(figsize=(6, 6))
810830

811831
parts = ax.violinplot(elo_data, positions=range(len(players)), showmeans=False, showmedians=False, widths=0.7)
812832

@@ -835,15 +855,17 @@ def _create_elo_violin_plot(
835855
)
836856

837857
ax.set_xticks(range(len(players)))
838-
ax.set_xticklabels(players, rotation=45, ha="right", fontsize=10)
839-
ax.set_ylabel("Elo Rating", fontsize=12, fontweight="bold")
858+
ax.set_xticklabels(display_names, rotation=45, ha="right", fontproperties=FONT_BOLD, fontsize=12)
859+
ax.set_ylabel("Elo Rating", fontproperties=FONT_BOLD, fontsize=14)
860+
ax.yaxis.set_minor_locator(AutoMinorLocator())
840861
ax.set_title(
841862
f"Elo Distribution ({self.bootstrap_type} bootstrap, {self.n_bootstrap} samples)",
842-
fontsize=14,
843-
fontweight="bold",
863+
fontproperties=FONT_BOLD,
864+
fontsize=16,
844865
)
845866
ax.grid(True, axis="y", alpha=0.3)
846-
ax.legend(fontsize=10)
867+
legend = ax.legend(prop=FONT_BOLD, fontsize=12)
868+
legend.set_frame_on(False)
847869

848870
plt.tight_layout()
849871
self._save_plot(output_dir, f"{self.game}_elo_violin_{self.bootstrap_type}")
@@ -1062,17 +1084,20 @@ def _plot_results(self, results_by_max_round: dict[int, dict[str, dict[str, floa
10621084
elos_list.append(results_by_max_round[max_round][game_name][player])
10631085

10641086
if max_rounds_list:
1065-
ax.plot(max_rounds_list, elos_list, marker="o", label=player, linewidth=2, markersize=6)
1087+
display_name = MODEL_TO_DISPLAY_NAME.get(player, player)
1088+
ax.plot(max_rounds_list, elos_list, marker="o", label=display_name, linewidth=2, markersize=6)
10661089

1067-
ax.set_xlabel("Max Round", fontsize=12, fontweight="bold")
1068-
ax.set_ylabel("Elo Rating", fontsize=12, fontweight="bold")
1069-
ax.set_title(f"Elo vs Max Rounds: {game_name}", fontsize=14, fontweight="bold")
1090+
ax.set_xlabel("Max Round", fontproperties=FONT_BOLD, fontsize=14)
1091+
ax.set_ylabel("Elo Rating", fontproperties=FONT_BOLD, fontsize=14)
1092+
ax.set_title(f"Elo vs Max Rounds: {game_name}", fontproperties=FONT_BOLD, fontsize=16)
10701093
ax.grid(True, alpha=0.3)
1094+
ax.yaxis.set_minor_locator(AutoMinorLocator())
10711095

10721096
# Add reference line at ELO_BASE
10731097
ax.axhline(ELO_BASE, color="red", linestyle="--", alpha=0.5, linewidth=1, label=f"Base Elo ({ELO_BASE})")
10741098

1075-
ax.legend(fontsize=10, loc="best")
1099+
legend = ax.legend(prop=FONT_BOLD, fontsize=12, loc="best")
1100+
legend.set_frame_on(False)
10761101

10771102
plt.tight_layout()
10781103
safe_game_name = game_name.replace("/", "_").replace(" ", "_")
@@ -1176,17 +1201,20 @@ def _plot_results(self, results_by_round: dict[int, dict[str, dict[str, float]]]
11761201
elos_list.append(results_by_round[round_num][game_name][player])
11771202

11781203
if rounds_list:
1179-
ax.plot(rounds_list, elos_list, marker="o", label=player, linewidth=2, markersize=6)
1204+
display_name = MODEL_TO_DISPLAY_NAME.get(player, player)
1205+
ax.plot(rounds_list, elos_list, marker="o", label=display_name, linewidth=2, markersize=6)
11801206

1181-
ax.set_xlabel("Round", fontsize=12, fontweight="bold")
1182-
ax.set_ylabel("Elo Rating", fontsize=12, fontweight="bold")
1183-
ax.set_title(f"Elo at Specific Round: {game_name}", fontsize=14, fontweight="bold")
1207+
ax.set_xlabel("Round", fontproperties=FONT_BOLD, fontsize=14)
1208+
ax.set_ylabel("Elo Rating", fontproperties=FONT_BOLD, fontsize=14)
1209+
ax.set_title(f"Elo at Specific Round: {game_name}", fontproperties=FONT_BOLD, fontsize=16)
11841210
ax.grid(True, alpha=0.3)
1211+
ax.yaxis.set_minor_locator(AutoMinorLocator())
11851212

11861213
# Add reference line at ELO_BASE
11871214
ax.axhline(ELO_BASE, color="red", linestyle="--", alpha=0.5, linewidth=1, label=f"Base Elo ({ELO_BASE})")
11881215

1189-
ax.legend(fontsize=10, loc="best")
1216+
legend = ax.legend(prop=FONT_BOLD, fontsize=12, loc="best")
1217+
legend.set_frame_on(False)
11901218

11911219
plt.tight_layout()
11921220
safe_game_name = game_name.replace("/", "_").replace(" ", "_")

0 commit comments

Comments
 (0)