Skip to content

Commit 7ed1bd0

Browse files
committed
Add line_chart_per_round_changes graph
1 parent 29a40cf commit 7ed1bd0

10 files changed

Lines changed: 426 additions & 282 deletions

codeclash/analysis/viz/box_plots_win_streaks.py

Lines changed: 0 additions & 136 deletions
This file was deleted.

codeclash/analysis/viz/cdf_command_diversity.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
from matplotlib import pyplot as plt
4242
from tqdm.auto import tqdm
4343

44+
from codeclash.analysis.viz.utils import ASSETS_DIR, MODEL_TO_COLOR, MODEL_TO_DISPLAY_NAME
4445
from codeclash.constants import LOCAL_LOG_DIR
4546

46-
OUTPUT_FILE = "cdf_command_diversity.png"
47+
OUTPUT_FILE = ASSETS_DIR / "cdf_command_diversity.png"
48+
DATA_CACHE = ASSETS_DIR / "cdf_command_diversity.json"
4749

4850

4951
def shannon_entropy(command_list):
@@ -123,42 +125,49 @@ def main():
123125
"""
124126
model_to_diversity = {}
125127

126-
# Find all tournament directories by looking for metadata.json files
127-
tournaments = [x.parent for x in LOCAL_LOG_DIR.rglob("metadata.json")]
128-
for game_log_folder in tqdm(tournaments):
129-
# Load tournament metadata to get player-to-model mapping
130-
with open(game_log_folder / "metadata.json") as f:
131-
metadata = json.load(f)
132-
try:
133-
# Extract mapping from player name to model name
134-
p2m = {x["name"]: x["config"]["model"]["model_name"].strip("@") for x in metadata["config"]["players"]}
135-
# Initialize diversity list for each model we encounter
136-
for model in p2m.values():
137-
if model not in model_to_diversity:
138-
model_to_diversity[model] = []
139-
except KeyError:
140-
# Skip tournaments with malformed metadata
141-
continue
142-
143-
# Process each player's trajectory files
144-
for name in p2m.keys():
145-
traj_files = (game_log_folder / "players" / name).rglob("*.traj.json")
146-
for traj_file in traj_files:
147-
try:
148-
with open(traj_file) as f:
149-
traj = json.load(f)
150-
151-
# Extract commands and calculate diversity for this session
152-
commands = extract_commands_from_trajectory(traj)
153-
if commands: # Only calculate entropy if there are commands
154-
diversity = shannon_entropy(commands)
155-
model_to_diversity[p2m[name]].append(diversity)
156-
except (json.JSONDecodeError, KeyError):
157-
# Skip malformed trajectory files
158-
continue
159-
160-
# Remove models with no valid data
161-
model_to_diversity = {k: v for k, v in model_to_diversity.items() if v}
128+
if not DATA_CACHE.exists():
129+
# Find all tournament directories by looking for metadata.json files
130+
tournaments = [x.parent for x in LOCAL_LOG_DIR.rglob("metadata.json")]
131+
for game_log_folder in tqdm(tournaments):
132+
# Load tournament metadata to get player-to-model mapping
133+
with open(game_log_folder / "metadata.json") as f:
134+
metadata = json.load(f)
135+
try:
136+
# Extract mapping from player name to model name
137+
p2m = {x["name"]: x["config"]["model"]["model_name"].strip("@") for x in metadata["config"]["players"]}
138+
# Initialize diversity list for each model we encounter
139+
for model in p2m.values():
140+
if model not in model_to_diversity:
141+
model_to_diversity[model] = []
142+
except KeyError:
143+
# Skip tournaments with malformed metadata
144+
continue
145+
146+
# Process each player's trajectory files
147+
for name in p2m.keys():
148+
traj_files = (game_log_folder / "players" / name).rglob("*.traj.json")
149+
for traj_file in traj_files:
150+
try:
151+
with open(traj_file) as f:
152+
traj = json.load(f)
153+
154+
# Extract commands and calculate diversity for this session
155+
commands = extract_commands_from_trajectory(traj)
156+
if commands: # Only calculate entropy if there are commands
157+
diversity = shannon_entropy(commands)
158+
model_to_diversity[p2m[name]].append(diversity)
159+
except (json.JSONDecodeError, KeyError):
160+
# Skip malformed trajectory files
161+
continue
162+
163+
# Remove models with no valid data
164+
model_to_diversity = {k: v for k, v in model_to_diversity.items() if v}
165+
166+
with open(DATA_CACHE, "w") as f:
167+
json.dump(model_to_diversity, f, indent=2)
168+
169+
with open(DATA_CACHE) as f:
170+
model_to_diversity = json.load(f)
162171

163172
# Print summary statistics for each model
164173
print("Command Diversity Summary:")
@@ -170,18 +179,19 @@ def main():
170179
)
171180

172181
# Generate CDF plot comparing all models
173-
plt.figure(figsize=(12, 8))
174-
colors = plt.cm.tab10(range(len(model_to_diversity)))
182+
plt.figure(figsize=(8, 8))
175183

176184
for i, (model, diversities) in enumerate(model_to_diversity.items()):
177185
# Sort diversity values and create cumulative probability values
178186
sorted_diversities = sorted(diversities)
179187
yvals = [i / len(sorted_diversities) for i in range(len(sorted_diversities))]
180188
# Plot as step function (standard for CDFs)
181-
plt.step(sorted_diversities, yvals, label=model, where="post", color=colors[i])
189+
plt.step(
190+
sorted_diversities, yvals, label=MODEL_TO_DISPLAY_NAME[model], where="post", color=MODEL_TO_COLOR[model]
191+
)
182192

183193
plt.xlabel("Command Diversity (Shannon Entropy)")
184-
plt.ylabel("Cumulative Probability")
194+
# plt.ylabel("Cumulative Probability")
185195
plt.title("CDF of Command Diversity by Model\n(Higher entropy = more diverse command usage)")
186196
plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left") # Legend outside plot area
187197
plt.grid(True, alpha=0.3)

codeclash/analysis/viz/cdf_files_edited_per_round.py

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,65 @@
33

44
from matplotlib import pyplot as plt
55
from tqdm.auto import tqdm
6+
from unidiff import PatchSet
67

8+
from codeclash.analysis.viz.utils import ASSETS_DIR, FONT_BOLD, FONT_REG, MODEL_TO_COLOR, MODEL_TO_DISPLAY_NAME
79
from codeclash.constants import LOCAL_LOG_DIR
810

9-
OUTPUT_FILE = "cdf_files_edited_per_round.png"
11+
OUTPUT_FILE = ASSETS_DIR / "cdf_files_edited_per_round.png"
12+
DATA_CACHE = ASSETS_DIR / "cdf_files_edited_per_round.json"
1013

1114

1215
def main():
1316
model_to_num_files = {}
1417

15-
tournaments = [x.parent for x in LOCAL_LOG_DIR.rglob("metadata.json")]
16-
for game_log_folder in tqdm(tournaments):
17-
with open(game_log_folder / "metadata.json") as f:
18-
metadata = json.load(f)
19-
try:
20-
p2m = {x["name"]: x["config"]["model"]["model_name"].strip("@") for x in metadata["config"]["players"]}
21-
for model in p2m.values():
22-
if model not in model_to_num_files:
23-
model_to_num_files[model] = []
24-
except KeyError:
25-
continue
26-
27-
for name in p2m.keys():
28-
changes_files = (game_log_folder / "players" / name).rglob("changes_r*.json")
29-
for changes_file in changes_files:
30-
with open(changes_file) as f:
31-
changes = json.load(f)
32-
num_files = len(changes["modified_files"])
33-
model_to_num_files[p2m[name]].append(num_files)
18+
if not DATA_CACHE.exists():
19+
tournaments = [x.parent for x in LOCAL_LOG_DIR.rglob("metadata.json")]
20+
for game_log_folder in tqdm(tournaments):
21+
with open(game_log_folder / "metadata.json") as f:
22+
metadata = json.load(f)
23+
try:
24+
p2m = {x["name"]: x["config"]["model"]["model_name"].strip("@") for x in metadata["config"]["players"]}
25+
for model in p2m.values():
26+
if model not in model_to_num_files:
27+
model_to_num_files[model] = []
28+
except KeyError:
29+
continue
30+
31+
for name in p2m.keys():
32+
changes_files = (game_log_folder / "players" / name).rglob("changes_r*.json")
33+
for changes_file in changes_files:
34+
with open(changes_file) as f:
35+
changes = json.load(f)
36+
num_files = len(PatchSet(changes["incremental_diff"]))
37+
model_to_num_files[p2m[name]].append(num_files)
38+
39+
with open(DATA_CACHE, "w") as f:
40+
json.dump(model_to_num_files, f, indent=2)
41+
42+
with open(DATA_CACHE) as f:
43+
model_to_num_files = json.load(f)
3444

3545
# Plot CDF
36-
plt.figure(figsize=(10, 6))
46+
plt.figure(figsize=(8, 8))
3747
for model, files_edited in model_to_num_files.items():
3848
sorted_files_edited = sorted(files_edited)
3949
yvals = [i / len(sorted_files_edited) for i in range(len(sorted_files_edited))]
40-
plt.step(sorted_files_edited, yvals, label=model, where="post")
50+
plt.step(
51+
sorted_files_edited, yvals, label=MODEL_TO_DISPLAY_NAME[model], where="post", color=MODEL_TO_COLOR[model]
52+
)
4153

42-
plt.xlabel("Files Edited per Round")
43-
plt.ylabel("Cumulative Probability")
44-
plt.title("CDF of Files Edited per Round by Model")
45-
plt.legend()
54+
LIM = 20
55+
plt.xlim(0, LIM) # Limit x-axis to 40 for better visibility
56+
plt.xticks(range(0, LIM + 1, 5), fontsize=12, fontproperties=FONT_REG)
57+
plt.yticks([i / 10 for i in range(11)], [f"{i * 10}%" for i in range(11)], fontsize=12, fontproperties=FONT_REG)
58+
plt.xlabel("Files Edited per Round", fontproperties=FONT_BOLD, fontsize=18)
59+
# plt.ylabel("Cumulative Probability", fontproperties=FONT_BOLD, fontsize=18)
60+
# plt.title("CDF of Files Edited per Round by Model")
61+
FONT_BOLD.set_size(14)
62+
plt.legend(prop=FONT_BOLD)
4663
plt.grid(True)
47-
plt.savefig(OUTPUT_FILE)
64+
plt.savefig(OUTPUT_FILE, dpi=300, bbox_inches="tight")
4865
print(f"Saved CDF plot to {OUTPUT_FILE}")
4966

5067

0 commit comments

Comments
 (0)