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 +798 -142
- requirements.txt +2 -0
- src/analytics.py +314 -0
- src/charts.py +259 -2
- src/leaderboard.py +52 -26
- src/rankings.py +152 -0
- tests/test_pr2_analytics.py +205 -0
- tests/test_token_efficiency.py +26 -6
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:
|
| 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 =
|
|
|
|
|
|
|
|
|
|
| 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,
|
| 177 |
|
| 178 |
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 193 |
-
|
|
|
|
| 194 |
</p>
|
| 195 |
-
<div
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 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("
|
| 255 |
-
gr.Markdown(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
with gr.Row():
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
value=
|
| 266 |
-
label="
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
label="Image background"
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
)
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
control.change(
|
| 294 |
-
fn=lambda
|
| 295 |
-
|
| 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 |
-
"###
|
| 304 |
-
"
|
| 305 |
-
"
|
| 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 |
-
|
| 343 |
-
|
| 344 |
-
"Model",
|
| 345 |
-
"Log",
|
| 346 |
-
True,
|
| 347 |
-
False,
|
| 348 |
-
DEFAULT_COLOR_PALETTE,
|
| 349 |
-
DEFAULT_PLOT_BACKGROUND,
|
| 350 |
)
|
| 351 |
-
efficiency_note = gr.Markdown(initial_efficiency[
|
| 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 |
-
|
| 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,
|
| 379 |
)
|
| 380 |
|
| 381 |
-
#
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
|
| 390 |
-
|
| 391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
|
| 393 |
-
with gr.Tab("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 219 |
dataframe: pd.DataFrame,
|
| 220 |
-
|
| 221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
) -> pd.DataFrame:
|
| 223 |
-
"""Return deterministic non-dominated points for
|
| 224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
return dataframe.iloc[0:0].copy()
|
| 226 |
|
| 227 |
candidates = dataframe.copy()
|
| 228 |
-
candidates[
|
| 229 |
-
candidates[
|
| 230 |
-
candidates = candidates.dropna(subset=[
|
| 231 |
-
|
|
|
|
| 232 |
if candidates.empty:
|
| 233 |
return candidates
|
| 234 |
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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("
|
| 86 |
-
assert app_source.
|
| 87 |
-
assert
|
|
|
|
|
|
|
| 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
|
| 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 "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|