"""Gradio component builders for the leaderboard. Each function creates one piece of the UI inside the surrounding Blocks/render context. No data-path logic lives here (see ``data_loading.py``) and no copy lives here (see ``website_texts.py``). """ from __future__ import annotations import html import math import re from dataclasses import replace from itertools import groupby from pathlib import Path import gradio as gr import pandas as pd import website_texts from constants import Constants, model_type_color, model_type_emoji, variant_color from data_loading import ( BEYOND_SUBSET_LABELS, DATASET_LABELS, SYSTEM_CATEGORY_LABELS, DATASET_SIZE_NOTE, TASK_LABELS, BeyondSubset, LBContainer, Subset, load_leaderboard_csv, parse_model, entrants_categories, subset_name, unzip_png, widest_entrants_key, ) # --------------------------------------------------------------------------- # # Full per-subset leaderboard table # --------------------------------------------------------------------------- # _IMPUTED_INFO = ( "We impute the performance for models that cannot run on all datasets due to" " task or dataset size constraints. We impute with the performance of a" " default RandomForest. We add a postfix [X% IMPUTED] to the model if any" " results were imputed. The X% shows the percentage of datasets that were" " imputed. In general, imputation negatively represents the model" " performance, punishing the model for not being able to run on all datasets." ) # Variants a model is evaluated in; all selected by default, and any combination is # valid. Systems carry no variant tag of their own but tune and ensemble internally, so # they belong with those. VARIANT_VALUES = ["default", "tuned", "tuned + ensembled"] # Columns that drive the filters or are folded into another cell; kept on the frame, # never rendered as their own column. _INTERNAL_COLUMNS = ["TypeName", "RefModel", "Imputed", "_variant", "_base", "_search"] # Shown as "(+115/-110)" after the Elo value instead of as a column of its own. _CI_COLUMN = "Elo 95% CI" _ELO_COLUMN = "Elo [⬆️]" # Rendered as a ✔️ badge on the model name, the way the overview does it. _VERIFIED_COLUMN = "Verified" # Always shown, so they are not offered in the column picker. _ALWAYS_SHOWN = ["#", "Type", "Model"] # Column header -> the metric-reference entry whose text becomes its hover hint, so # the tooltips and the documented definitions cannot drift apart. _LB_TOOLTIP_METRIC = { _ELO_COLUMN: "🏆 Elo (ranking aggregation)", "Score [⬆️]": "📊 Score", "Improvability (%) [⬇️]": "📉 Improvability (%)", "Rank [⬇️]": "🔢 Average Rank", "Harmonic Rank [⬇️]": "🎯 Harmonic Rank", "Median Train Time (s/1K) [⬇️]": "⏱️ Train / Predict Time (s/1K)", "Median Predict Time (s/1K) [⬇️]": "⏱️ Train / Predict Time (s/1K)", "Imputed (%) [⬇️]": "🧩 Imputed (%)", } _LB_FIXED_TOOLTIPS = { "#": "Position in this subset's Elo ranking, as published.", "Type": "Model family; see the legend above the table.", "Model": ( "The model, its configuration variant in brackets, and ✔️ when the " "implementation was verified by its authors or the maintainers. Links to the " "implementation." ), "Hardware": "The hardware the reported runtimes were measured on.", } # Which direction is good, per column, for the per-column heatmap. Columns absent # from this map (#, Hardware) are left unshaded. _LB_HIGHER_IS_BETTER = { _ELO_COLUMN: True, "Score [⬆️]": True, "Rank [⬇️]": False, "Harmonic Rank [⬇️]": False, "Improvability (%) [⬇️]": False, "Median Train Time (s/1K) [⬇️]": False, "Median Predict Time (s/1K) [⬇️]": False, "Imputed (%) [⬇️]": False, } # Runtimes span orders of magnitude, so shading them linearly paints every model # the same green and only the slowest one red. Normalize those in log space. _LB_LOG_SCALED = { "Median Train Time (s/1K) [⬇️]", "Median Predict Time (s/1K) [⬇️]", } # The marker the plot explorers put on an imputed method (see the generated # *_explorer.html); reused here so the same thing looks the same everywhere. IMPUTED_MARK = "‡" # Per-column value formatting; everything else falls back to _format_value. _LB_FORMATS = { _ELO_COLUMN: lambda v: str(int(round(v))), "Score [⬆️]": lambda v: f"{v:.3f}", "Rank [⬇️]": lambda v: f"{v:.2f}", "Harmonic Rank [⬇️]": lambda v: f"{v:.2f}", "Improvability (%) [⬇️]": lambda v: f"{v:.2f}", "Median Train Time (s/1K) [⬇️]": lambda v: f"{v:.2f}", "Median Predict Time (s/1K) [⬇️]": lambda v: f"{v:.3f}", "Imputed (%) [⬇️]": lambda v: f"{v:.1f}", } def _column_tooltip(column: str) -> str | None: """Hover hint for a leaderboard column header, or None when there is nothing to add.""" if column in _LB_FIXED_TOOLTIPS: return _LB_FIXED_TOOLTIPS[column] name = _LB_TOOLTIP_METRIC.get(column) if not name: return None for metric in website_texts.METRICS: if metric["name"] == name: return f"{metric['details']} · Why we use it: {metric['why']}" return None def _format_value(column: str, value) -> str: """Display string for one cell; `data-sort` keeps the raw value for sorting.""" if value is None or (isinstance(value, float) and pd.isna(value)): return "–" formatter = _LB_FORMATS.get(column) if formatter and isinstance(value, (int, float)) and not isinstance(value, bool): return formatter(value) if isinstance(value, float) and value.is_integer(): return str(int(value)) return str(value) def filter_leaderboard( df: pd.DataFrame, *, models: list[str], variants: list[str], show_imputed: bool, search: str = "", ) -> pd.DataFrame: """Apply the table's row filters. Pure so it can be tested without a Gradio context. `df` carries the internal ``_base`` / ``_variant`` / ``Imputed`` / ``_search`` columns added by :func:`_prepare_leaderboard`. `models` is the selected individual models: family chips are bulk selectors over that list, not a filter of their own. Column selection is applied when rendering, not here. """ sub = df[df["_base"].isin(models)] # Only narrow when the reader has actually deselected something, so a row whose # variant we failed to classify can never be dropped silently. if variants is not None and set(variants) != set(VARIANT_VALUES): sub = sub[sub["_variant"].isin(variants)] if not show_imputed: sub = sub[~sub["Imputed"].astype(bool)] term = (search or "").strip().lower() if term: sub = sub[sub["_search"].str.contains(re.escape(term), regex=True)] return sub def _prepare_leaderboard(raw: pd.DataFrame) -> pd.DataFrame: """Add the internal columns the filters and the renderer need.""" df = raw.copy() parsed = [parse_model(str(m)) for m in raw["Model"]] df["_base"] = [base for base, _, _ in parsed] # A system has no variant tag of its own, but it tunes and ensembles internally, so the # variant filter groups it with the tuned ensembles. Keyed off the family rather than the # name, so this holds for every system and not only AutoGluon. df["_variant"] = [ "tuned + ensembled" if not variant and type_name == Constants.system else variant for (_, variant, _), type_name in zip(parsed, raw["TypeName"], strict=True) ] df["_search"] = [ f"{base} {variant} {type_name}".lower() for (base, variant, _), type_name in zip(parsed, raw["TypeName"], strict=True) ] return df def leaderboard_families(df: pd.DataFrame) -> list[tuple[str, list[str]]]: """(family, models) pairs present in `df`, in the legend's family order.""" families = [] for type_name in model_type_emoji: models = sorted(set(df.loc[df["TypeName"] == type_name, "_base"])) if models: families.append((type_name, models)) return families def fam_chip_colors(families: list[tuple[str, list[str]]]) -> str: """`--fam` per family, so each chiprow carries its family's colour.""" rules = [ f".ta-fam-{re.sub(r'[^a-z0-9]+', '-', type_name.lower())}" f"{{--fam:{model_type_color.get(type_name, '#9e9e9e')};}}" for type_name, _ in families ] # The variant toggles take their colours from the Leaderboard Overview explorer. # Generated from the same list the choices come from, so the nth-of-type index # cannot drift from the option order. rules += [ f".ta-variants label:nth-of-type({i + 1}){{--fam:{variant_color[value]};}}" for i, value in enumerate(VARIANT_VALUES) if value in variant_color ] return "".join(rules) def _group_handler(index: int, models: list[str], render): """A model chip group changed: bring its family chip in line, redraw the table.""" def handler(*values): selected = values[index] or [] return gr.update(value=set(selected) == set(models)), render(*values) return handler def _family_handler(index: int, models: list[str], render): """A family chip was toggled: select or clear all of its models, redraw the table.""" def handler(checked, *values): updated = list(values) updated[index] = list(models) if checked else [] return gr.update(value=updated[index]), render(*updated) return handler def _heatmap_bounds(df: pd.DataFrame, columns: list[str]) -> dict[str, tuple[float, float]]: """Per-column (lo, hi) over the rendered rows, in the scale used for shading.""" bounds = {} for column in columns: if column not in _LB_HIGHER_IS_BETTER or column not in df.columns: continue values = pd.to_numeric(df[column], errors="coerce").dropna() if column in _LB_LOG_SCALED: values = values[values > 0] values = values.apply(math.log10) if len(values) < 2 or values.min() == values.max(): continue bounds[column] = (float(values.min()), float(values.max())) return bounds def _heatmap_style(column: str, value: float, bounds: dict[str, tuple[float, float]]) -> str: """Inline background for one shaded cell, or "" when the column is not shaded.""" if column not in bounds: return "" lo, hi = bounds[column] scaled = value if column in _LB_LOG_SCALED: if value <= 0: return "" scaled = math.log10(value) frac_best = (scaled - lo) / (hi - lo) if not _LB_HIGHER_IS_BETTER[column]: frac_best = 1 - frac_best frac_best = max(0.0, min(1.0, frac_best)) return f' style="background:{_interp_color(1 - frac_best)};color:#f7f7f7;"' def _model_cell(row: pd.Series) -> str: """The Model cell, styled like the cross-subset overview's.""" color = model_type_color.get(row["TypeName"], "#9e9e9e") _, variant, url = parse_model(str(row["Model"])) name = html.escape(row["_base"]) if variant: name += f' ({html.escape(variant)})' if str(row.get(_VERIFIED_COLUMN, "")).strip() == "✔️": name += ' ✔️' if bool(row.get("Imputed", False)): name += ( f' {IMPUTED_MARK}' ) if url: return ( f'{name}' f'' ) return f'{name}' def leaderboard_table_html(df: pd.DataFrame, columns: list[str], table_id: str) -> str: """Render the leaderboard as a sortable HTML table in the overview's style. Every header is clickable (``taSortTable`` in ``main.py``'s head) and carries the column's definition as a hover hint. Numeric cells put the raw value in ``data-sort`` and the formatted one in the text, which is what lets the Elo cell show its confidence interval without that text taking part in the sort. """ metric_columns = [c for c in columns if c not in _ALWAYS_SHOWN] header = [ '
{caption} · click a column header to sort, hover one for its ' f"definition · {shaded} · {IMPUTED_MARK} marks a model with imputed results
" ) def make_leaderboard(lb: LBContainer, *, collapsible: bool = False) -> None: """The full leaderboard table for one subset. The table is a generated artifact (`leaderboard_table.html`, built by `tabarena.plot.interactive.leaderboard_table`), embedded the same way as the other interactive plots. It lives upstream so that it reuses the explorers' family and variant colours, chip components and imputation markers rather than reimplementing them here, where they drifted. Subsets whose artifacts predate it fall back to :func:`make_leaderboard_gradio`, this app's own table. """ content = lb.html_content("leaderboard_table") if content is None: make_leaderboard_gradio(lb) return if collapsible: # Collapsed by default: the table is the detailed reference at the end of the page, # not the thing a reader arrives for, and it is 80-odd rows tall when open. The # accordion carries the anchor so the contents chip above can open it. with gr.Accordion( "⭐ Full Leaderboard Table", open=False, elem_id=_panel_uid(lb, "leaderboard_table") ): _leaderboard_card(lb, content, show_title=False) return with gr.Column(elem_classes="ta-lb", elem_id=_panel_uid(lb, "leaderboard_table")): _leaderboard_card(lb, content, show_title=True) def _leaderboard_card(lb: LBContainer, content: str, *, show_title: bool) -> None: """The table's header bar and its frame. ``show_title`` is off inside an accordion, whose own label already names it. """ gr.HTML( '" ) gr.HTML(_interactive_plot_iframe(content, f"Full leaderboard table, {lb.name}", height=1100)) def make_leaderboard_gradio(lb: LBContainer) -> None: """The fallback table, rendered by this app rather than embedded. Kept for subsets whose artifacts were generated before `leaderboard_table.html` existed. :func:`make_leaderboard` is the current path; prefer fixing the upstream generator over this. Replaces the third-party `gradio_leaderboard` widget (which pinned Gradio < 6) with the same hand-rolled HTML table the cross-subset overview uses: type pills, dotted-underline model links, tooltip-carrying headers, sticky header and scroll box. Model selection mirrors the plot explorers' edit view — a family chip above its models, in the family's colour. Sorting and CSV export are client-side (`taSortTable` / `taExportTable`); the filters round-trip to rebuild the HTML. """ raw = lb.load_df() has_imputed = bool(raw["Imputed"].any()) df = _prepare_leaderboard(raw) if not has_imputed: df = df.drop(columns=["Imputed (%) [⬇️]"]) # The CI and Verified columns are folded into the Elo and Model cells. renderable = [ c for c in df.columns if c not in _INTERNAL_COLUMNS + [_CI_COLUMN, _VERIFIED_COLUMN] ] optional = [c for c in renderable if c not in _ALWAYS_SHOWN] families = leaderboard_families(df) table_id = f"lb-{lb.subset.rel_path.replace('/', '-')}" def render(*values) -> str: """Redraw the table from the controls' values, positional as Gradio passes them.""" count = len(families) models = [m for group in values[:count] for m in (group or [])] variants, show_imputed, columns, search = values[count : count + 4] sub = filter_leaderboard( df, models=models, variants=variants, show_imputed=show_imputed or not has_imputed, search=search, ) chosen = [c for c in renderable if c in set(columns or []) or c in _ALWAYS_SHOWN] return leaderboard_table_html(sub, chosen, table_id) with gr.Column(elem_classes="ta-lb", elem_id=_panel_uid(lb, "leaderboard_table")): gr.HTML( # The table borrows the overview's stylesheet; inject it here rather than # relying on the legend, which this card no longer draws (the family chips # below say the same thing, in colour). _OVERVIEW_CSS + f"" + '" ) # Model selection, laid out like the Pareto explorer's chiprows: one row per # family, the family chip toggling all of its models at once. fam_toggles, model_groups = [], [] for type_name, models in families: fam_class = f"ta-fam-{re.sub(r'[^a-z0-9]+', '-', type_name.lower())}" with gr.Row(elem_classes="ta-chiprow"): fam_toggles.append( gr.Checkbox( value=True, label=f"{model_type_emoji.get(type_name, '')} {type_name} ×{len(models)}", show_label=False, container=False, interactive=True, elem_classes=["ta-famchip", fam_class], scale=0, min_width=210, ) ) model_groups.append( gr.CheckboxGroup( choices=models, value=models, show_label=False, container=False, interactive=True, elem_classes=["ta-chips", fam_class], scale=1, ) ) with gr.Row(elem_classes="ta-lb-controls"): variant = gr.CheckboxGroup( choices=VARIANT_VALUES, value=VARIANT_VALUES, label="⚙️ Variants", interactive=True, elem_classes=["ta-btns", "ta-variants"], scale=3, min_width=290, ) show_imputed = gr.Checkbox( value=True, label=f"{IMPUTED_MARK} Include imputed", info=_IMPUTED_INFO, interactive=True, visible=has_imputed, elem_classes=["ta-btns", "ta-btns-imputed"], scale=1, min_width=190, ) columns = gr.Dropdown( choices=optional, value=optional, multiselect=True, label="📋 Columns", info="# / Type / Model always shown", interactive=True, scale=2, min_width=220, ) search = gr.Textbox( label="🔍 Search", placeholder="model or type…", interactive=True, scale=1, min_width=150, ) state = [*model_groups, variant, show_imputed, columns, search] table = gr.HTML(render(*[c.value for c in state])) # `.input` rather than `.change`: a family chip rewrites its group's value and # each group rewrites its family chip, so reacting to programmatic changes too # would let the two bounce off each other. for index, (models, group, fam) in enumerate( zip([m for _, m in families], model_groups, fam_toggles, strict=True) ): group.input( _group_handler(index, models, render), state, [fam, table], api_visibility="private", ) fam.input( _family_handler(index, models, render), [fam, *state], [group, table], api_visibility="private", ) for control in (variant, show_imputed, columns, search): control.input(render, state, table, api_visibility="private") # --------------------------------------------------------------------------- # # Per-subset figures # --------------------------------------------------------------------------- # def _interactive_plot_iframe(content: str, title: str, height: int = 720, extra_attrs: str = "") -> str: """Wrap a self-contained interactive plot page in a sandboxed iframe. ``srcdoc`` + a ``sandbox`` runs the page's inline JS without granting it same-origin access; the page has no external dependencies by construction. ``allow-downloads`` is the one extra capability, for the paper view's SVG/PNG figure export — without it the sandbox silently drops the download. Three integration details: - The site forces the dark theme, so stamp ``data-theme="dark"`` on the page's root element (the explorer's CSS honors it) — otherwise the frame would follow the viewer's OS preference and could render light-on-dark. - The explorer posts its content height via ``postMessage``; the listener registered in ``main.py``'s ``head`` resizes the iframe to fit, so the frame never shows an inner scrollbar. ``height`` is only the initial placeholder until the first message arrives. - The paper view is toggled from the panel header over the same channel (see ``main.taPaperView``), since the frame is cross-origin. ``extra_attrs`` is spliced into the tag for frames the host has to configure once they are up (the per-dataset browser reads its opening filters off ``data-`` attributes). """ content = content.replace('', '', 1) return ( f'' ) def _panel_uid(lb: LBContainer, key: str) -> str: """A DOM-safe id unique to one (subset, figure) panel.""" return "ta-fig-" + re.sub(r"[^a-z0-9]+", "-", f"{lb.subset.rel_path}-{key}".lower()).strip("-") def _switchable_figure( lb: LBContainer, *, html_name: str, img_name: str, label: str, height: int = 500, ) -> None: """A figure panel: the interactive explorer, with a switch to the static PNG when one ships. Both views are rendered up front and flipped client-side by ``main.taSwitchView`` (no server round trip). Either half can be absent. TabArena ships explorers only: the static PNGs were a second copy of what the explorer already renders and exports, so they are no longer published and the "🖼️ Static figure" button is dropped. BeyondArena is the other way round for most of its figures, and a subset whose artifacts predate the explorers still falls back to the PNG on its own. """ uid = _panel_uid(lb, html_name) content = lb.html_content(html_name) if content is None: # Static-only fallback still answers to the anchor, so a contents chip works either way. gr.Image( value=lb.image_path(img_name), label=label, height=height, show_label=True, elem_id=uid, ) return has_static = lb.has_image(img_name) # "Name [subset]" -> the name as the heading, the subset as a quiet qualifier, # so the eye finds where each figure block starts. name, _, subset = label.partition(" [") subset_html = f'' if subset else "" # `elem_id` on the card itself: this is what the contents chips scroll to. with gr.Column(elem_classes="ta-figpanel", elem_id=uid): gr.HTML( f'" ) with gr.Column(elem_id=f"{uid}-i", elem_classes="ta-figview"): gr.HTML(_interactive_plot_iframe(content, title=label)) if has_static: with gr.Column(elem_id=f"{uid}-s", elem_classes=["ta-figview", "ta-hidden"]): # No fixed height: the CSS lets the PNG span the panel width and # take whatever height its aspect ratio needs, so a wide figure is # not letterboxed inside a tall box (and a tall one is not shrunk). gr.Image( value=lb.image_path(img_name), show_label=False, ) # What the reader is optimizing for -> which figure answers it first, and (for the Pareto # panel) which time axis it plots against. Both Pareto explorers are generated from the same # points upstream, so switching axis is a different artifact, not a different computation. # Insertion order = selector order; first = default. # Prediction speed before training speed: it is what serving costs, so it is the constraint # more readers arrive with. CARE_LABELS = { "quality": "🏆 Best quality", "infer": "⚡ Fast predictions", "train": "⏱️ Fast to train", } # The second half of "I care about": which headline metric leads. Elo and Improvability # answer different questions, and the leaderboard has always reported both. METRIC_LABELS = { "elo": "🏅 Consistent wins", "imp": "📉 Relative gains", } METRIC_NOTES = { "elo": ( "Ranks by Elo: how reliably a method beats the others head to head, whatever the margin." ), "imp": ( "Ranks by Improvability: how far a method sits from the best one on each dataset, in percent." ), } # The overview metric each choice selects, and the complement one panel stays pinned to. METRIC_TO_OVERVIEW = {"elo": "Elo", "imp": "Improvability (%)"} METRIC_COMPLEMENT = {"elo": "imp", "imp": "elo"} CARE_NOTES = { "quality": "Ranked purely on accuracy. Start here if compute is not your constraint.", "infer": "Leads with the accuracy-versus-prediction-time trade-off, which is what serving costs.", "train": "Leads with the accuracy-versus-training-time trade-off.", } _PARETO_PANELS = { "train": ("pareto_front_explorer_time_train", "pareto_front_improvability_vs_time_train", "train time"), "infer": ("pareto_front_explorer", "pareto_front_improvability_vs_time_infer", "inference time"), } def _pareto_panel(lb: LBContainer, name: str, axis: str) -> None: """The Pareto panel plotted against one time axis, falling back to the other.""" html_name, img_name, axis_label = _PARETO_PANELS[axis] # A subset generated before the train-time explorer shipped only has the inference one. if lb.html_content(html_name) is None and not lb.has_image(img_name): html_name, img_name, axis_label = _PARETO_PANELS["infer"] _switchable_figure( lb, html_name=html_name, img_name=img_name, label=f"Pareto Front, {axis_label} [{name}]", ) def _overview_panel(lb: LBContainer, name: str) -> None: _switchable_figure( lb, html_name="leaderboard_overview_explorer", img_name="tuning-impact-elo", label=f"Leaderboard Overview [{name}]", # The static bar figure is ~7:1; a taller box only letterboxes it. height=320, ) def _figure_plan(lb: LBContainer, care: str, metric: str) -> list[tuple[str, str, str]]: """The figure stack for this subset as ``(panel key, chip label, pinned metric)``, in order. `care` sets the order, the Pareto time axis, and which figure gets the metric the reader chose: whichever leads. Asking for quality puts it on the Leaderboard Overview; asking for speed puts it on the Pareto front. The figure that does not lead carries the other metric, which is what keeps both on the page whichever was picked. The Pareto front and the tuning trajectories always match each other, because they are read together (where a method lands on the trade-off, and how it got there) and one showing Elo while the other showed Improvability would make that comparison nonsense. One list drives both the jump links and the panels themselves, so the contents page cannot promise a figure the page does not render, or list them in the wrong order. """ axis = "train" if care == "train" else "infer" other = METRIC_COMPLEMENT[metric] # The lead figure gets the chosen metric; the one under it gets the complement. overview_metric, pareto_metric = (metric, other) if care == "quality" else (other, metric) pareto_label = "Pareto Front, " + _PARETO_PANELS[axis][2] stack = [ ("leaderboard_overview_explorer", "Leaderboard Overview", overview_metric), (axis, pareto_label, pareto_metric), ] if care != "quality": stack.reverse() # Read alongside the Pareto front, so it shares its metric. stack.append(("tuning_trajectories_explorer", "Tuning Trajectories", pareto_metric)) # Neither the win-rate matrix nor the two collapsed blocks have an Elo/Improvability # switch, so their pins are no-ops; they are listed because the contents should name # everything below. stack.append(("winrate_explorer", "Win-rate Matrix", pareto_metric)) stack.append(("per_dataset_explorer", "Per-dataset Results", pareto_metric)) stack.append(("leaderboard_table", "Full Leaderboard Table", pareto_metric)) return stack #: Panels that live inside a collapsed accordion. Their contents chip carries the anchor id a #: second time so the click handler can open the section as well as scroll to it. _COLLAPSED_PANELS = frozenset({"per_dataset_explorer", "leaderboard_table"}) #: Panels that have a page section of their own. The chip scrolls to that section's heading #: rather than to the panel, so the reader lands on the title and its one-line explanation. _PANEL_SECTIONS = {"per_dataset_explorer": "ta-perdataset-section"} def make_figure_contents(lb: LBContainer, care: str = "quality", metric: str = "elo") -> None: """A row of buttons naming the figures below, in the order they appear, each jumping to one. The order changes with "I care about", so saying what is coming and in what sequence saves the reader scrolling to find out. """ # A plain anchor, deliberately. These used to call `scrollIntoView` and cancel the default, # which did nothing at all inside a Hugging Face Space: the section is often below the # bottom of the Space's own frame, and a *scripted* scroll is not allowed to move a # cross-origin parent, while following an anchor is -- it is the reader's own navigation. # Cancelling the default therefore threw away the one mechanism that works. Smoothness comes # from `scroll-behavior` in the stylesheet instead, and the offset from `scroll-margin-top`. links = [] for key, label, _ in _figure_plan(lb, care, metric): html_name = _PARETO_PANELS[key][0] if key in _PARETO_PANELS else key uid = _panel_uid(lb, html_name) # A collapsed section has to be opened as well as scrolled to; `main.taOpenSection` # reads this attribute and clicks the accordion's own header. expand = f' data-open="{uid}"' if key in _COLLAPSED_PANELS else "" target = _PANEL_SECTIONS.get(key, uid) links.append(f'{html.escape(label)}') gr.HTML('No overview data available.
") # The leading column decides which variant stands for each model, so the kept row is the one # the reader is ranking by. keep = None if one_per_model: lead = next((r for lbl, _, r in loaded if lbl not in _FIXED_COLUMN_SPECS), loaded[0][2]) best = _subset_best(lead, higher_is_better) keep = set(zip(best["base"], best["variant"])) for label, group, rows in loaded: keys = list(zip(rows["base"], rows["variant"])) if keep is not None: rows = rows[[k in keep for k in keys]] keys = [k for k in keys if k in keep] if rows.empty: continue val_by_col[label] = dict(zip(keys, rows["val"])) imp_by_col[label] = dict(zip(keys, rows["imputed"])) present.append((label, group)) for key, (_, row) in zip(keys, rows.iterrows()): meta.setdefault( key, { "type_name": row["TypeName"], "emoji": row["Type"], "variant": row["variant"], "url": row["url"], "verified": row["verified"], }, ) if not present: return gr.HTML("No overview data available.
") # Bring each selected column to the front of its own group, keeping the group order intact. highlighted = [c for c in _selected_overview_columns(tasks, datasets, care) if c in val_by_col] if highlighted: ordered: list[tuple[str, str]] = [] for _group, items in groupby(present, key=lambda x: x[1]): items = list(items) lead = [i for i in items if i[0] in highlighted] ordered.extend(lead + [i for i in items if i not in lead]) present = ordered # Only explain the System pill when one is actually on screen. has_systems = any(m["type_name"] == Constants.system for m in meta.values()) sort_label = present[0][0] worst_sort = float("-inf") if higher_is_better else float("inf") entries = sorted( meta, key=lambda k: val_by_col[sort_label].get(k, worst_sort), reverse=higher_is_better ) rank_by_col, bounds = {}, {} for label, _ in present: col_higher_better = ( _FIXED_COLUMN_SPECS[label][1] if label in _FIXED_COLUMN_SPECS else higher_is_better ) col = val_by_col[label] ranked = sorted(col, key=lambda b: col[b], reverse=col_higher_better) rank_by_col[label] = {b: i + 1 for i, b in enumerate(ranked[:3])} bounds[label] = (min(col.values()), max(col.values())) if col else (0.0, 1.0) # -- Grouped header (two rows) row1 = ['