Cédric P. Legendre rounakbende commited on
Commit
7ddc8cb
·
unverified ·
1 Parent(s): 9472758

Add efficiency, coding, generalist, and benchmark matrix views (#25)

Browse files

* Add analytics views and benchmark matrices

* Add Bradley-Terry rankings tab with filters for benchmarks, models, harnesses, and rank-by metric

* Address CR: fix eqvdata population, empty filter handling, and per-table error isolation

* Address leaderboard review feedback

* Round trade-off table values to one decimal

* Round trade-off table values to one decimal

* Round trade-off metrics to two decimals

* Round trade-off metrics to two decimals

---------

Co-authored-by: rounakbende10 <rounakbende@gmail.com>

app.py CHANGED
@@ -43,14 +43,31 @@ def patch_gradio_leaderboard():
43
  patch_gradio_leaderboard()
44
 
45
  import gradio as gr
 
46
  from apscheduler.schedulers.background import BackgroundScheduler
47
  from gradio_leaderboard import ColumnFilter, Leaderboard, SelectColumns
48
  from huggingface_hub import HfApi
49
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  from src.charts import (
51
  clean_markdown_link,
 
52
  create_leaderboard_benchmark_plot,
 
53
  create_performance_vs_resource_plot,
 
 
54
  )
55
  from src.display.text_blocks import (
56
  HOW_TO_USE_TEXT,
@@ -63,41 +80,49 @@ from src.leaderboard import (
63
  get_benchmark_names,
64
  get_benchmark_run_df,
65
  get_efficiency_df,
66
- get_token_efficiency_table_df,
67
  )
 
68
 
69
  REPO_ID = "taagarwa/coding-agent-leaderboard"
70
  TOKEN = os.environ.get("HF_TOKEN")
71
  API = HfApi(token=TOKEN)
72
  COLOR_BY_CHOICES = ["Model", "Harness"]
73
  EFFICIENCY_COLOR_BY_CHOICES = ["Model", "Harness"]
74
- COLOR_PALETTE_CHOICES = [
75
- "Citrus",
76
- "Okabe-Ito",
77
- "High contrast",
78
- "Rainbow",
79
- "Grayscale",
80
- "Viridis",
81
- "Plasma",
82
- "Cividis",
83
- ]
84
  DEFAULT_COLOR_PALETTE = "Citrus"
85
  PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
86
  DEFAULT_PLOT_BACKGROUND = "Dark"
87
  RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420
 
88
  RESPONSIVE_PLOT_CSS = f"""
89
  <style>
90
  .responsive-plot {{
91
- overflow-x: auto;
92
  width: 100%;
 
93
  min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
94
  }}
95
  .responsive-plot .plot-container,
96
  .responsive-plot .js-plotly-plot,
97
- .responsive-plot .plotly-graph-div {{
 
98
  width: 100% !important;
 
 
99
  min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
100
  }}
 
 
 
 
 
 
 
 
 
 
 
 
101
  </style>
102
  """
103
  FORCE_DARK_MODE_HEAD = (
@@ -108,7 +133,36 @@ FORCE_DARK_MODE_HEAD = (
108
  if (!url.searchParams.has("__theme")) {
109
  url.searchParams.set("__theme", "dark");
110
  window.location.replace(url.toString());
 
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  })();
113
  </script>
114
  """
@@ -124,6 +178,9 @@ BENCHMARK_NAMES = get_benchmark_names()
124
  DEFAULT_BENCHMARK = BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None
125
  BENCHMARK_RUN_DF = get_benchmark_run_df()
126
  ANALYSIS_DF = get_analysis_df()
 
 
 
127
 
128
 
129
  def render_leaderboard_benchmark_plot(
@@ -141,7 +198,6 @@ def render_leaderboard_benchmark_plot(
141
  )
142
 
143
 
144
-
145
  def render_efficiency(
146
  benchmark_name,
147
  token_metric,
@@ -157,12 +213,11 @@ def render_efficiency(
157
  resource_metric=token_metric,
158
  analysis_df=ANALYSIS_DF,
159
  )
160
- table_df = get_token_efficiency_table_df(
161
- benchmark_name=benchmark_name,
162
- analysis_df=ANALYSIS_DF,
163
- )
164
  exclusion_count = plot_df.attrs.get("exclusion_count", 0)
165
- note = f"{exclusion_count} runs excluded for this benchmark because {token_metric.lower()} was missing or non-positive."
 
 
 
166
  figure = create_performance_vs_resource_plot(
167
  plot_df,
168
  resource_metric=token_metric,
@@ -173,34 +228,338 @@ def render_efficiency(
173
  palette_name=color_palette,
174
  background_name=plot_background,
175
  )
176
- return figure, table_df, note
177
 
178
 
179
- def build_header_html(df):
180
- n_results = len(df)
181
- n_models = df["Model"].nunique()
182
- n_harnesses = df["Harness"].apply(clean_markdown_link).nunique()
183
- n_benchmarks = df["Benchmark"].apply(clean_markdown_link).nunique()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  return f"""
186
  <base target="_blank">
187
  <div style="padding: 1.5rem 0.5rem 1rem 0.5rem; text-align: left; color: #F8FAFC;">
188
- <h1 style="margin: 0 0 0.5rem 0; font-size: 2rem;">
189
- Coding Agent Leaderboard
190
- </h1>
191
  <div style="height: 4px; border-radius: 2px; background: linear-gradient(90deg, #84cc16, #f59e0b); margin-bottom: 0.75rem;"></div>
192
- <p style="margin: 0 0 0.75rem 0; font-size: 1.1rem; color: #E5E7EB;">
193
- Compare coding agents across models and harnesses
 
194
  </p>
195
- <div style="display: flex; gap: 0.5rem; flex-wrap: wrap; font-size: 0.95rem; color: #CBD5E1;">
196
- <span style="font-weight: 600;">{n_results} Results</span>
197
- <span>·</span>
198
- <span style="font-weight: 600;">{n_models} Models</span>
199
- <span>·</span>
200
- <span style="font-weight: 600;">{n_harnesses} Harnesses</span>
201
- <span>·</span>
202
- <span style="font-weight: 600;">{n_benchmarks} Benchmarks</span>
203
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  </div>
205
  """
206
 
@@ -245,155 +604,452 @@ def init_benchmark_runs(dataframe):
245
  )
246
 
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  demo = gr.Blocks(theme="citrus", head=FORCE_DARK_MODE_HEAD)
249
  with demo:
 
250
  gr.HTML(build_header_html(BENCHMARK_RUN_DF))
251
- gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
252
 
253
  with gr.Tabs():
254
- with gr.Tab("🏆 Leaderboard"):
255
- gr.Markdown("### Benchmark scores")
 
 
 
 
256
  with gr.Row():
257
- leaderboard_color_by = gr.Radio(
258
- choices=COLOR_BY_CHOICES,
259
- value="Model",
260
- label="Color by",
261
- elem_classes="color-control",
262
- )
263
- leaderboard_palette = gr.Dropdown(
264
- choices=COLOR_PALETTE_CHOICES,
265
- value=DEFAULT_COLOR_PALETTE,
266
- label="Color palette",
267
- elem_classes="color-control",
268
- )
269
- leaderboard_background = gr.Dropdown(
270
- choices=PLOT_BACKGROUND_CHOICES,
271
- value=DEFAULT_PLOT_BACKGROUND,
272
- label="Image background",
273
- elem_classes="color-control",
274
- )
275
-
276
- leaderboard_plots = []
277
- for benchmark_name in BENCHMARK_NAMES:
278
- gr.Markdown(f"#### {benchmark_name}")
279
- plot = gr.Plot(
280
- value=render_leaderboard_benchmark_plot(
281
- benchmark_name,
282
- "Model",
283
- DEFAULT_COLOR_PALETTE,
284
- DEFAULT_PLOT_BACKGROUND,
285
- ),
286
- show_label=False,
287
- elem_classes="responsive-plot",
288
- )
289
- leaderboard_plots.append((benchmark_name, plot))
290
-
291
- for benchmark_name, plot in leaderboard_plots:
292
- for control in (leaderboard_color_by, leaderboard_palette, leaderboard_background):
 
 
 
 
 
 
 
 
 
 
293
  control.change(
294
- fn=lambda color_by, palette, background, name=benchmark_name: render_leaderboard_benchmark_plot(
295
- name, color_by, palette, background
296
- ),
297
- inputs=[leaderboard_color_by, leaderboard_palette, leaderboard_background],
298
  outputs=plot,
299
  )
300
 
301
- with gr.Tab("⚡ Efficiency") as efficiency_tab:
302
  gr.Markdown(
303
- "### Efficiency\n"
304
- "Compare score with resource use within one benchmark. The x-axis can show total tokens, "
305
- "cost per task, or agent execution time per task. The dashed Pareto frontier connects runs "
306
- "for which no other displayed run uses an equal or lower amount of the selected resource "
307
- "while achieving an equal or higher score. Tokens Per Solved Task remains in the ranking "
308
- "table as a reference metric."
309
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  with gr.Row():
311
  efficiency_benchmark = gr.Dropdown(
312
- choices=BENCHMARK_NAMES,
313
- value=BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None,
314
- label="Benchmark",
315
  )
316
  efficiency_metric = gr.Dropdown(
317
- choices=list(EFFICIENCY_RESOURCE_METRICS),
318
- value="Total tokens",
319
- label="Resource metric",
320
  )
321
  efficiency_color_by = gr.Radio(
322
- choices=EFFICIENCY_COLOR_BY_CHOICES,
323
- value="Model",
324
- label="Color by",
325
  )
326
  efficiency_scale = gr.Radio(choices=["Log", "Linear"], value="Log", label="X-axis scale")
327
  with gr.Row():
328
  efficiency_pareto = gr.Checkbox(value=True, label="Show Pareto frontier")
329
  efficiency_labels = gr.Checkbox(value=False, label="Show point labels")
330
  efficiency_palette = gr.Dropdown(
331
- choices=COLOR_PALETTE_CHOICES,
332
- value=DEFAULT_COLOR_PALETTE,
333
- label="Color palette",
334
  )
335
  efficiency_background = gr.Dropdown(
336
- choices=PLOT_BACKGROUND_CHOICES,
337
- value=DEFAULT_PLOT_BACKGROUND,
338
- label="Image background",
339
  )
340
-
341
  initial_efficiency = render_efficiency(
342
- BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None,
343
- "Total tokens",
344
- "Model",
345
- "Log",
346
- True,
347
- False,
348
- DEFAULT_COLOR_PALETTE,
349
- DEFAULT_PLOT_BACKGROUND,
350
  )
351
- efficiency_note = gr.Markdown(initial_efficiency[2])
352
  efficiency_plot = gr.Plot(
353
- value=initial_efficiency[0],
354
- show_label=False,
355
- elem_classes="responsive-plot",
356
  )
357
- gr.Markdown("#### Efficiency ranking")
358
- efficiency_table = gr.Dataframe(
359
- value=initial_efficiency[1],
360
- interactive=False,
361
- show_label=False,
362
- )
363
-
364
  efficiency_controls = [
365
- efficiency_benchmark,
366
- efficiency_metric,
367
- efficiency_color_by,
368
- efficiency_scale,
369
- efficiency_pareto,
370
- efficiency_labels,
371
- efficiency_palette,
372
- efficiency_background,
373
  ]
374
  for control in efficiency_controls:
375
  control.change(
376
  fn=render_efficiency,
377
  inputs=efficiency_controls,
378
- outputs=[efficiency_plot, efficiency_table, efficiency_note],
379
  )
380
 
381
- # Gradio initially lays out hidden tabs without reliable dimensions. Re-render
382
- # once Efficiency becomes visible so Plotly can autosize against the real
383
- # container instead of keeping the hidden-tab geometry.
384
- efficiency_tab.select(
385
- fn=render_efficiency,
386
- inputs=efficiency_controls,
387
- outputs=[efficiency_plot, efficiency_table, efficiency_note],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
- with gr.Tab("🏃 Benchmark Runs"):
391
- benchmark_runs = init_benchmark_runs(BENCHMARK_RUN_DF)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
- with gr.Tab("ℹ️ About"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
395
  gr.Markdown(HOW_TO_USE_TEXT, elem_classes="markdown-text")
396
 
 
397
  scheduler = BackgroundScheduler()
398
  scheduler.add_job(restart_space, "interval", seconds=1800)
399
  scheduler.start()
 
43
  patch_gradio_leaderboard()
44
 
45
  import gradio as gr
46
+ import pandas as pd
47
  from apscheduler.schedulers.background import BackgroundScheduler
48
  from gradio_leaderboard import ColumnFilter, Leaderboard, SelectColumns
49
  from huggingface_hub import HfApi
50
 
51
+ from src.analytics import (
52
+ MATRIX_METRICS,
53
+ RANKING_METRICS,
54
+ TRADEOFF_METRICS,
55
+ benchmarks_for_category,
56
+ coverage_summary,
57
+ cross_benchmark_ranking_df,
58
+ enrich_analysis_df,
59
+ filter_category,
60
+ matrix_df,
61
+ ranking_df,
62
+ )
63
  from src.charts import (
64
  clean_markdown_link,
65
+ create_coverage_matrix_plot,
66
  create_leaderboard_benchmark_plot,
67
+ create_matrix_plot,
68
  create_performance_vs_resource_plot,
69
+ create_ranking_plot,
70
+ create_tradeoff_plot,
71
  )
72
  from src.display.text_blocks import (
73
  HOW_TO_USE_TEXT,
 
80
  get_benchmark_names,
81
  get_benchmark_run_df,
82
  get_efficiency_df,
 
83
  )
84
+ from src.rankings import RANK_BY_OPTIONS, load_and_rank
85
 
86
  REPO_ID = "taagarwa/coding-agent-leaderboard"
87
  TOKEN = os.environ.get("HF_TOKEN")
88
  API = HfApi(token=TOKEN)
89
  COLOR_BY_CHOICES = ["Model", "Harness"]
90
  EFFICIENCY_COLOR_BY_CHOICES = ["Model", "Harness"]
91
+ COLOR_PALETTE_CHOICES = ["Citrus", "Okabe-Ito", "High contrast", "Rainbow"]
 
 
 
 
 
 
 
 
 
92
  DEFAULT_COLOR_PALETTE = "Citrus"
93
  PLOT_BACKGROUND_CHOICES = ["Dark", "White"]
94
  DEFAULT_PLOT_BACKGROUND = "Dark"
95
  RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420
96
+ TABLE_MAX_HEIGHT_PX = 720
97
  RESPONSIVE_PLOT_CSS = f"""
98
  <style>
99
  .responsive-plot {{
100
+ overflow-x: hidden;
101
  width: 100%;
102
+ min-width: 0;
103
  min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
104
  }}
105
  .responsive-plot .plot-container,
106
  .responsive-plot .js-plotly-plot,
107
+ .responsive-plot .plotly-graph-div,
108
+ .responsive-plot .svg-container {{
109
  width: 100% !important;
110
+ max-width: 100% !important;
111
+ min-width: 0 !important;
112
  min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px;
113
  }}
114
+ .summary-cards {{
115
+ display: grid;
116
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
117
+ gap: 0.6rem;
118
+ }}
119
+ .summary-card {{
120
+ border: 1px solid rgba(203,213,225,.18);
121
+ border-radius: 10px;
122
+ padding: .8rem;
123
+ background: rgba(39,33,30,.7);
124
+ }}
125
+ .summary-card strong {{ font-size: 1.35rem; display:block; }}
126
  </style>
127
  """
128
  FORCE_DARK_MODE_HEAD = (
 
133
  if (!url.searchParams.has("__theme")) {
134
  url.searchParams.set("__theme", "dark");
135
  window.location.replace(url.toString());
136
+ return;
137
  }
138
+
139
+ // Plotly often measures hidden Gradio tabs before they are visible. Resize every
140
+ // visible chart when a tab opens, its container changes size, or the window resizes.
141
+ const resizeVisiblePlots = () => {
142
+ if (!window.Plotly) return;
143
+ document.querySelectorAll('.responsive-plot .js-plotly-plot').forEach((plot) => {
144
+ if (plot.offsetParent !== null) window.Plotly.Plots.resize(plot);
145
+ });
146
+ };
147
+ const scheduleResize = () => {
148
+ requestAnimationFrame(() => {
149
+ resizeVisiblePlots();
150
+ setTimeout(resizeVisiblePlots, 80);
151
+ setTimeout(resizeVisiblePlots, 250);
152
+ });
153
+ };
154
+ window.addEventListener('resize', scheduleResize);
155
+ document.addEventListener('click', scheduleResize, true);
156
+ document.addEventListener('DOMContentLoaded', () => {
157
+ const observer = new ResizeObserver(scheduleResize);
158
+ document.querySelectorAll('.responsive-plot').forEach((el) => observer.observe(el));
159
+ const mutation = new MutationObserver(() => {
160
+ document.querySelectorAll('.responsive-plot').forEach((el) => observer.observe(el));
161
+ scheduleResize();
162
+ });
163
+ mutation.observe(document.body, {childList: true, subtree: true});
164
+ scheduleResize();
165
+ });
166
  })();
167
  </script>
168
  """
 
178
  DEFAULT_BENCHMARK = BENCHMARK_NAMES[0] if BENCHMARK_NAMES else None
179
  BENCHMARK_RUN_DF = get_benchmark_run_df()
180
  ANALYSIS_DF = get_analysis_df()
181
+ PR2_DF = enrich_analysis_df(ANALYSIS_DF)
182
+ CODING_BENCHMARKS = benchmarks_for_category(PR2_DF, "Coding")
183
+ GENERALIST_BENCHMARKS = benchmarks_for_category(PR2_DF, "Generalist")
184
 
185
 
186
  def render_leaderboard_benchmark_plot(
 
198
  )
199
 
200
 
 
201
  def render_efficiency(
202
  benchmark_name,
203
  token_metric,
 
213
  resource_metric=token_metric,
214
  analysis_df=ANALYSIS_DF,
215
  )
 
 
 
 
216
  exclusion_count = plot_df.attrs.get("exclusion_count", 0)
217
+ note = (
218
+ f"{exclusion_count} runs excluded for this benchmark because "
219
+ f"{token_metric.lower()} was missing or non-positive."
220
+ )
221
  figure = create_performance_vs_resource_plot(
222
  plot_df,
223
  resource_metric=token_metric,
 
228
  palette_name=color_palette,
229
  background_name=plot_background,
230
  )
231
+ return figure, note
232
 
233
 
234
+ PAGE_TABLE_COLUMNS = [
235
+ "Model",
236
+ "Harness",
237
+ "Benchmark",
238
+ "Score (%)",
239
+ "Within-Benchmark Rank",
240
+ "Within-Benchmark Percentile",
241
+ "Total Tokens Per Task",
242
+ "Cost Per Task",
243
+ "Total Time Per Task",
244
+ "Agent Time Per Task",
245
+ "Execution Error Rate (%)",
246
+ "Tokens Per Successful Task",
247
+ "Cost Per Successful Task",
248
+ "Time Per Successful Task",
249
+ ]
250
+
251
+ PAGE_TABLE_SORT_COLUMNS = {
252
+ "Score": "Score (%)",
253
+ "Rank": "Within-Benchmark Rank",
254
+ "Percentile": "Within-Benchmark Percentile",
255
+ "Total tokens": "Total Tokens Per Task",
256
+ "Cost": "Cost Per Task",
257
+ "Response time": "Total Time Per Task",
258
+ "Agent time": "Agent Time Per Task",
259
+ "Execution error rate": "Execution Error Rate (%)",
260
+ }
261
+
262
+
263
+ def render_page_table(benchmark, sort_metric="Score", sort_order="Largest value first"):
264
+ """One compact table per page with all metrics relevant to ranking/trade-off views."""
265
+ data = PR2_DF.copy()
266
+ if benchmark and benchmark != "All benchmarks":
267
+ data = data[data["Benchmark"] == benchmark].copy()
268
+ columns = [column for column in PAGE_TABLE_COLUMNS if column in data.columns]
269
+ data = data[columns].copy()
270
+ if data.empty:
271
+ return data
272
+
273
+ data["_agent"] = data["Model"].astype(str) + " / " + data["Harness"].astype(str)
274
+ if sort_order == "Alphabetical (A–Z)":
275
+ data = data.sort_values(["_agent", "Benchmark"], ascending=[True, True], kind="mergesort")
276
+ elif sort_order == "Alphabetical (Z–A)":
277
+ data = data.sort_values(["_agent", "Benchmark"], ascending=[False, True], kind="mergesort")
278
+ else:
279
+ sort_column = PAGE_TABLE_SORT_COLUMNS.get(sort_metric, "Score (%)")
280
+ values = pd.to_numeric(data.get(sort_column), errors="coerce")
281
+ data["_sort_value"] = values
282
+ ascending = sort_order == "Lowest value first"
283
+ data = data.sort_values(
284
+ ["_sort_value", "_agent", "Benchmark"],
285
+ ascending=[ascending, True, True],
286
+ na_position="last",
287
+ kind="mergesort",
288
+ ).drop(columns="_sort_value")
289
+ data = data.drop(columns="_agent").reset_index(drop=True)
290
+
291
+ # Metrics displayed to 2 decimal places
292
+ decimal_columns = [
293
+ "Score (%)",
294
+ "Within-Benchmark Percentile",
295
+ "Execution Error Rate (%)",
296
+ "Cost Per Successful Task",
297
+ ]
298
+
299
+ for column in decimal_columns:
300
+ if column in data.columns:
301
+ data[column] = pd.to_numeric(data[column], errors="coerce").round(2)
302
+
303
+ # Token and time metrics displayed as whole numbers
304
+ whole_number_columns = [
305
+ "Total Tokens Per Task",
306
+ "Total Time Per Task",
307
+ "Agent Time Per Task",
308
+ "Tokens Per Successful Task",
309
+ "Time Per Successful Task",
310
+ ]
311
+
312
+ for column in whole_number_columns:
313
+ if column in data.columns:
314
+ data[column] = pd.to_numeric(data[column], errors="coerce").round(0)
315
+
316
+ return data
317
 
318
+
319
+ def render_ranking(
320
+ metric,
321
+ benchmark,
322
+ color_by="Model",
323
+ color_palette=DEFAULT_COLOR_PALETTE,
324
+ plot_background=DEFAULT_PLOT_BACKGROUND,
325
+ sort_order="Largest value first",
326
+ ):
327
+ def sort_table(table, metric_column, higher_is_better):
328
+ if table is None or table.empty:
329
+ return table
330
+ work = table.copy()
331
+ work["_agent"] = work["Model"].astype(str) + " / " + work["Harness"].astype(str)
332
+ if sort_order == "Alphabetical (A–Z)":
333
+ work = work.sort_values("_agent", ascending=True, kind="mergesort")
334
+ elif sort_order == "Alphabetical (Z–A)":
335
+ work = work.sort_values("_agent", ascending=False, kind="mergesort")
336
+ elif sort_order == "Lowest value first":
337
+ work = work.sort_values(
338
+ [metric_column, "_agent"],
339
+ ascending=[True, True],
340
+ kind="mergesort",
341
+ )
342
+ else:
343
+ work = work.sort_values(
344
+ [metric_column, "_agent"],
345
+ ascending=[False, True],
346
+ kind="mergesort",
347
+ )
348
+ return work.drop(columns="_agent").reset_index(drop=True)
349
+
350
+ if metric == "Score" and benchmark == "All benchmarks":
351
+ table = cross_benchmark_ranking_df(PR2_DF, minimum_coverage=0.5)
352
+ table = sort_table(table, "Normalized Performance", True)
353
+ plot_df = table.rename(columns={"Normalized Performance": "_metric"}).copy()
354
+ if not plot_df.empty:
355
+ plot_df["Benchmark"] = "Normalized across benchmarks"
356
+ figure = create_ranking_plot(
357
+ plot_df,
358
+ "_metric",
359
+ "Normalized performance (0–100)",
360
+ True,
361
+ color_by=color_by,
362
+ palette_name=color_palette,
363
+ background_name=plot_background,
364
+ sort_order=sort_order,
365
+ )
366
+ return figure, table
367
+
368
+ table = ranking_df(PR2_DF, metric, benchmark=benchmark)
369
+ spec = RANKING_METRICS[metric]
370
+ table = sort_table(table, spec.column, spec.higher_is_better)
371
+ figure = create_ranking_plot(
372
+ table,
373
+ spec.column,
374
+ spec.label,
375
+ spec.higher_is_better,
376
+ color_by=color_by,
377
+ palette_name=color_palette,
378
+ background_name=plot_background,
379
+ sort_order=sort_order,
380
+ )
381
+ return figure, table
382
+
383
+
384
+ TRADEOFF_PAIRS = {
385
+ "Score vs cost": ("Cost Per Task", "Score (%)", "Cost per task (USD)", "Score (%)", True, True),
386
+ "Score vs tokens": ("Total Tokens Per Task", "Score (%)", "Total tokens per task", "Score (%)", True, True),
387
+ "Score vs total time": ("Total Time Per Task", "Score (%)", "Total time per task (seconds)", "Score (%)", True, True),
388
+ "Score vs agent time": ("Agent Time Per Task", "Score (%)", "Agent time per task (seconds)", "Score (%)", True, True),
389
+ "Score vs execution error rate": (
390
+ "Execution Error Rate (%)", "Score (%)", "Execution error rate (%)", "Score (%)", True, True
391
+ ),
392
+ "Tokens vs cost": ("Total Tokens Per Task", "Cost Per Task", "Total tokens per task", "Cost per task (USD)", True, False),
393
+ "Cost vs total time": ("Cost Per Task", "Total Time Per Task", "Cost per task (USD)", "Total time per task (seconds)", True, False),
394
+ }
395
+
396
+
397
+ def render_tradeoff(
398
+ pair,
399
+ benchmark,
400
+ color_by,
401
+ show_labels,
402
+ x_scale,
403
+ show_pareto,
404
+ color_palette,
405
+ plot_background,
406
+ ):
407
+ x_column, y_column, x_label, y_label, lower_x, higher_y = TRADEOFF_PAIRS[pair]
408
+ data = PR2_DF[PR2_DF["Benchmark"] == benchmark].copy()
409
+ figure = create_tradeoff_plot(
410
+ data,
411
+ x_column=x_column,
412
+ y_column=y_column,
413
+ x_label=x_label,
414
+ y_label=y_label,
415
+ color_by=color_by,
416
+ show_labels=show_labels,
417
+ x_scale=x_scale,
418
+ show_pareto_frontier=show_pareto,
419
+ lower_x_is_better=lower_x,
420
+ higher_y_is_better=higher_y,
421
+ palette_name=color_palette,
422
+ background_name=plot_background,
423
+ )
424
+ valid = data[[x_column, y_column]].apply(pd.to_numeric, errors="coerce").dropna()
425
+ note = f"{len(valid)} comparable runs shown for {benchmark}; missing metrics are omitted, not treated as zero."
426
+ return figure, note
427
+
428
+
429
+ def render_matrix(
430
+ metric,
431
+ category,
432
+ include_incomplete,
433
+ sort_by,
434
+ show_values,
435
+ reverse_scale,
436
+ plot_background,
437
+ ):
438
+ category_filter = None if category == "All" else category
439
+ matrix = matrix_df(
440
+ PR2_DF,
441
+ metric,
442
+ category=category_filter,
443
+ include_incomplete=include_incomplete,
444
+ sort_by=sort_by,
445
+ )
446
+ if metric == "Coverage":
447
+ return create_coverage_matrix_plot(matrix, plot_background)
448
+ spec = MATRIX_METRICS[metric]
449
+ display_matrix = None
450
+ display_metric_label = None
451
+ if metric == "Within-benchmark percentile":
452
+ display_matrix = matrix_df(
453
+ PR2_DF,
454
+ "Score",
455
+ category=category_filter,
456
+ include_incomplete=include_incomplete,
457
+ sort_by=sort_by,
458
+ ).reindex(index=matrix.index, columns=matrix.columns)
459
+ display_metric_label = "Benchmark score (%)"
460
+ return create_matrix_plot(
461
+ matrix,
462
+ f"{metric} matrix",
463
+ spec.label,
464
+ higher_is_better=spec.higher_is_better,
465
+ show_values=show_values,
466
+ reverse_scale=reverse_scale,
467
+ background_name=plot_background,
468
+ display_matrix=display_matrix,
469
+ display_metric_label=display_metric_label,
470
+ )
471
+
472
+
473
+ def category_leaderboard(category):
474
+ data = filter_category(PR2_DF, category)
475
+ if data.empty:
476
+ return pd.DataFrame()
477
+ normalized = cross_benchmark_ranking_df(data, minimum_coverage=0)
478
+ return normalized
479
+
480
+
481
+ def render_category_tradeoff(category, benchmark, metric, color_by, show_labels, plot_background):
482
+ data = filter_category(PR2_DF, category)
483
+ data = data[data["Benchmark"] == benchmark]
484
+ spec = TRADEOFF_METRICS[metric]
485
+ return create_tradeoff_plot(
486
+ data,
487
+ x_column=spec.column,
488
+ y_column="Score (%)",
489
+ x_label=spec.label,
490
+ y_label="Score (%)",
491
+ color_by=color_by,
492
+ show_labels=show_labels,
493
+ show_pareto_frontier=metric != "Execution error rate",
494
+ lower_x_is_better=True,
495
+ higher_y_is_better=True,
496
+ background_name=plot_background,
497
+ )
498
+
499
+
500
+ def render_category_matrix(category, metric, show_values, plot_background):
501
+ matrix = matrix_df(PR2_DF, metric, category=category, include_incomplete=True)
502
+ if metric == "Coverage":
503
+ return create_coverage_matrix_plot(matrix, plot_background)
504
+ spec = MATRIX_METRICS[metric]
505
+ display_matrix = None
506
+ display_metric_label = None
507
+ if metric == "Within-benchmark percentile":
508
+ display_matrix = matrix_df(
509
+ PR2_DF, "Score", category=category, include_incomplete=True
510
+ ).reindex(index=matrix.index, columns=matrix.columns)
511
+ display_metric_label = "Benchmark score (%)"
512
+ return create_matrix_plot(
513
+ matrix,
514
+ f"{category} — {metric}",
515
+ spec.label,
516
+ higher_is_better=spec.higher_is_better,
517
+ show_values=show_values,
518
+ background_name=plot_background,
519
+ display_matrix=display_matrix,
520
+ display_metric_label=display_metric_label,
521
+ )
522
+
523
+
524
+ def build_header_html(df):
525
+ summary = coverage_summary(PR2_DF)
526
  return f"""
527
  <base target="_blank">
528
  <div style="padding: 1.5rem 0.5rem 1rem 0.5rem; text-align: left; color: #F8FAFC;">
529
+ <h1 style="margin: 0 0 0.5rem 0; font-size: 2rem;">Coding Agent Leaderboard</h1>
 
 
530
  <div style="height: 4px; border-radius: 2px; background: linear-gradient(90deg, #84cc16, #f59e0b); margin-bottom: 0.75rem;"></div>
531
+ <p style="margin: 0 0 0.9rem 0; font-size: 1.1rem; color: #E5E7EB;">
532
+ Performance, efficiency, coverage, and reliability across coding-agent benchmarks.
533
+ Each result is one model + harness run on one benchmark.
534
  </p>
535
+ <div class="summary-cards">
536
+ <div class="summary-card"><strong>{summary['results']}</strong>benchmark results</div>
537
+ <div class="summary-card"><strong>{summary['models']}</strong>models</div>
538
+ <div class="summary-card"><strong>{summary['harnesses']}</strong>harnesses</div>
539
+ <div class="summary-card"><strong>{summary['benchmarks']}</strong>benchmarks</div>
540
+ <div class="summary-card"><strong>{summary['token_coverage_pct']:.0f}%</strong>token coverage</div>
541
+ <div class="summary-card"><strong>{summary['cost_coverage_pct']:.0f}%</strong>cost coverage</div>
542
+ <div class="summary-card"><strong>{summary['time_coverage_pct']:.0f}%</strong>timing coverage</div>
543
  </div>
544
+ <p style="margin: 0.9rem 0 0 0; color: #CBD5E1; font-size: 0.95rem;">
545
+ Cross-benchmark ordering uses within-benchmark percentiles rather than averaging incompatible raw score scales.
546
+ Missing metrics remain missing and reduce coverage; they are never converted to zero.
547
+ </p>
548
+ </div>
549
+ """
550
+
551
+
552
+ def build_overview_html():
553
+ summary = coverage_summary(PR2_DF)
554
+ return f"""
555
+ <div class="summary-cards">
556
+ <div class="summary-card"><strong>{summary['results']}</strong>benchmark results</div>
557
+ <div class="summary-card"><strong>{summary['models']}</strong>models</div>
558
+ <div class="summary-card"><strong>{summary['harnesses']}</strong>harnesses</div>
559
+ <div class="summary-card"><strong>{summary['benchmarks']}</strong>benchmarks</div>
560
+ <div class="summary-card"><strong>{summary['token_coverage_pct']:.0f}%</strong>token coverage</div>
561
+ <div class="summary-card"><strong>{summary['cost_coverage_pct']:.0f}%</strong>cost coverage</div>
562
+ <div class="summary-card"><strong>{summary['time_coverage_pct']:.0f}%</strong>timing coverage</div>
563
  </div>
564
  """
565
 
 
604
  )
605
 
606
 
607
+ def add_category_section(category, benchmarks):
608
+ if not benchmarks:
609
+ gr.Markdown(f"No active benchmarks are currently classified as **{category}**.")
610
+ return
611
+ gr.Markdown(
612
+ f"Results classified as **{category}**. Cross-benchmark ordering uses within-benchmark "
613
+ "percentiles and reports coverage; raw benchmark scores are not averaged together."
614
+ )
615
+ gr.Markdown("#### Trade-offs")
616
+ with gr.Row():
617
+ benchmark = gr.Dropdown(choices=benchmarks, value=benchmarks[0], label="Benchmark")
618
+ metric = gr.Dropdown(
619
+ choices=["Cost per task", "Total tokens per task", "Total time per task", "Execution error rate"],
620
+ value="Cost per task",
621
+ label="X metric",
622
+ )
623
+ color_by = gr.Radio(choices=COLOR_BY_CHOICES, value="Model", label="Color by")
624
+ labels = gr.Checkbox(value=False, label="Show point labels")
625
+ background = gr.Dropdown(
626
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
627
+ )
628
+ plot = gr.Plot(
629
+ value=render_category_tradeoff(category, benchmarks[0], "Cost per task", "Model", False, "Dark"),
630
+ show_label=False,
631
+ elem_classes="responsive-plot",
632
+ )
633
+ controls = [benchmark, metric, color_by, labels, background]
634
+ for control in controls:
635
+ control.change(
636
+ fn=lambda b, m, c, l, bg, cat=category: render_category_tradeoff(cat, b, m, c, l, bg),
637
+ inputs=controls,
638
+ outputs=plot,
639
+ )
640
+
641
+ gr.Markdown("#### Matrix")
642
+ with gr.Row():
643
+ matrix_metric = gr.Dropdown(
644
+ choices=[
645
+ "Score", "Within-benchmark percentile", "Within-benchmark rank",
646
+ "Total tokens", "Cost", "Total time", "Agent time", "Execution error rate", "Coverage"
647
+ ],
648
+ value="Within-benchmark percentile",
649
+ label="Metric",
650
+ )
651
+ matrix_values = gr.Checkbox(value=True, label="Show cell values")
652
+ matrix_background = gr.Dropdown(
653
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
654
+ )
655
+ matrix_plot = gr.Plot(
656
+ value=render_category_matrix(category, "Within-benchmark percentile", True, "Dark"),
657
+ show_label=False,
658
+ elem_classes="responsive-plot",
659
+ )
660
+ matrix_controls = [matrix_metric, matrix_values, matrix_background]
661
+ for control in matrix_controls:
662
+ control.change(
663
+ fn=lambda m, v, bg, cat=category: render_category_matrix(cat, m, v, bg),
664
+ inputs=matrix_controls,
665
+ outputs=matrix_plot,
666
+ )
667
+
668
+ gr.Markdown("#### Category ranking data")
669
+ gr.Dataframe(
670
+ value=category_leaderboard(category), interactive=False, show_label=False, max_height=TABLE_MAX_HEIGHT_PX
671
+ )
672
+
673
+
674
  demo = gr.Blocks(theme="citrus", head=FORCE_DARK_MODE_HEAD)
675
  with demo:
676
+ # Overview is deliberately always visible above the page navigation.
677
  gr.HTML(build_header_html(BENCHMARK_RUN_DF))
 
678
 
679
  with gr.Tabs():
680
+ with gr.Tab("Rankings"):
681
+ gr.Markdown(
682
+ "### Rankings\n"
683
+ "All ranking charts are shown on one page. Use the shared display controls below, then choose a benchmark "
684
+ "for each metric. Tables are capped to a scrollable height so the visualizations stay primary."
685
+ )
686
  with gr.Row():
687
+ ranking_color = gr.Radio(choices=COLOR_BY_CHOICES, value="Model", label="Color by")
688
+ ranking_sort = gr.Dropdown(
689
+ choices=[
690
+ "Largest value first",
691
+ "Lowest value first",
692
+ "Alphabetical (A–Z)",
693
+ "Alphabetical (Z–A)",
694
+ ],
695
+ value="Largest value first",
696
+ label="Chart order",
697
+ )
698
+ ranking_palette = gr.Dropdown(
699
+ choices=COLOR_PALETTE_CHOICES, value=DEFAULT_COLOR_PALETTE, label="Color palette"
700
+ )
701
+ ranking_background = gr.Dropdown(
702
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
703
+ )
704
+
705
+ ranking_sections = [("Score", "Score", ["All benchmarks", *BENCHMARK_NAMES], "All benchmarks")]
706
+ ranking_sections += [
707
+ ("Token usage", "Total tokens", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
708
+ ("Cost", "Cost", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
709
+ ("Response time", "Response time", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
710
+ ("Reliability", "Reliability", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
711
+ ("Tokens per successful task", "Tokens per successful task", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
712
+ ("Cost per successful task", "Cost per successful task", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
713
+ ("Time per successful task", "Time per successful task", BENCHMARK_NAMES, DEFAULT_BENCHMARK),
714
+ ]
715
+ shared_ranking_controls = [ranking_color, ranking_palette, ranking_background, ranking_sort]
716
+ for section_label, metric_name, benchmark_choices, default_benchmark in ranking_sections:
717
+ spec = RANKING_METRICS[metric_name]
718
+ gr.Markdown(f"#### {section_label}\n{spec.label}. {'Higher' if spec.higher_is_better else 'Lower'} is better.")
719
+ benchmark = gr.Dropdown(
720
+ choices=benchmark_choices, value=default_benchmark, label="Benchmark"
721
+ )
722
+ initial = render_ranking(
723
+ metric_name,
724
+ default_benchmark,
725
+ "Model",
726
+ DEFAULT_COLOR_PALETTE,
727
+ DEFAULT_PLOT_BACKGROUND,
728
+ "Largest value first",
729
+ )
730
+ plot = gr.Plot(value=initial[0], show_label=False, elem_classes="responsive-plot")
731
+ controls = [benchmark, *shared_ranking_controls]
732
+ for control in controls:
733
  control.change(
734
+ fn=lambda b, c, p, bg, so, m=metric_name: render_ranking(m, b, c, p, bg, so)[0],
735
+ inputs=controls,
 
 
736
  outputs=plot,
737
  )
738
 
 
739
  gr.Markdown(
740
+ "### Ranking data\n"
741
+ "One table for the page, placed after all charts. It includes the score, resource, timing, "
742
+ "reliability, and per-success values for the selected benchmark."
 
 
 
743
  )
744
+ with gr.Row():
745
+ ranking_table_benchmark = gr.Dropdown(
746
+ choices=BENCHMARK_NAMES, value=DEFAULT_BENCHMARK, label="Table benchmark"
747
+ )
748
+ ranking_table_metric = gr.Dropdown(
749
+ choices=list(PAGE_TABLE_SORT_COLUMNS), value="Score", label="Sort table by"
750
+ )
751
+ ranking_table_order = gr.Dropdown(
752
+ choices=[
753
+ "Largest value first",
754
+ "Lowest value first",
755
+ "Alphabetical (A–Z)",
756
+ "Alphabetical (Z–A)",
757
+ ],
758
+ value="Largest value first",
759
+ label="Table order",
760
+ )
761
+ ranking_page_table = gr.Dataframe(
762
+ value=render_page_table(DEFAULT_BENCHMARK, "Score", "Largest value first"),
763
+ interactive=False,
764
+ show_label=False,
765
+ max_height=TABLE_MAX_HEIGHT_PX,
766
+ )
767
+ ranking_table_controls = [ranking_table_benchmark, ranking_table_metric, ranking_table_order]
768
+ for control in ranking_table_controls:
769
+ control.change(
770
+ fn=render_page_table,
771
+ inputs=ranking_table_controls,
772
+ outputs=ranking_page_table,
773
+ )
774
+
775
+ with gr.Tab("Trade-offs"):
776
+ gr.Markdown(
777
+ "### Trade-offs\n"
778
+ "Efficiency and metric-pair views are displayed together. Pareto frontiers support both maximize and "
779
+ "minimize directions, so a checked frontier is shown whenever valid comparable points exist."
780
+ )
781
+ gr.Markdown("#### Efficiency")
782
  with gr.Row():
783
  efficiency_benchmark = gr.Dropdown(
784
+ choices=BENCHMARK_NAMES, value=DEFAULT_BENCHMARK, label="Benchmark"
 
 
785
  )
786
  efficiency_metric = gr.Dropdown(
787
+ choices=list(EFFICIENCY_RESOURCE_METRICS), value="Total tokens", label="Resource metric"
 
 
788
  )
789
  efficiency_color_by = gr.Radio(
790
+ choices=EFFICIENCY_COLOR_BY_CHOICES, value="Model", label="Color by"
 
 
791
  )
792
  efficiency_scale = gr.Radio(choices=["Log", "Linear"], value="Log", label="X-axis scale")
793
  with gr.Row():
794
  efficiency_pareto = gr.Checkbox(value=True, label="Show Pareto frontier")
795
  efficiency_labels = gr.Checkbox(value=False, label="Show point labels")
796
  efficiency_palette = gr.Dropdown(
797
+ choices=COLOR_PALETTE_CHOICES, value=DEFAULT_COLOR_PALETTE, label="Color palette"
 
 
798
  )
799
  efficiency_background = gr.Dropdown(
800
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
 
 
801
  )
 
802
  initial_efficiency = render_efficiency(
803
+ DEFAULT_BENCHMARK, "Total tokens", "Model", "Log", True, False,
804
+ DEFAULT_COLOR_PALETTE, DEFAULT_PLOT_BACKGROUND,
 
 
 
 
 
 
805
  )
806
+ efficiency_note = gr.Markdown(initial_efficiency[1])
807
  efficiency_plot = gr.Plot(
808
+ value=initial_efficiency[0], show_label=False, elem_classes="responsive-plot"
 
 
809
  )
 
 
 
 
 
 
 
810
  efficiency_controls = [
811
+ efficiency_benchmark, efficiency_metric, efficiency_color_by, efficiency_scale,
812
+ efficiency_pareto, efficiency_labels, efficiency_palette, efficiency_background,
 
 
 
 
 
 
813
  ]
814
  for control in efficiency_controls:
815
  control.change(
816
  fn=render_efficiency,
817
  inputs=efficiency_controls,
818
+ outputs=[efficiency_plot, efficiency_note],
819
  )
820
 
821
+ gr.Markdown("#### Metric pairs")
822
+ with gr.Row():
823
+ tradeoff_pair = gr.Dropdown(
824
+ choices=list(TRADEOFF_PAIRS), value="Score vs cost", label="Trade-off"
825
+ )
826
+ tradeoff_benchmark = gr.Dropdown(
827
+ choices=BENCHMARK_NAMES, value=DEFAULT_BENCHMARK, label="Benchmark"
828
+ )
829
+ tradeoff_color = gr.Radio(choices=COLOR_BY_CHOICES, value="Model", label="Color by")
830
+ tradeoff_scale = gr.Radio(choices=["Linear", "Log"], value="Linear", label="X-axis scale")
831
+ with gr.Row():
832
+ tradeoff_labels = gr.Checkbox(value=False, label="Show point labels")
833
+ tradeoff_pareto = gr.Checkbox(value=True, label="Show Pareto frontier")
834
+ tradeoff_palette = gr.Dropdown(
835
+ choices=COLOR_PALETTE_CHOICES, value=DEFAULT_COLOR_PALETTE, label="Color palette"
836
+ )
837
+ tradeoff_background = gr.Dropdown(
838
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
839
+ )
840
+ initial_tradeoff = render_tradeoff(
841
+ "Score vs cost", DEFAULT_BENCHMARK, "Model", False, "Linear", True,
842
+ DEFAULT_COLOR_PALETTE, DEFAULT_PLOT_BACKGROUND,
843
  )
844
+ tradeoff_note = gr.Markdown(initial_tradeoff[1])
845
+ tradeoff_plot = gr.Plot(
846
+ value=initial_tradeoff[0], show_label=False, elem_classes="responsive-plot"
847
+ )
848
+ tradeoff_controls = [
849
+ tradeoff_pair, tradeoff_benchmark, tradeoff_color, tradeoff_labels,
850
+ tradeoff_scale, tradeoff_pareto, tradeoff_palette, tradeoff_background,
851
+ ]
852
+ for control in tradeoff_controls:
853
+ control.change(
854
+ fn=render_tradeoff,
855
+ inputs=tradeoff_controls,
856
+ outputs=[tradeoff_plot, tradeoff_note],
857
+ )
858
 
859
+ gr.Markdown(
860
+ "### Trade-off data\n"
861
+ "A single table for this page appears after both charts and includes every metric used by the trade-off views."
862
+ )
863
+ with gr.Row():
864
+ tradeoff_table_benchmark = gr.Dropdown(
865
+ choices=BENCHMARK_NAMES, value=DEFAULT_BENCHMARK, label="Table benchmark"
866
+ )
867
+ tradeoff_table_metric = gr.Dropdown(
868
+ choices=list(PAGE_TABLE_SORT_COLUMNS), value="Score", label="Sort table by"
869
+ )
870
+ tradeoff_table_order = gr.Dropdown(
871
+ choices=[
872
+ "Largest value first",
873
+ "Lowest value first",
874
+ "Alphabetical (A–Z)",
875
+ "Alphabetical (Z–A)",
876
+ ],
877
+ value="Largest value first",
878
+ label="Table order",
879
+ )
880
+ tradeoff_page_table = gr.Dataframe(
881
+ value=render_page_table(DEFAULT_BENCHMARK, "Score", "Largest value first"),
882
+ interactive=False,
883
+ show_label=False,
884
+ max_height=TABLE_MAX_HEIGHT_PX,
885
+ )
886
+ tradeoff_table_controls = [tradeoff_table_benchmark, tradeoff_table_metric, tradeoff_table_order]
887
+ for control in tradeoff_table_controls:
888
+ control.change(
889
+ fn=render_page_table,
890
+ inputs=tradeoff_table_controls,
891
+ outputs=tradeoff_page_table,
892
+ )
893
 
894
+ with gr.Tab("Matrices"):
895
+ gr.Markdown(
896
+ "### Model × benchmark matrices\n"
897
+ "The within-benchmark percentile controls the color scale, while cell labels show the actual benchmark "
898
+ "score. Missing cells stay missing."
899
+ )
900
+ with gr.Row():
901
+ matrix_metric = gr.Dropdown(
902
+ choices=[*MATRIX_METRICS.keys(), "Coverage"],
903
+ value="Within-benchmark percentile",
904
+ label="Metric",
905
+ )
906
+ matrix_category = gr.Dropdown(
907
+ choices=["All", "Coding", "Generalist"], value="All", label="Benchmark category"
908
+ )
909
+ matrix_sort = gr.Dropdown(
910
+ choices=[
911
+ "Normalized performance (high to low)",
912
+ "Normalized performance (low to high)",
913
+ "Coverage (high to low)",
914
+ "Coverage (low to high)",
915
+ "Alphabetical",
916
+ "Alphabetical (Z–A)",
917
+ ],
918
+ value="Normalized performance (high to low)",
919
+ label="Sort rows",
920
+ )
921
+ matrix_background = gr.Dropdown(
922
+ choices=PLOT_BACKGROUND_CHOICES, value=DEFAULT_PLOT_BACKGROUND, label="Image background"
923
+ )
924
+ with gr.Row():
925
+ matrix_incomplete = gr.Checkbox(value=True, label="Include incomplete rows")
926
+ matrix_values = gr.Checkbox(value=True, label="Show cell values")
927
+ matrix_reverse = gr.Checkbox(value=False, label="Reverse color scale")
928
+ initial_matrix = render_matrix(
929
+ "Within-benchmark percentile", "All", True,
930
+ "Normalized performance (high to low)", True, False, "Dark"
931
+ )
932
+ matrix_plot = gr.Plot(value=initial_matrix, show_label=False, elem_classes="responsive-plot")
933
+ matrix_controls = [
934
+ matrix_metric, matrix_category, matrix_incomplete, matrix_sort,
935
+ matrix_values, matrix_reverse, matrix_background,
936
+ ]
937
+ for control in matrix_controls:
938
+ control.change(fn=render_matrix, inputs=matrix_controls, outputs=matrix_plot)
939
+
940
+
941
+ with gr.Tab("📊 Bradley-Terry Rankings"):
942
+ gr.Markdown("### Bradley-Terry Paired Comparison Rankings")
943
+ gr.Markdown(
944
+ "Rankings computed across all benchmarks using "
945
+ "[paired comparison methods](https://github.com/erikerlandson/paired-comparison-ranking). "
946
+ "Handles missing data and inconsistent orderings."
947
+ )
948
+
949
+ rank_csv = pd.read_csv("results.csv")
950
+ rank_csv = rank_csv.dropna(subset=["metrics.score"])
951
+ rank_model_choices = sorted(rank_csv["model.name"].unique().tolist())
952
+ rank_harness_choices = sorted(rank_csv["harness.name"].unique().tolist())
953
+ rank_benchmark_choices = sorted(rank_csv["benchmark.name"].unique().tolist())
954
+
955
+ with gr.Row():
956
+ rank_by = gr.Dropdown(
957
+ choices=list(RANK_BY_OPTIONS.keys()),
958
+ value="Benchmark Score",
959
+ label="Rank by",
960
+ )
961
+ rank_oss_models = gr.Checkbox(value=False, label="Open models only")
962
+ rank_oss_harnesses = gr.Checkbox(value=False, label="Open harnesses only")
963
+
964
+ with gr.Row():
965
+ rank_benchmark_filter = gr.CheckboxGroup(
966
+ choices=rank_benchmark_choices,
967
+ value=rank_benchmark_choices,
968
+ label="Benchmarks",
969
+ )
970
+
971
+ with gr.Row():
972
+ rank_model_filter = gr.CheckboxGroup(
973
+ choices=rank_model_choices,
974
+ value=rank_model_choices,
975
+ label="Models",
976
+ )
977
+
978
+ with gr.Row():
979
+ rank_harness_filter = gr.CheckboxGroup(
980
+ choices=rank_harness_choices,
981
+ value=rank_harness_choices,
982
+ label="Harnesses",
983
+ )
984
+
985
+ harness_df_init, model_df_init, pair_df_init = load_and_rank("results.csv")
986
+
987
+ gr.Markdown("#### Harness Rankings")
988
+ harness_table = gr.Dataframe(value=harness_df_init, interactive=False)
989
+ gr.Markdown("#### Model Rankings")
990
+ model_table = gr.Dataframe(value=model_df_init, interactive=False)
991
+ gr.Markdown("#### (Model, Harness) Rankings")
992
+ pair_table = gr.Dataframe(value=pair_df_init, interactive=False)
993
+
994
+ def update_rankings(rank_by_val, oss_models, oss_harnesses, benchmarks, models, harnesses):
995
+ return load_and_rank(
996
+ "results.csv",
997
+ open_models_only=oss_models,
998
+ open_harnesses_only=oss_harnesses,
999
+ benchmarks=benchmarks,
1000
+ models=models,
1001
+ harnesses=harnesses,
1002
+ rank_by=rank_by_val,
1003
+ )
1004
+
1005
+ ranking_inputs = [
1006
+ rank_by,
1007
+ rank_oss_models,
1008
+ rank_oss_harnesses,
1009
+ rank_benchmark_filter,
1010
+ rank_model_filter,
1011
+ rank_harness_filter,
1012
+ ]
1013
+ for control in ranking_inputs:
1014
+ control.change(
1015
+ fn=update_rankings,
1016
+ inputs=ranking_inputs,
1017
+ outputs=[harness_table, model_table, pair_table],
1018
+ )
1019
+
1020
+ with gr.Tab("Coding"):
1021
+ gr.Markdown(
1022
+ "### Coding\n"
1023
+ "Coding benchmarks are defined centrally in the benchmark catalog. The aggregate leaderboard uses "
1024
+ "within-benchmark percentiles and displays benchmark coverage."
1025
+ )
1026
+ add_category_section("Coding", CODING_BENCHMARKS)
1027
+
1028
+ with gr.Tab("Generalist"):
1029
+ gr.Markdown(
1030
+ "### Terminal & Generalist\n"
1031
+ "This category reflects active terminal/generalist benchmarks present in the repository."
1032
+ )
1033
+ add_category_section("Generalist", GENERALIST_BENCHMARKS)
1034
+
1035
+ with gr.Tab("Results Explorer"):
1036
+ gr.Markdown("### Benchmark runs")
1037
+ benchmark_runs = init_benchmark_runs(BENCHMARK_RUN_DF)
1038
+ gr.Markdown("### Methodology")
1039
+ gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
1040
+ gr.Markdown(
1041
+ "### Analytics methodology notes\n"
1042
+ "- **Normalized ordering:** rank/percentile is calculated independently inside each benchmark, then "
1043
+ "aggregated by model + harness with coverage shown beside it.\n"
1044
+ "- **Execution error rate:** recorded errors divided by recorded task count; unresolved tasks are not "
1045
+ "relabeled as errors.\n"
1046
+ "- **Missing metrics:** omitted from metric-specific comparisons and preserved as missing matrix cells.\n"
1047
+ "- **Pareto frontier:** benchmark-specific and direction-aware for maximize/minimize metric pairs."
1048
+ )
1049
  gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
1050
  gr.Markdown(HOW_TO_USE_TEXT, elem_classes="markdown-text")
1051
 
1052
+
1053
  scheduler = BackgroundScheduler()
1054
  scheduler.add_job(restart_space, "interval", seconds=1800)
1055
  scheduler.start()
requirements.txt CHANGED
@@ -15,3 +15,5 @@ tqdm
15
  transformers
16
  tokenizers>=0.15.0
17
  sentencepiece
 
 
 
15
  transformers
16
  tokenizers>=0.15.0
17
  sentencepiece
18
+ choix
19
+ scipy
src/analytics.py ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ import pandas as pd
6
+
7
+
8
+ BENCHMARK_CATALOG: dict[str, dict[str, object]] = {
9
+ "SWE-Bench Verified": {
10
+ "category": "Coding",
11
+ "capabilities": ["repository-repair", "software-engineering"],
12
+ },
13
+ "SWE-Bench Pro -- Ansible": {
14
+ "category": "Coding",
15
+ "capabilities": ["repository-repair", "software-engineering", "ansible"],
16
+ },
17
+ "RH SWE-Bench": {
18
+ "category": "Coding",
19
+ "capabilities": ["repository-repair", "software-engineering"],
20
+ },
21
+ "Terminal Bench 2.0": {
22
+ "category": "Generalist",
23
+ "capabilities": ["shell", "tool-use"],
24
+ },
25
+ "Shellbench": {
26
+ "category": "Generalist",
27
+ "capabilities": ["shell", "tool-use"],
28
+ },
29
+ }
30
+
31
+ DEFAULT_BENCHMARK_CATEGORY = "Other"
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class MetricSpec:
36
+ column: str
37
+ label: str
38
+ higher_is_better: bool
39
+ positive_only: bool = False
40
+
41
+
42
+ RANKING_METRICS: dict[str, MetricSpec] = {
43
+ "Score": MetricSpec("Score (%)", "Score (%)", True),
44
+ "Total tokens": MetricSpec("Total Tokens Per Task", "Total tokens per task", False, True),
45
+ "Input tokens": MetricSpec("Input Tokens Per Task", "Input tokens per task", False, True),
46
+ "Output tokens": MetricSpec("Output Tokens Per Task", "Output tokens per task", False, True),
47
+ "Cache tokens": MetricSpec("Cache Tokens Per Task", "Cache tokens per task", False, True),
48
+ "Cost": MetricSpec("Cost Per Task", "Cost per task (USD)", False, True),
49
+ "Response time": MetricSpec("Total Time Per Task", "Total time per task (seconds)", False, True),
50
+ "Agent time": MetricSpec("Agent Time Per Task", "Agent time per task (seconds)", False, True),
51
+ "Reliability": MetricSpec("Execution Error Rate (%)", "Execution error rate (%)", False),
52
+ "Tokens per successful task": MetricSpec("Tokens Per Successful Task", "Tokens per successful task", False, True),
53
+ "Cost per successful task": MetricSpec("Cost Per Successful Task", "Cost per successful task (USD)", False, True),
54
+ "Time per successful task": MetricSpec("Time Per Successful Task", "Time per successful task (seconds)", False, True),
55
+ }
56
+
57
+
58
+ TRADEOFF_METRICS: dict[str, MetricSpec] = {
59
+ "Score": RANKING_METRICS["Score"],
60
+ "Cost per task": RANKING_METRICS["Cost"],
61
+ "Total tokens per task": RANKING_METRICS["Total tokens"],
62
+ "Total time per task": RANKING_METRICS["Response time"],
63
+ "Agent time per task": RANKING_METRICS["Agent time"],
64
+ "Execution error rate": RANKING_METRICS["Reliability"],
65
+ }
66
+
67
+
68
+ MATRIX_METRICS: dict[str, MetricSpec] = {
69
+ "Score": RANKING_METRICS["Score"],
70
+ "Within-benchmark percentile": MetricSpec("Within-Benchmark Percentile", "Within-benchmark percentile", True),
71
+ "Within-benchmark rank": MetricSpec("Within-Benchmark Rank", "Within-benchmark rank", False),
72
+ "Total tokens": RANKING_METRICS["Total tokens"],
73
+ "Cost": RANKING_METRICS["Cost"],
74
+ "Total time": RANKING_METRICS["Response time"],
75
+ "Agent time": RANKING_METRICS["Agent time"],
76
+ "Execution error rate": RANKING_METRICS["Reliability"],
77
+ }
78
+
79
+
80
+ def benchmark_metadata(name: str) -> dict[str, object]:
81
+ metadata = BENCHMARK_CATALOG.get(name)
82
+ if metadata is not None:
83
+ return metadata
84
+ return {"category": DEFAULT_BENCHMARK_CATEGORY, "capabilities": []}
85
+
86
+
87
+ def benchmark_category(name: str) -> str:
88
+ return str(benchmark_metadata(name)["category"])
89
+
90
+
91
+ def benchmarks_for_category(dataframe: pd.DataFrame, category: str) -> list[str]:
92
+ if dataframe is None or dataframe.empty or "Benchmark" not in dataframe:
93
+ return []
94
+ names = sorted(str(value) for value in dataframe["Benchmark"].dropna().unique())
95
+ return [name for name in names if benchmark_category(name) == category]
96
+
97
+
98
+ def enrich_analysis_df(dataframe: pd.DataFrame) -> pd.DataFrame:
99
+ """Add PR2 taxonomy, reliability, per-success and normalized performance fields."""
100
+ if dataframe is None:
101
+ return pd.DataFrame()
102
+ df = dataframe.copy()
103
+ if df.empty:
104
+ for column in (
105
+ "Benchmark Category",
106
+ "Execution Error Rate (%)",
107
+ "Tokens Per Successful Task",
108
+ "Cost Per Successful Task",
109
+ "Time Per Successful Task",
110
+ "Total Benchmark Cost",
111
+ "Within-Benchmark Rank",
112
+ "Within-Benchmark Percentile",
113
+ ):
114
+ if column not in df:
115
+ df[column] = pd.Series(dtype="float64" if column != "Benchmark Category" else "object")
116
+ return df
117
+
118
+ df["Benchmark Category"] = df["Benchmark"].map(lambda value: benchmark_category(str(value)))
119
+
120
+ tasks = pd.to_numeric(df.get("Tasks"), errors="coerce")
121
+ errors = pd.to_numeric(df.get("Errors"), errors="coerce")
122
+ valid_tasks = tasks.notna() & (tasks > 0)
123
+ df["Execution Error Rate (%)"] = (errors / tasks * 100).where(valid_tasks & errors.notna())
124
+
125
+ score_fraction = pd.to_numeric(df.get("Score"), errors="coerce")
126
+ successful = score_fraction.notna() & (score_fraction > 0)
127
+ for source, target in (
128
+ ("Total Tokens Per Task", "Tokens Per Successful Task"),
129
+ ("Cost Per Task", "Cost Per Successful Task"),
130
+ ("Total Time Per Task", "Time Per Successful Task"),
131
+ ):
132
+ values = pd.to_numeric(df.get(source), errors="coerce")
133
+ df[target] = (values / score_fraction).where(successful & values.notna() & (values > 0))
134
+
135
+ cost = pd.to_numeric(df.get("Cost Per Task"), errors="coerce")
136
+ df["Total Benchmark Cost"] = (cost * tasks).where(cost.notna() & (cost > 0) & valid_tasks)
137
+
138
+ scores = pd.to_numeric(df.get("Score (%)"), errors="coerce")
139
+ df["Within-Benchmark Rank"] = scores.groupby(df["Benchmark"]).rank(method="min", ascending=False)
140
+
141
+ def percentile(group: pd.Series) -> pd.Series:
142
+ valid = group.dropna()
143
+ out = pd.Series(index=group.index, dtype=float)
144
+ if valid.empty:
145
+ return out
146
+ ranks = valid.rank(method="average", ascending=False)
147
+ if len(valid) == 1:
148
+ out.loc[valid.index] = 100.0
149
+ else:
150
+ out.loc[valid.index] = 100.0 * (len(valid) - ranks) / (len(valid) - 1)
151
+ return out
152
+
153
+ df["Within-Benchmark Percentile"] = scores.groupby(df["Benchmark"], group_keys=False).apply(percentile)
154
+ return df
155
+
156
+
157
+ def filter_category(dataframe: pd.DataFrame, category: str) -> pd.DataFrame:
158
+ df = enrich_analysis_df(dataframe)
159
+ return df[df["Benchmark Category"] == category].copy()
160
+
161
+
162
+ def ranking_df(
163
+ dataframe: pd.DataFrame,
164
+ metric: str,
165
+ benchmark: str | None = None,
166
+ category: str | None = None,
167
+ ) -> pd.DataFrame:
168
+ df = enrich_analysis_df(dataframe)
169
+ spec = RANKING_METRICS[metric]
170
+ if category:
171
+ df = df[df["Benchmark Category"] == category]
172
+ if benchmark and benchmark != "All benchmarks":
173
+ df = df[df["Benchmark"] == benchmark]
174
+ elif benchmark == "All benchmarks":
175
+ if metric != "Score":
176
+ # Resource units can be compared across benchmarks, but rows remain per benchmark;
177
+ # do not silently aggregate them.
178
+ pass
179
+ else:
180
+ return cross_benchmark_ranking_df(df)
181
+
182
+ values = pd.to_numeric(df[spec.column], errors="coerce")
183
+ valid = values.notna()
184
+ if spec.positive_only:
185
+ valid &= values > 0
186
+ df = df.loc[valid].copy()
187
+ df[spec.column] = values.loc[valid]
188
+ columns = [
189
+ "Model", "Harness", "Benchmark", "Benchmark Category", spec.column,
190
+ "Score (%)", "Execution Error Rate (%)"
191
+ ]
192
+ columns = list(dict.fromkeys(column for column in columns if column in df))
193
+ return df.sort_values(
194
+ [spec.column, "Model", "Harness"],
195
+ ascending=[not spec.higher_is_better, True, True],
196
+ kind="mergesort",
197
+ )[columns].reset_index(drop=True)
198
+
199
+
200
+ def cross_benchmark_ranking_df(
201
+ dataframe: pd.DataFrame,
202
+ minimum_coverage: float | int = 0.5,
203
+ ) -> pd.DataFrame:
204
+ """Aggregate within-benchmark percentiles without averaging incompatible raw scores."""
205
+ df = enrich_analysis_df(dataframe)
206
+ if df.empty:
207
+ return pd.DataFrame(columns=[
208
+ "Model", "Harness", "Normalized Performance", "Benchmarks Covered",
209
+ "Eligible Benchmarks", "Coverage (%)",
210
+ ])
211
+ eligible = int(df["Benchmark"].nunique())
212
+ grouped = (
213
+ df.dropna(subset=["Within-Benchmark Percentile"])
214
+ .groupby(["Model", "Harness"], as_index=False)
215
+ .agg(
216
+ **{
217
+ "Normalized Performance": ("Within-Benchmark Percentile", "mean"),
218
+ "Benchmarks Covered": ("Benchmark", "nunique"),
219
+ }
220
+ )
221
+ )
222
+ grouped["Eligible Benchmarks"] = eligible
223
+ grouped["Coverage (%)"] = grouped["Benchmarks Covered"] / eligible * 100 if eligible else 0.0
224
+
225
+ if isinstance(minimum_coverage, float) and minimum_coverage <= 1:
226
+ threshold_pct = minimum_coverage * 100
227
+ grouped = grouped[grouped["Coverage (%)"] >= threshold_pct]
228
+ else:
229
+ grouped = grouped[grouped["Benchmarks Covered"] >= int(minimum_coverage)]
230
+ return grouped.sort_values(
231
+ ["Normalized Performance", "Benchmarks Covered", "Model", "Harness"],
232
+ ascending=[False, False, True, True],
233
+ kind="mergesort",
234
+ ).reset_index(drop=True)
235
+
236
+
237
+ def matrix_df(
238
+ dataframe: pd.DataFrame,
239
+ metric: str,
240
+ category: str | None = None,
241
+ include_incomplete: bool = True,
242
+ sort_by: str = "Normalized performance",
243
+ ) -> pd.DataFrame:
244
+ df = enrich_analysis_df(dataframe)
245
+ if category:
246
+ df = df[df["Benchmark Category"] == category]
247
+ if df.empty:
248
+ return pd.DataFrame()
249
+
250
+ df["Agent"] = df["Model"].astype(str) + " / " + df["Harness"].astype(str)
251
+ benchmarks = sorted(df["Benchmark"].dropna().unique())
252
+ agents = sorted(df["Agent"].dropna().unique())
253
+
254
+ if metric == "Coverage":
255
+ available = df.assign(_coverage=1).pivot_table(
256
+ index="Agent", columns="Benchmark", values="_coverage", aggfunc="max"
257
+ )
258
+ matrix = available.reindex(index=agents, columns=benchmarks)
259
+ else:
260
+ spec = MATRIX_METRICS[metric]
261
+ values = pd.to_numeric(df[spec.column], errors="coerce")
262
+ work = df.assign(_value=values)
263
+ matrix = work.pivot_table(index="Agent", columns="Benchmark", values="_value", aggfunc="mean")
264
+ matrix = matrix.reindex(index=agents, columns=benchmarks)
265
+
266
+ if not include_incomplete:
267
+ matrix = matrix.dropna(axis=0, how="any")
268
+
269
+ if matrix.empty:
270
+ return matrix
271
+
272
+ if sort_by in {"Coverage", "Coverage (high to low)", "Coverage (low to high)"}:
273
+ ascending = sort_by == "Coverage (low to high)"
274
+ coverage = matrix.notna().sum(axis=1)
275
+ order = coverage.sort_values(ascending=ascending, kind="mergesort").index
276
+ matrix = matrix.loc[order]
277
+ elif sort_by in {"Normalized performance", "Normalized performance (high to low)", "Normalized performance (low to high)"}:
278
+ perf = cross_benchmark_ranking_df(df, minimum_coverage=0)
279
+ perf["Agent"] = perf["Model"] + " / " + perf["Harness"]
280
+ perf = perf.sort_values(
281
+ ["Normalized Performance", "Agent"],
282
+ ascending=[sort_by == "Normalized performance (low to high)", True],
283
+ kind="mergesort",
284
+ )
285
+ order = [agent for agent in perf["Agent"] if agent in matrix.index]
286
+ order += [agent for agent in matrix.index if agent not in order]
287
+ matrix = matrix.loc[order]
288
+ elif sort_by == "Alphabetical (Z–A)":
289
+ matrix = matrix.loc[sorted(matrix.index, reverse=True)]
290
+ elif sort_by in {"Alphabetical", "Stable"}:
291
+ matrix = matrix.loc[sorted(matrix.index)]
292
+ return matrix
293
+
294
+
295
+ def coverage_summary(dataframe: pd.DataFrame) -> dict[str, float | int]:
296
+ df = enrich_analysis_df(dataframe)
297
+ total = len(df)
298
+ def pct(column: str, positive: bool = False) -> float:
299
+ if total == 0:
300
+ return 0.0
301
+ values = pd.to_numeric(df[column], errors="coerce")
302
+ mask = values.notna()
303
+ if positive:
304
+ mask &= values > 0
305
+ return float(mask.mean() * 100)
306
+ return {
307
+ "results": total,
308
+ "models": int(df["Model"].nunique()) if total else 0,
309
+ "harnesses": int(df["Harness"].nunique()) if total else 0,
310
+ "benchmarks": int(df["Benchmark"].nunique()) if total else 0,
311
+ "token_coverage_pct": pct("Total Tokens Per Task", True),
312
+ "cost_coverage_pct": pct("Cost Per Task", True),
313
+ "time_coverage_pct": pct("Total Time Per Task", True),
314
+ }
src/charts.py CHANGED
@@ -346,8 +346,6 @@ def create_leaderboard_benchmark_plot(
346
  )
347
  fig.update_xaxes(tickangle=-28)
348
  fig = apply_plot_theme(fig, background_name)
349
- min_width = max(600, len(plot_df) * 80)
350
- fig.update_layout(width=min_width)
351
  return fig
352
 
353
 
@@ -651,3 +649,262 @@ def create_token_pareto_frontier_plot(
651
  palette_name=palette_name,
652
  background_name=background_name,
653
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  )
347
  fig.update_xaxes(tickangle=-28)
348
  fig = apply_plot_theme(fig, background_name)
 
 
349
  return fig
350
 
351
 
 
649
  palette_name=palette_name,
650
  background_name=background_name,
651
  )
652
+
653
+
654
+ def create_ranking_plot(
655
+ dataframe: pd.DataFrame,
656
+ metric_column: str,
657
+ metric_label: str,
658
+ higher_is_better: bool,
659
+ color_by: ColorBy = "Model",
660
+ palette_name: str | None = DEFAULT_PALETTE,
661
+ background_name: str | None = DEFAULT_BACKGROUND,
662
+ sort_order: str = "Largest value first",
663
+ ) -> Figure:
664
+ """Generic horizontal ranking chart for any numeric metric."""
665
+ if dataframe is None or dataframe.empty or metric_column not in dataframe:
666
+ return empty_figure(f"No data available for {metric_label}.", background_name)
667
+ plot_df = dataframe.copy()
668
+ plot_df[metric_column] = pd.to_numeric(plot_df[metric_column], errors="coerce")
669
+ plot_df = plot_df.dropna(subset=[metric_column])
670
+ if plot_df.empty:
671
+ return empty_figure(f"No data available for {metric_label}.", background_name)
672
+ plot_df["Agent"] = plot_df["Model"].astype(str) + " / " + plot_df["Harness"].astype(str)
673
+ if sort_order == "Alphabetical (A–Z)":
674
+ plot_df = plot_df.sort_values(["Agent", metric_column], ascending=[True, False], kind="mergesort")
675
+ elif sort_order == "Alphabetical (Z–A)":
676
+ plot_df = plot_df.sort_values(["Agent", metric_column], ascending=[False, False], kind="mergesort")
677
+ elif sort_order == "Lowest value first":
678
+ plot_df = plot_df.sort_values(
679
+ [metric_column, "Agent"],
680
+ ascending=[True, True],
681
+ kind="mergesort",
682
+ )
683
+ else:
684
+ plot_df = plot_df.sort_values(
685
+ [metric_column, "Agent"],
686
+ ascending=[False, True],
687
+ kind="mergesort",
688
+ )
689
+ colors = color_map_for(plot_df[color_by], color_by, palette_name)
690
+ theme = get_plot_background(background_name)
691
+ fig = go.Figure()
692
+ for group, group_df in plot_df.groupby(color_by, sort=True):
693
+ fig.add_trace(
694
+ go.Bar(
695
+ x=group_df[metric_column],
696
+ y=group_df["Agent"],
697
+ orientation="h",
698
+ name=str(group),
699
+ marker={
700
+ "color": colors[str(group)],
701
+ "line": {"width": 1, "color": theme["marker_line_color"]},
702
+ },
703
+ customdata=group_df[["Benchmark", "Model", "Harness"]],
704
+ hovertemplate=(
705
+ "<b>%{customdata[1]}</b><br>"
706
+ "Harness: %{customdata[2]}<br>"
707
+ "Benchmark: %{customdata[0]}<br>"
708
+ f"{metric_label}: %{{x:.4g}}<extra></extra>"
709
+ ),
710
+ )
711
+ )
712
+ agent_order = plot_df["Agent"].drop_duplicates().tolist()
713
+ fig.update_layout(
714
+ xaxis={"title": metric_label},
715
+ yaxis={
716
+ "title": None,
717
+ "autorange": "reversed",
718
+ "categoryorder": "array",
719
+ "categoryarray": agent_order,
720
+ },
721
+ legend_title_text=color_by,
722
+ barmode="group",
723
+ )
724
+ return apply_plot_theme(fig, background_name)
725
+
726
+
727
+ def create_tradeoff_plot(
728
+ dataframe: pd.DataFrame,
729
+ x_column: str,
730
+ y_column: str,
731
+ x_label: str,
732
+ y_label: str,
733
+ color_by: ColorBy = "Model",
734
+ show_labels: bool = False,
735
+ palette_name: str | None = DEFAULT_PALETTE,
736
+ background_name: str | None = DEFAULT_BACKGROUND,
737
+ x_scale: Literal["Linear", "Log"] = "Linear",
738
+ y_scale: Literal["Linear", "Log"] = "Linear",
739
+ show_pareto_frontier: bool = False,
740
+ lower_x_is_better: bool = True,
741
+ higher_y_is_better: bool = True,
742
+ ) -> Figure:
743
+ """Generic two-metric scatter used by PR2 trade-off views."""
744
+ if dataframe is None or dataframe.empty:
745
+ return empty_figure("No trade-off data available.", background_name)
746
+ if x_column not in dataframe or y_column not in dataframe:
747
+ return empty_figure("Selected trade-off metric is unavailable.", background_name)
748
+ if color_by not in ("Model", "Harness") or color_by not in dataframe:
749
+ return empty_figure(f"Color dimension not available: {color_by}.", background_name)
750
+
751
+ plot_df = dataframe.copy()
752
+ plot_df[x_column] = pd.to_numeric(plot_df[x_column], errors="coerce")
753
+ plot_df[y_column] = pd.to_numeric(plot_df[y_column], errors="coerce")
754
+ plot_df = plot_df.dropna(subset=[x_column, y_column])
755
+ if x_scale == "Log":
756
+ plot_df = plot_df[plot_df[x_column] > 0]
757
+ if y_scale == "Log":
758
+ plot_df = plot_df[plot_df[y_column] > 0]
759
+ if plot_df.empty:
760
+ return empty_figure("No valid points for the selected trade-off.", background_name)
761
+
762
+ colors = color_map_for(plot_df[color_by], color_by, palette_name)
763
+ theme = get_plot_background(background_name)
764
+ fig = go.Figure()
765
+ for group, group_df in plot_df.groupby(color_by, sort=True):
766
+ label_kwargs = scatter_label_kwargs(group_df, show_labels)
767
+ fig.add_trace(
768
+ go.Scatter(
769
+ x=group_df[x_column],
770
+ y=group_df[y_column],
771
+ name=str(group),
772
+ **label_kwargs,
773
+ marker={
774
+ "size": 13,
775
+ "color": colors[str(group)],
776
+ "line": {"width": 1, "color": theme["marker_line_color"]},
777
+ },
778
+ customdata=group_df[["Model", "Harness", "Benchmark"]],
779
+ hovertemplate=(
780
+ "<b>%{customdata[0]}</b><br>"
781
+ "Harness: %{customdata[1]}<br>"
782
+ "Benchmark: %{customdata[2]}<br>"
783
+ f"{x_label}: %{{x:.4g}}<br>"
784
+ f"{y_label}: %{{y:.4g}}<extra></extra>"
785
+ ),
786
+ )
787
+ )
788
+
789
+ if show_pareto_frontier:
790
+ from src.leaderboard import get_pareto_frontier_df
791
+
792
+ frontier = get_pareto_frontier_df(
793
+ plot_df,
794
+ x_column,
795
+ y_column,
796
+ lower_x_is_better=lower_x_is_better,
797
+ higher_y_is_better=higher_y_is_better,
798
+ )
799
+ if not frontier.empty:
800
+ fig.add_trace(
801
+ go.Scatter(
802
+ x=frontier[x_column],
803
+ y=frontier[y_column],
804
+ mode="lines+markers",
805
+ name="Pareto frontier",
806
+ line={"width": 3, "dash": "dash", "color": theme["text_primary"]},
807
+ marker={"size": 9, "symbol": "diamond-open"},
808
+ hovertemplate=f"{x_label}: %{{x:.4g}}<br>{y_label}: %{{y:.4g}}<extra></extra>",
809
+ )
810
+ )
811
+
812
+ fig.update_layout(
813
+ xaxis={"title": x_label, "type": "log" if x_scale == "Log" else "linear"},
814
+ yaxis={"title": y_label, "type": "log" if y_scale == "Log" else "linear"},
815
+ legend_title_text=color_by,
816
+ )
817
+ return apply_plot_theme(fig, background_name)
818
+
819
+
820
+ def create_matrix_plot(
821
+ matrix: pd.DataFrame,
822
+ title: str,
823
+ metric_label: str,
824
+ higher_is_better: bool = True,
825
+ show_values: bool = True,
826
+ reverse_scale: bool | None = None,
827
+ background_name: str | None = DEFAULT_BACKGROUND,
828
+ display_matrix: pd.DataFrame | None = None,
829
+ display_metric_label: str | None = None,
830
+ ) -> Figure:
831
+ """Render a reusable model/harness × benchmark matrix."""
832
+ if matrix is None or matrix.empty:
833
+ return empty_figure(f"No data available for {title}.", background_name)
834
+ reverse = (not higher_is_better) if reverse_scale is None else reverse_scale
835
+ colorscale = "Viridis_r" if reverse else "Viridis"
836
+ z = matrix.to_numpy(dtype=float)
837
+ text = None
838
+ texttemplate = None
839
+ display_values = matrix if display_matrix is None else display_matrix.reindex(
840
+ index=matrix.index, columns=matrix.columns
841
+ )
842
+ display_z = display_values.to_numpy(dtype=float)
843
+ if show_values:
844
+ text = [[("" if pd.isna(value) else f"{value:.4g}") for value in row] for row in display_z]
845
+ texttemplate = "%{text}"
846
+ hover_label = display_metric_label or metric_label
847
+ customdata = display_z if display_matrix is not None else None
848
+ hovertemplate = (
849
+ "Agent: %{y}<br>"
850
+ "Benchmark: %{x}<br>"
851
+ + (
852
+ f"{hover_label}: %{{customdata:.4g}}<br>{metric_label}: %{{z:.4g}}<extra></extra>"
853
+ if display_matrix is not None
854
+ else f"{metric_label}: %{{z:.4g}}<extra></extra>"
855
+ )
856
+ )
857
+ fig = go.Figure(
858
+ go.Heatmap(
859
+ z=z,
860
+ x=[str(value) for value in matrix.columns],
861
+ y=[str(value) for value in matrix.index],
862
+ colorscale=colorscale,
863
+ colorbar={"title": metric_label},
864
+ text=text,
865
+ texttemplate=texttemplate,
866
+ customdata=customdata,
867
+ hovertemplate=hovertemplate,
868
+ hoverongaps=False,
869
+ )
870
+ )
871
+ fig.update_layout(
872
+ title=title,
873
+ xaxis={"title": "Benchmark"},
874
+ yaxis={"title": "Model / Harness", "autorange": "reversed"},
875
+ height=max(480, 28 * len(matrix.index) + 180),
876
+ )
877
+ return apply_plot_theme(fig, background_name)
878
+
879
+
880
+ def create_coverage_matrix_plot(
881
+ matrix: pd.DataFrame,
882
+ background_name: str | None = DEFAULT_BACKGROUND,
883
+ ) -> Figure:
884
+ """Render coverage as available/missing without converting missing data to score zero."""
885
+ if matrix is None or matrix.empty:
886
+ return empty_figure("No benchmark coverage data available.", background_name)
887
+ display = matrix.copy()
888
+ z = display.notna().astype(int).to_numpy()
889
+ text = [["Available" if value else "Missing" for value in row] for row in z]
890
+ fig = go.Figure(
891
+ go.Heatmap(
892
+ z=z,
893
+ x=[str(value) for value in display.columns],
894
+ y=[str(value) for value in display.index],
895
+ zmin=0,
896
+ zmax=1,
897
+ colorscale=[[0, "#475569"], [1, "#84cc16"]],
898
+ showscale=False,
899
+ text=text,
900
+ texttemplate="%{text}",
901
+ hovertemplate="Agent: %{y}<br>Benchmark: %{x}<br>Status: %{text}<extra></extra>",
902
+ )
903
+ )
904
+ fig.update_layout(
905
+ title="Benchmark coverage",
906
+ xaxis={"title": "Benchmark"},
907
+ yaxis={"title": "Model / Harness", "autorange": "reversed"},
908
+ height=max(480, 28 * len(display.index) + 180),
909
+ )
910
+ return apply_plot_theme(fig, background_name)
src/leaderboard.py CHANGED
@@ -215,44 +215,70 @@ def get_token_efficiency_table_df(
215
  return table_df
216
 
217
 
218
- def get_resource_pareto_frontier_df(
219
  dataframe: pd.DataFrame,
220
- token_metric: str,
221
- score_column: str = "Score (%)",
 
 
 
 
222
  ) -> pd.DataFrame:
223
- """Return deterministic non-dominated points for lower resource use/higher score."""
224
- if token_metric not in dataframe.columns or score_column not in dataframe.columns:
 
 
 
 
225
  return dataframe.iloc[0:0].copy()
226
 
227
  candidates = dataframe.copy()
228
- candidates[token_metric] = pd.to_numeric(candidates[token_metric], errors="coerce")
229
- candidates[score_column] = pd.to_numeric(candidates[score_column], errors="coerce")
230
- candidates = candidates.dropna(subset=[token_metric, score_column])
231
- candidates = candidates[candidates[token_metric] > 0]
 
232
  if candidates.empty:
233
  return candidates
234
 
235
- tie_breakers = [column for column in ("Benchmark", "Model", "Harness", "Run Label") if column in candidates]
236
- candidates = candidates.sort_values(
237
- [token_metric, score_column, *tie_breakers],
238
- ascending=[True, False, *([True] * len(tie_breakers))],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  kind="mergesort",
240
  )
241
 
242
- frontier_indices: list[object] = []
243
- best_score_at_lower_tokens = float("-inf")
244
- for _, token_group in candidates.groupby(token_metric, sort=True):
245
- group_best_score = float(token_group[score_column].max())
246
- if group_best_score > best_score_at_lower_tokens:
247
- frontier_indices.extend(token_group[token_group[score_column] == group_best_score].index.tolist())
248
- best_score_at_lower_tokens = group_best_score
249
-
250
- return candidates.loc[frontier_indices].sort_values(
251
- [token_metric, score_column, *tie_breakers],
252
- ascending=[True, False, *([True] * len(tie_breakers))],
253
- kind="mergesort",
254
- )
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
 
257
  def get_token_pareto_frontier_df(
258
  dataframe: pd.DataFrame,
 
215
  return table_df
216
 
217
 
218
+ def get_pareto_frontier_df(
219
  dataframe: pd.DataFrame,
220
+ x_column: str,
221
+ y_column: str,
222
+ *,
223
+ lower_x_is_better: bool = True,
224
+ higher_y_is_better: bool = True,
225
+ require_positive_x: bool = False,
226
  ) -> pd.DataFrame:
227
+ """Return deterministic non-dominated points for arbitrary metric directions.
228
+
229
+ Ties are preserved. A row is excluded only when another row is at least as
230
+ good on both axes and strictly better on at least one axis.
231
+ """
232
+ if x_column not in dataframe.columns or y_column not in dataframe.columns:
233
  return dataframe.iloc[0:0].copy()
234
 
235
  candidates = dataframe.copy()
236
+ candidates[x_column] = pd.to_numeric(candidates[x_column], errors="coerce")
237
+ candidates[y_column] = pd.to_numeric(candidates[y_column], errors="coerce")
238
+ candidates = candidates.dropna(subset=[x_column, y_column])
239
+ if require_positive_x:
240
+ candidates = candidates[candidates[x_column] > 0]
241
  if candidates.empty:
242
  return candidates
243
 
244
+ x = candidates[x_column]
245
+ y = candidates[y_column]
246
+ frontier_mask = pd.Series(True, index=candidates.index)
247
+ for idx in candidates.index:
248
+ x_at_idx = x.loc[idx]
249
+ y_at_idx = y.loc[idx]
250
+ x_at_least_as_good = x <= x_at_idx if lower_x_is_better else x >= x_at_idx
251
+ y_at_least_as_good = y >= y_at_idx if higher_y_is_better else y <= y_at_idx
252
+ x_strictly_better = x < x_at_idx if lower_x_is_better else x > x_at_idx
253
+ y_strictly_better = y > y_at_idx if higher_y_is_better else y < y_at_idx
254
+ dominated = x_at_least_as_good & y_at_least_as_good & (x_strictly_better | y_strictly_better)
255
+ dominated.loc[idx] = False
256
+ if dominated.any():
257
+ frontier_mask.loc[idx] = False
258
+
259
+ frontier = candidates.loc[frontier_mask].copy()
260
+ tie_breakers = [column for column in ("Benchmark", "Model", "Harness", "Run Label") if column in frontier]
261
+ return frontier.sort_values(
262
+ [x_column, y_column, *tie_breakers],
263
+ ascending=[lower_x_is_better, not higher_y_is_better, *([True] * len(tie_breakers))],
264
  kind="mergesort",
265
  )
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
+ def get_resource_pareto_frontier_df(
269
+ dataframe: pd.DataFrame,
270
+ token_metric: str,
271
+ score_column: str = "Score (%)",
272
+ ) -> pd.DataFrame:
273
+ """Return deterministic non-dominated points for lower resource use/higher score."""
274
+ return get_pareto_frontier_df(
275
+ dataframe,
276
+ token_metric,
277
+ score_column,
278
+ lower_x_is_better=True,
279
+ higher_y_is_better=True,
280
+ require_positive_x=True,
281
+ )
282
 
283
  def get_token_pareto_frontier_df(
284
  dataframe: pd.DataFrame,
src/rankings.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ from pathlib import Path
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+ import choix
7
+
8
+
9
+ def prepare_ranking_data(
10
+ df: pd.DataFrame,
11
+ catcol: str | list[str],
12
+ metcol: str,
13
+ descending: bool = False,
14
+ eqvcol: str | list[str] = [],
15
+ ) -> tuple[list[tuple[int, int]], list[Any], dict]:
16
+ ndata = df.shape[0]
17
+ if ndata < 2:
18
+ raise ValueError("Not enough data to prepare ranking comparisons")
19
+ catcol = catcol if isinstance(catcol, list) else [catcol]
20
+ eqvcol = eqvcol if isinstance(eqvcol, list) else [eqvcol]
21
+ ncat = len(catcol)
22
+ neqv = len(eqvcol)
23
+ tcols = catcol + eqvcol + [metcol]
24
+ t = list(df[tcols].itertuples(index=False, name=None))
25
+ metvals = [x[-1] for x in t]
26
+ if ncat > 1:
27
+ catvals = [x[:ncat] for x in t]
28
+ else:
29
+ catvals = [x[0] for x in t]
30
+ if neqv > 1:
31
+ eqvvals = [x[ncat : ncat + neqv] for x in t]
32
+ elif neqv == 1:
33
+ eqvvals = [x[ncat] for x in t]
34
+ else:
35
+ eqvvals = ["[ALL]"] * ndata
36
+ umap = dict([(y, x) for x, y in enumerate(sorted(set(catvals)))])
37
+ cats = sorted(umap.keys())
38
+ eqvcats = sorted(set(eqvvals))
39
+ eqvdata = {}
40
+ for eqv in eqvcats:
41
+ eqvdata[eqv] = [[] for _ in range(len(cats))]
42
+ compvals = [(umap[c], m, e) for c, m, e in zip(catvals, metvals, eqvvals)]
43
+ for category, metric, equivalence in compvals:
44
+ eqvdata[equivalence][category].append(metric)
45
+ comps = []
46
+ for i in range(ndata):
47
+ ic, im, ie = compvals[i]
48
+ for j in range(i):
49
+ jc, jm, je = compvals[j]
50
+ if ie != je:
51
+ continue
52
+ if im == jm:
53
+ continue
54
+ iwin = im < jm if descending else im > jm
55
+ if iwin:
56
+ comps.append((ic, jc))
57
+ else:
58
+ comps.append((jc, ic))
59
+ return comps, cats, eqvdata
60
+
61
+
62
+ def ranking_dataframe(cats, params, eqvdata) -> pd.DataFrame:
63
+ ranking = np.argsort(params)[::-1]
64
+ rows = []
65
+ for rank, idx in enumerate(ranking, start=1):
66
+ row = {
67
+ "Rank": rank,
68
+ "Category": cats[idx] if not isinstance(cats[idx], tuple) else " + ".join(cats[idx]),
69
+ }
70
+ for k in sorted(eqvdata.keys()):
71
+ mets = eqvdata[k][idx]
72
+ row[k] = round(float(np.mean(mets)), 3) if len(mets) > 0 else None
73
+ rows.append(row)
74
+ return pd.DataFrame(rows)
75
+
76
+
77
+ RANK_BY_OPTIONS = {
78
+ "Benchmark Score": ("metrics.score", False),
79
+ "Mean Cost Per Task (USD)": ("metrics.mean_cost_usd_per_task", True),
80
+ "Mean Tokens Per Task": ("metrics.mean_tokens_per_task", True),
81
+ }
82
+
83
+
84
+ def compute_ranking(df, catcol, metcol="metrics.score", descending=False, eqvcol="benchmark.name"):
85
+ comps, cats, eqvdata = prepare_ranking_data(
86
+ df, catcol, metcol, descending=descending, eqvcol=eqvcol
87
+ )
88
+ params = choix.ilsr_pairwise(len(cats), comps, alpha=1e-3)
89
+ return ranking_dataframe(cats, params, eqvdata)
90
+
91
+
92
+ def rank_harnesses(df: pd.DataFrame, metcol="metrics.score", descending=False) -> pd.DataFrame:
93
+ return compute_ranking(df, "harness.name", metcol, descending)
94
+
95
+
96
+ def rank_models(df: pd.DataFrame, metcol="metrics.score", descending=False) -> pd.DataFrame:
97
+ return compute_ranking(df, "model.name", metcol, descending)
98
+
99
+
100
+ def rank_pairs(df: pd.DataFrame, metcol="metrics.score", descending=False) -> pd.DataFrame:
101
+ return compute_ranking(df, ["model.name", "harness.name"], metcol, descending)
102
+
103
+
104
+ def _load_csv(csv_path: str | Path = "results.csv") -> pd.DataFrame:
105
+ df = pd.read_csv(csv_path)
106
+ df = df.dropna(subset=["metrics.score"])
107
+ df = df.loc[df["metrics.score"] > 0]
108
+ return df.reset_index(drop=True)
109
+
110
+
111
+ def _empty_table():
112
+ return pd.DataFrame({"Rank": [], "Category": []})
113
+
114
+
115
+ def load_and_rank(
116
+ csv_path: str | Path = "results.csv",
117
+ open_models_only: bool = False,
118
+ open_harnesses_only: bool = False,
119
+ benchmarks: list[str] | None = None,
120
+ models: list[str] | None = None,
121
+ harnesses: list[str] | None = None,
122
+ rank_by: str = "Benchmark Score",
123
+ ) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
124
+ df = _load_csv(csv_path)
125
+ if open_models_only:
126
+ df = df.loc[df["model.is_oss"] == True]
127
+ if open_harnesses_only:
128
+ df = df.loc[df["harness.is_oss"] == True]
129
+ if benchmarks is not None:
130
+ df = df.loc[df["benchmark.name"].isin(benchmarks)]
131
+ if models is not None:
132
+ df = df.loc[df["model.name"].isin(models)]
133
+ if harnesses is not None:
134
+ df = df.loc[df["harness.name"].isin(harnesses)]
135
+
136
+ metcol, descending = RANK_BY_OPTIONS.get(rank_by, ("metrics.score", False))
137
+ df = df.dropna(subset=[metcol])
138
+ if descending:
139
+ df = df.loc[df[metcol] > 0]
140
+ df = df.reset_index(drop=True)
141
+
142
+ if len(df) < 2:
143
+ empty = _empty_table()
144
+ return empty, empty, empty
145
+
146
+ results = []
147
+ for rank_fn in (rank_harnesses, rank_models, rank_pairs):
148
+ try:
149
+ results.append(rank_fn(df, metcol, descending))
150
+ except ValueError:
151
+ results.append(_empty_table())
152
+ return results[0], results[1], results[2]
tests/test_pr2_analytics.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import plotly.graph_objects as go
3
+
4
+ from src.analytics import (
5
+ BENCHMARK_CATALOG,
6
+ benchmark_category,
7
+ benchmarks_for_category,
8
+ cross_benchmark_ranking_df,
9
+ enrich_analysis_df,
10
+ filter_category,
11
+ matrix_df,
12
+ ranking_df,
13
+ )
14
+ from src.charts import create_coverage_matrix_plot, create_matrix_plot, create_tradeoff_plot
15
+
16
+
17
+ def frame():
18
+ return pd.DataFrame(
19
+ [
20
+ {
21
+ "Benchmark": "SWE-Bench Verified", "Model": "a", "Harness": "h", "Run Label": "a / h",
22
+ "Category": "FOSS", "Score": .8, "Score (%)": 80, "Tasks": 10, "Errors": 1,
23
+ "Input Tokens Per Task": 50, "Cache Tokens Per Task": 10, "Output Tokens Per Task": 20,
24
+ "Total Tokens Per Task": 80, "Tokens Per Solved Task": 100, "Cost Per Task": .2,
25
+ "Total Time Per Task": 10, "Agent Time Per Task": 8, "Token Data Available": True,
26
+ },
27
+ {
28
+ "Benchmark": "SWE-Bench Verified", "Model": "b", "Harness": "h", "Run Label": "b / h",
29
+ "Category": "FOSS", "Score": .4, "Score (%)": 40, "Tasks": 10, "Errors": 2,
30
+ "Input Tokens Per Task": 90, "Cache Tokens Per Task": None, "Output Tokens Per Task": 30,
31
+ "Total Tokens Per Task": 120, "Tokens Per Solved Task": 300, "Cost Per Task": .1,
32
+ "Total Time Per Task": 20, "Agent Time Per Task": 15, "Token Data Available": True,
33
+ },
34
+ {
35
+ "Benchmark": "Terminal Bench 2.0", "Model": "a", "Harness": "h", "Run Label": "a / h",
36
+ "Category": "FOSS", "Score": .2, "Score (%)": 20, "Tasks": 10, "Errors": 0,
37
+ "Input Tokens Per Task": 30, "Cache Tokens Per Task": 5, "Output Tokens Per Task": 10,
38
+ "Total Tokens Per Task": 45, "Tokens Per Solved Task": 225, "Cost Per Task": .3,
39
+ "Total Time Per Task": 30, "Agent Time Per Task": 25, "Token Data Available": True,
40
+ },
41
+ {
42
+ "Benchmark": "Terminal Bench 2.0", "Model": "c", "Harness": "h", "Run Label": "c / h",
43
+ "Category": "FOSS", "Score": .9, "Score (%)": 90, "Tasks": 10, "Errors": None,
44
+ "Input Tokens Per Task": None, "Cache Tokens Per Task": None, "Output Tokens Per Task": None,
45
+ "Total Tokens Per Task": None, "Tokens Per Solved Task": None, "Cost Per Task": None,
46
+ "Total Time Per Task": None, "Agent Time Per Task": None, "Token Data Available": False,
47
+ },
48
+ {
49
+ "Benchmark": "New Benchmark", "Model": "z", "Harness": "h", "Run Label": "z / h",
50
+ "Category": "FOSS", "Score": .5, "Score (%)": 50, "Tasks": 10, "Errors": 0,
51
+ "Input Tokens Per Task": 1, "Cache Tokens Per Task": 1, "Output Tokens Per Task": 1,
52
+ "Total Tokens Per Task": 3, "Tokens Per Solved Task": 6, "Cost Per Task": .01,
53
+ "Total Time Per Task": 1, "Agent Time Per Task": 1, "Token Data Available": True,
54
+ },
55
+ ]
56
+ )
57
+
58
+
59
+ def test_benchmark_catalog_and_unknown_fallback():
60
+ assert benchmark_category("SWE-Bench Verified") == "Coding"
61
+ assert benchmark_category("Terminal Bench 2.0") == "Generalist"
62
+ assert benchmark_category("Shellbench") == "Generalist"
63
+ assert benchmark_category("New Benchmark") == "Other"
64
+ assert "SWE-Bench Pro -- Ansible" in BENCHMARK_CATALOG
65
+
66
+
67
+ def test_category_filtering_keeps_unknown_visible_as_other():
68
+ df = frame()
69
+ assert set(benchmarks_for_category(df, "Coding")) == {"SWE-Bench Verified"}
70
+ assert set(filter_category(df, "Generalist")["Benchmark"]) == {"Terminal Bench 2.0"}
71
+ assert set(filter_category(df, "Other")["Benchmark"]) == {"New Benchmark"}
72
+
73
+
74
+ def test_derived_reliability_and_per_success_metrics():
75
+ df = enrich_analysis_df(frame())
76
+ first = df.iloc[0]
77
+ assert first["Execution Error Rate (%)"] == 10
78
+ assert first["Tokens Per Successful Task"] == 100
79
+ assert first["Cost Per Successful Task"] == .25
80
+ assert first["Time Per Successful Task"] == 12.5
81
+ assert pd.isna(df.loc[df["Model"].eq("c"), "Execution Error Rate (%)"]).all()
82
+
83
+
84
+ def test_within_benchmark_percentile_and_rank():
85
+ df = enrich_analysis_df(frame())
86
+ coding = df[df["Benchmark"] == "SWE-Bench Verified"].set_index("Model")
87
+ assert coding.loc["a", "Within-Benchmark Rank"] == 1
88
+ assert coding.loc["b", "Within-Benchmark Rank"] == 2
89
+ assert coding.loc["a", "Within-Benchmark Percentile"] == 100
90
+ assert coding.loc["b", "Within-Benchmark Percentile"] == 0
91
+
92
+
93
+ def test_cross_benchmark_ordering_uses_normalization_and_coverage_threshold():
94
+ df = frame()
95
+ ranked = cross_benchmark_ranking_df(df, minimum_coverage=0.5)
96
+ a = ranked[ranked["Model"] == "a"].iloc[0]
97
+ assert a["Benchmarks Covered"] == 2
98
+ assert a["Eligible Benchmarks"] == 3
99
+ assert a["Normalized Performance"] == 50
100
+ strict = cross_benchmark_ranking_df(df, minimum_coverage=1.0)
101
+ assert strict.empty
102
+
103
+
104
+ def test_token_ranking_excludes_missing_and_orders_lower_first():
105
+ ranked = ranking_df(frame(), "Total tokens", benchmark="Terminal Bench 2.0")
106
+ assert ranked["Model"].tolist() == ["a"]
107
+
108
+
109
+ def test_score_rank_and_metric_matrices_preserve_missing_cells():
110
+ df = frame()
111
+ score = matrix_df(df, "Score")
112
+ rank = matrix_df(df, "Within-benchmark rank")
113
+ cost = matrix_df(df, "Cost")
114
+ assert pd.isna(score.loc["b / h", "Terminal Bench 2.0"])
115
+ assert rank.loc["a / h", "SWE-Bench Verified"] == 1
116
+ assert pd.isna(cost.loc["c / h", "Terminal Bench 2.0"])
117
+
118
+
119
+ def test_coverage_matrix_uses_missing_not_zero_score():
120
+ matrix = matrix_df(frame(), "Coverage")
121
+ assert matrix.loc["a / h", "SWE-Bench Verified"] == 1
122
+ assert pd.isna(matrix.loc["b / h", "Terminal Bench 2.0"])
123
+ figure = create_coverage_matrix_plot(matrix)
124
+ assert isinstance(figure, go.Figure)
125
+ assert "Available" in figure.data[0].text[0] or "Missing" in figure.data[0].text[0]
126
+
127
+
128
+ def test_generic_tradeoff_and_matrix_charts_construct():
129
+ df = enrich_analysis_df(frame())
130
+ figure = create_tradeoff_plot(
131
+ df[df["Benchmark"] == "SWE-Bench Verified"],
132
+ "Total Tokens Per Task", "Score (%)",
133
+ "Total tokens per task", "Score (%)",
134
+ show_pareto_frontier=True,
135
+ )
136
+ matrix_figure = create_matrix_plot(matrix_df(df, "Score"), "Score matrix", "Score (%)")
137
+ assert isinstance(figure, go.Figure)
138
+ assert isinstance(matrix_figure, go.Figure)
139
+ assert any(trace.name == "Pareto frontier" for trace in figure.data)
140
+
141
+
142
+ def test_tradeoff_pareto_supports_lower_is_better_on_both_axes():
143
+ df = pd.DataFrame(
144
+ {
145
+ "Model": ["a", "b", "c"],
146
+ "Harness": ["h", "h", "h"],
147
+ "Benchmark": ["bench", "bench", "bench"],
148
+ "Total Tokens Per Task": [100, 200, 300],
149
+ "Cost Per Task": [0.3, 0.2, 0.4],
150
+ }
151
+ )
152
+ figure = create_tradeoff_plot(
153
+ df,
154
+ "Total Tokens Per Task",
155
+ "Cost Per Task",
156
+ "Tokens",
157
+ "Cost",
158
+ show_pareto_frontier=True,
159
+ lower_x_is_better=True,
160
+ higher_y_is_better=False,
161
+ )
162
+ frontier = next(trace for trace in figure.data if trace.name == "Pareto frontier")
163
+ assert list(frontier.x) == [100, 200]
164
+ assert list(frontier.y) == [0.3, 0.2]
165
+
166
+
167
+ def test_matrix_can_color_by_percentile_but_display_raw_values():
168
+ color_matrix = pd.DataFrame([[100.0, 0.0]], index=["a / h"], columns=["b1", "b2"] )
169
+ raw_matrix = pd.DataFrame([[82.5, 41.25]], index=["a / h"], columns=["b1", "b2"] )
170
+ figure = create_matrix_plot(
171
+ color_matrix,
172
+ "Score matrix",
173
+ "Within-benchmark percentile",
174
+ display_matrix=raw_matrix,
175
+ display_metric_label="Benchmark score (%)",
176
+ )
177
+ assert list(figure.data[0].z[0]) == [100.0, 0.0]
178
+ assert list(figure.data[0].text[0]) == ["82.5", "41.25"]
179
+ assert "Benchmark score (%)" in figure.data[0].hovertemplate
180
+
181
+
182
+ def test_ranking_plot_order_can_be_value_or_alphabetical():
183
+ from src.charts import create_ranking_plot
184
+
185
+ df = pd.DataFrame(
186
+ {
187
+ "Model": ["b", "a", "c"],
188
+ "Harness": ["h", "h", "h"],
189
+ "Benchmark": ["bench", "bench", "bench"],
190
+ "Score (%)": [20, 10, 30],
191
+ }
192
+ )
193
+ largest = create_ranking_plot(
194
+ df, "Score (%)", "Score", True, sort_order="Largest value first"
195
+ )
196
+ lowest = create_ranking_plot(
197
+ df, "Score (%)", "Score", True, sort_order="Lowest value first"
198
+ )
199
+ alpha = create_ranking_plot(
200
+ df, "Score (%)", "Score", True, sort_order="Alphabetical (A–Z)"
201
+ )
202
+
203
+ assert list(largest.layout.yaxis.categoryarray) == ["c / h", "b / h", "a / h"]
204
+ assert list(lowest.layout.yaxis.categoryarray) == ["a / h", "b / h", "c / h"]
205
+ assert list(alpha.layout.yaxis.categoryarray) == ["a / h", "b / h", "c / h"]
tests/test_token_efficiency.py CHANGED
@@ -75,16 +75,18 @@ def make_result(
75
  )
76
 
77
 
78
- def test_cost_vs_performance_tab_removed_without_efficiency_cost_regression():
79
  app_source = Path("app.py").read_text()
80
 
81
  assert 'gr.Tab("💰 Cost vs Performance")' not in app_source
82
  assert "cost_benchmark" not in app_source
83
  assert "cost_controls" not in app_source
84
  assert "render_score_vs_cost_plot" not in app_source
85
- assert 'with gr.Tab("⚡ Efficiency")' in app_source
86
- assert app_source.index('with gr.Tab("🏆 Leaderboard")') < app_source.index('with gr.Tab("⚡ Efficiency")')
87
- assert app_source.index('with gr.Tab("⚡ Efficiency")') < app_source.index('with gr.Tab("🏃 Benchmark Runs")')
 
 
88
 
89
  def test_analysis_df_columns_and_derived_metrics():
90
  dataframe = get_analysis_df(
@@ -385,9 +387,27 @@ def test_efficiency_figure_uses_responsive_autosizing_without_fixed_width():
385
  assert figure.layout.height is None
386
 
387
 
388
- def test_shared_plot_container_has_minimum_height_and_efficiency_tab_refresh():
389
  app_source = (Path(__file__).parents[1] / "app.py").read_text()
390
 
391
  assert "RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420" in app_source
392
  assert "min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px" in app_source
393
- assert "efficiency_tab.select(" in app_source
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  )
76
 
77
 
78
+ def test_cost_vs_performance_tab_removed_and_navigation_is_single_layer():
79
  app_source = Path("app.py").read_text()
80
 
81
  assert 'gr.Tab("💰 Cost vs Performance")' not in app_source
82
  assert "cost_benchmark" not in app_source
83
  assert "cost_controls" not in app_source
84
  assert "render_score_vs_cost_plot" not in app_source
85
+ assert 'with gr.Tab("Overview")' not in app_source
86
+ assert app_source.count("with gr.Tabs():") == 1
87
+ assert 'with gr.Tab("Rankings")' in app_source
88
+ assert 'with gr.Tab("Trade-offs")' in app_source
89
+ assert 'with gr.Tab("Matrices")' in app_source
90
 
91
  def test_analysis_df_columns_and_derived_metrics():
92
  dataframe = get_analysis_df(
 
387
  assert figure.layout.height is None
388
 
389
 
390
+ def test_shared_plot_container_has_minimum_height_and_scrollable_tables():
391
  app_source = (Path(__file__).parents[1] / "app.py").read_text()
392
 
393
  assert "RESPONSIVE_PLOT_MIN_HEIGHT_PX = 420" in app_source
394
  assert "min-height: {RESPONSIVE_PLOT_MIN_HEIGHT_PX}px" in app_source
395
+ assert "TABLE_MAX_HEIGHT_PX = 720" in app_source
396
+ assert "max_height=TABLE_MAX_HEIGHT_PX" in app_source
397
+
398
+
399
+ def test_page_tables_are_single_and_below_visualizations_and_plots_resize():
400
+ app_source = Path("app.py").read_text()
401
+
402
+ rankings = app_source[app_source.index('with gr.Tab("Rankings")'):app_source.index('with gr.Tab("Trade-offs")')]
403
+ tradeoffs = app_source[app_source.index('with gr.Tab("Trade-offs")'):app_source.index('with gr.Tab("Matrices")')]
404
+
405
+ assert rankings.count("gr.Dataframe(") == 1
406
+ assert tradeoffs.count("gr.Dataframe(") == 1
407
+ assert rankings.rindex("gr.Dataframe(") > rankings.rindex("gr.Plot(")
408
+ assert tradeoffs.rindex("gr.Dataframe(") > tradeoffs.rindex("gr.Plot(")
409
+ assert '"Largest value first"' in rankings
410
+ assert '"Lowest value first"' in rankings
411
+ assert '"Alphabetical (A–Z)"' in rankings
412
+ assert "ResizeObserver" in app_source
413
+ assert "window.Plotly.Plots.resize" in app_source