Skip to content

Commit 82b5253

Browse files
committed
Enh(viz): Add avg numbers to legend
1 parent 30bd73c commit 82b5253

1 file changed

Lines changed: 54 additions & 7 deletions

File tree

codeclash/analysis/viz/recover_after_loss_streak.py

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,27 @@ def load_tournament_data(log_dir: Path) -> pd.DataFrame:
7474
return pd.DataFrame(data)
7575

7676

77-
def calculate_streak_probabilities(df: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame]:
77+
def calculate_streak_probabilities(df: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
7878
"""Calculate comeback and falldown probabilities after i consecutive losses/wins."""
7979
model_comeback_stats = defaultdict(lambda: defaultdict(lambda: {"opportunities": 0, "successes": 0}))
8080
model_falldown_stats = defaultdict(lambda: defaultdict(lambda: {"opportunities": 0, "successes": 0}))
81+
model_overall_stats = defaultdict(lambda: {"total_rounds": 0, "wins": 0})
8182

8283
for _, row in df.iterrows():
8384
model_a = row["model_a"]
8485
model_b = row["model_b"]
8586

87+
for round_num in range(1, 16):
88+
winner_current = row[f"round_{round_num}_winner"]
89+
90+
# Track overall win rates
91+
model_overall_stats[model_a]["total_rounds"] += 1
92+
model_overall_stats[model_b]["total_rounds"] += 1
93+
if winner_current == model_a:
94+
model_overall_stats[model_a]["wins"] += 1
95+
elif winner_current == model_b:
96+
model_overall_stats[model_b]["wins"] += 1
97+
8698
for round_num in range(2, 16):
8799
winner_current = row[f"round_{round_num}_winner"]
88100

@@ -171,10 +183,21 @@ def calculate_streak_probabilities(df: pd.DataFrame) -> tuple[pd.DataFrame, pd.D
171183

172184
falldown_prob_df = pd.DataFrame(falldown_prob_data).set_index("model")
173185

174-
return comeback_prob_df, falldown_prob_df
186+
# Create overall win rate dataframe
187+
overall_win_rate_data = []
188+
for model in model_overall_stats:
189+
if model_overall_stats[model]["total_rounds"] > 0:
190+
win_rate = model_overall_stats[model]["wins"] / model_overall_stats[model]["total_rounds"]
191+
overall_win_rate_data.append({"model": model, "win_rate": win_rate})
192+
193+
overall_win_rate_df = pd.DataFrame(overall_win_rate_data).set_index("model")
175194

195+
return comeback_prob_df, falldown_prob_df, overall_win_rate_df
176196

177-
def plot_comeback_probabilities(comeback_prob_df: pd.DataFrame, output_file: Path) -> None:
197+
198+
def plot_comeback_probabilities(
199+
comeback_prob_df: pd.DataFrame, overall_win_rate_df: pd.DataFrame, output_file: Path
200+
) -> None:
178201
"""Plot probability of winning after i consecutive losses."""
179202
fig, ax = plt.subplots(figsize=(6, 6))
180203
label_font = FontProperties(fname=FONT_BOLD.get_file(), size=18)
@@ -186,6 +209,7 @@ def plot_comeback_probabilities(comeback_prob_df: pd.DataFrame, output_file: Pat
186209
for idx, model in enumerate(sorted_models):
187210
x_values = []
188211
y_values = []
212+
189213
for i in range(1, 15):
190214
col = f"comeback_prob_after_{i}_losses"
191215
if pd.notna(comeback_prob_df.loc[model, col]):
@@ -194,6 +218,12 @@ def plot_comeback_probabilities(comeback_prob_df: pd.DataFrame, output_file: Pat
194218

195219
if x_values:
196220
display_name = MODEL_TO_DISPLAY_NAME.get(model, model)
221+
222+
# Add overall win rate to legend
223+
if model in overall_win_rate_df.index:
224+
win_rate_pct = overall_win_rate_df.loc[model, "win_rate"] * 100
225+
display_name = f"{display_name} ({win_rate_pct:.0f}%)"
226+
197227
color = MODEL_TO_COLOR.get(model, None)
198228
marker = MARKERS[idx % len(MARKERS)]
199229
ax.plot(
@@ -214,14 +244,20 @@ def plot_comeback_probabilities(comeback_prob_df: pd.DataFrame, output_file: Pat
214244
ax.grid(True, alpha=0.3)
215245
ax.yaxis.set_minor_locator(AutoMinorLocator())
216246
ax.xaxis.set_minor_locator(NullLocator())
247+
248+
# Set x-axis to show integer ticks
249+
ax.set_xticks(range(1, 15))
250+
ax.set_xlim(0.5, max(ax.get_xlim()[1], 14.5))
217251
for label in ax.get_xticklabels() + ax.get_yticklabels():
218252
label.set_fontproperties(FontProperties(fname=FONT_BOLD.get_file(), size=14))
219253
plt.tight_layout()
220254
plt.savefig(output_file, bbox_inches="tight")
221255
print(f"Saved comeback probability plot to {output_file}")
222256

223257

224-
def plot_falldown_probabilities(falldown_prob_df: pd.DataFrame, output_file: Path) -> None:
258+
def plot_falldown_probabilities(
259+
falldown_prob_df: pd.DataFrame, overall_win_rate_df: pd.DataFrame, output_file: Path
260+
) -> None:
225261
"""Plot probability of losing after i consecutive wins."""
226262
fig, ax = plt.subplots(figsize=(6, 6))
227263
label_font = FontProperties(fname=FONT_BOLD.get_file(), size=18)
@@ -233,6 +269,7 @@ def plot_falldown_probabilities(falldown_prob_df: pd.DataFrame, output_file: Pat
233269
for idx, model in enumerate(sorted_models):
234270
x_values = []
235271
y_values = []
272+
236273
for i in range(1, 15):
237274
col = f"falldown_prob_after_{i}_wins"
238275
if pd.notna(falldown_prob_df.loc[model, col]):
@@ -241,6 +278,12 @@ def plot_falldown_probabilities(falldown_prob_df: pd.DataFrame, output_file: Pat
241278

242279
if x_values:
243280
display_name = MODEL_TO_DISPLAY_NAME.get(model, model)
281+
282+
# Add overall loss rate to legend
283+
if model in overall_win_rate_df.index:
284+
loss_rate_pct = (1 - overall_win_rate_df.loc[model, "win_rate"]) * 100
285+
display_name = f"{display_name} ({loss_rate_pct:.0f}%)"
286+
244287
color = MODEL_TO_COLOR.get(model, None)
245288
marker = MARKERS[idx % len(MARKERS)]
246289
ax.plot(
@@ -261,6 +304,10 @@ def plot_falldown_probabilities(falldown_prob_df: pd.DataFrame, output_file: Pat
261304
ax.grid(True, alpha=0.3)
262305
ax.yaxis.set_minor_locator(AutoMinorLocator())
263306
ax.xaxis.set_minor_locator(NullLocator())
307+
308+
# Set x-axis to show integer ticks
309+
ax.set_xticks(range(1, 15))
310+
ax.set_xlim(0.5, max(ax.get_xlim()[1], 14.5))
264311
for label in ax.get_xticklabels() + ax.get_yticklabels():
265312
label.set_fontproperties(FontProperties(fname=FONT_BOLD.get_file(), size=14))
266313
plt.tight_layout()
@@ -277,10 +324,10 @@ def main(log_dir: Path | None = None) -> None:
277324
df = load_tournament_data(log_dir)
278325
print(f"Loaded {len(df)} tournaments")
279326

280-
comeback_prob_df, falldown_prob_df = calculate_streak_probabilities(df)
327+
comeback_prob_df, falldown_prob_df, overall_win_rate_df = calculate_streak_probabilities(df)
281328

282-
plot_comeback_probabilities(comeback_prob_df, ASSETS_DIR / "comeback_probabilities.pdf")
283-
plot_falldown_probabilities(falldown_prob_df, ASSETS_DIR / "falldown_probabilities.pdf")
329+
plot_comeback_probabilities(comeback_prob_df, overall_win_rate_df, ASSETS_DIR / "comeback_probabilities.pdf")
330+
plot_falldown_probabilities(falldown_prob_df, overall_win_rate_df, ASSETS_DIR / "falldown_probabilities.pdf")
284331

285332

286333
if __name__ == "__main__":

0 commit comments

Comments
 (0)