Leaderboard / assets /app.js
schaeferbasti's picture
Leaderboard v0.2.0
2efb236
Raw History Blame Contribute Delete
10.1 kB
// SelectArena leaderboard: a static page over the generated files in data/.
//
// data/meta.json lists every published subset; each subset folder
// data/subsets/tasks_<t>/models_<m>/budgets_<b>/ holds elo_explorer.html and leaderboard_table.html,
// which are embedded as iframes. The folder names mirror selectarena.website.subsets.Subset.rel_path.
// Every embedded page posts {saFrameHeight: <px>} to this window; the listener below resizes its iframe.
(function () {
'use strict';
var ALL = 'all';
var TASK_LABELS = {
all: 'All tasks',
classification: 'Classification',
binary: 'Binary',
multiclass: 'Multiclass',
regression: 'Regression'
};
var TABS = ['leaderboard', 'datasets', 'robustness', 'about'];
var state = { tab: 'leaderboard', tasks: ALL, model: ALL, budget: ALL };
var meta = null;
var published = {};
function $(id) { return document.getElementById(id); }
function key(s) { return s.tasks + '|' + s.model + '|' + s.budget; }
function subsetDir(s) {
return 'data/subsets/tasks_' + s.tasks + '/models_' + s.model + '/budgets_' + s.budget + '/';
}
function withAxis(axis, value) {
var s = { tasks: state.tasks, model: state.model, budget: state.budget };
s[axis] = value;
return s;
}
// 0.5 -> "0.5", 0.75 -> "0.75", 1 -> "1.0"
function noiseLabel(value) { return Number(value).toFixed(2).replace(/0$/, ''); }
function budgetLabel(index, total) {
var label = 'Budget ' + (index + 1);
if (total && index === 0) return label + ' (smallest)';
if (total && index === total - 1) return label + ' (largest)';
return label;
}
// ---- URL hash: #tab=...&tasks=...&model=...&budget=... (shareable selections) ----
function readHash() {
var params = new URLSearchParams(window.location.hash.slice(1));
['tab', 'tasks', 'model', 'budget'].forEach(function (k) {
var v = params.get(k);
if (v) state[k] = v;
});
if (TABS.indexOf(state.tab) < 0) state.tab = 'leaderboard';
}
function writeHash() {
var params = new URLSearchParams();
if (state.tab !== 'leaderboard') params.set('tab', state.tab);
['tasks', 'model', 'budget'].forEach(function (k) { if (state[k] !== ALL) params.set(k, state[k]); });
var hash = params.toString();
try {
history.replaceState(null, '', hash ? '#' + hash : window.location.pathname + window.location.search);
} catch (e) { /* sandboxed frame: the selection still works, it just is not in the URL */ }
}
// ---- iframes ----
function setFrame(frame, src) {
if (frame.getAttribute('src') !== src) frame.setAttribute('src', src);
}
window.addEventListener('message', function (event) {
var data = event.data;
if (!data || typeof data.saFrameHeight !== 'number') return;
document.querySelectorAll('iframe.sa-frame').forEach(function (frame) {
if (frame.contentWindow === event.source) frame.style.height = data.saFrameHeight + 'px';
});
});
// ---- header ----
function renderFacts() {
var version = document.querySelector('meta[name="selectarena-version"]').getAttribute('content');
$('current-version').textContent = 'v' + version;
var facts = [];
if (meta) {
var models = Object.keys(meta.models || {}).map(function (k) { return meta.models[k]; });
facts.push(meta.n_methods + ' methods', meta.n_datasets + ' datasets');
if (models.length) facts.push('downstream models: ' + models.join(', '));
facts.push('updated ' + meta.generated_at);
}
facts.push('v' + version);
var list = $('facts');
list.textContent = '';
facts.forEach(function (text) {
var li = document.createElement('li');
li.textContent = text;
list.appendChild(li);
});
}
// ---- tabs ----
function showTab(tab) {
state.tab = tab;
TABS.forEach(function (t) {
$('tab-' + t).setAttribute('aria-selected', String(t === tab));
$('tab-' + t).tabIndex = t === tab ? 0 : -1;
$('panel-' + t).hidden = t !== tab;
});
if (tab === 'datasets') loadDatasets();
if (tab === 'robustness') loadRobustness();
writeHash();
}
function initTabs() {
document.querySelectorAll('[role="tab"]').forEach(function (button) {
button.addEventListener('click', function () { showTab(button.dataset.tab); });
button.addEventListener('keydown', function (event) {
var i = TABS.indexOf(button.dataset.tab);
if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
var next = TABS[(i + (event.key === 'ArrowRight' ? 1 : TABS.length - 1)) % TABS.length];
showTab(next);
$('tab-' + next).focus();
}
});
});
}
// ---- leaderboard ----
function axisOptions() {
var taskTypes = meta.task_types || [ALL];
var models = meta.models || {};
return {
tasks: Object.keys(TASK_LABELS)
.filter(function (k) { return taskTypes.indexOf(k) >= 0; })
.map(function (k) { return { value: k, label: TASK_LABELS[k] }; }),
model: [{ value: ALL, label: 'All models' }].concat(
Object.keys(models).map(function (k) { return { value: k, label: models[k] }; })),
budget: [{ value: ALL, label: 'All budgets' }].concat(
(meta.budgets || []).map(function (b) { return { value: String(b), label: budgetLabel(b, meta.total_budget) }; }))
};
}
function renderChips(axis, options) {
var container = $('chips-' + axis);
container.textContent = '';
options.forEach(function (option) {
var button = document.createElement('button');
button.type = 'button';
button.className = 'chip';
button.textContent = option.label;
button.setAttribute('aria-pressed', String(option.value === state[axis]));
var available = published[key(withAxis(axis, option.value))];
if (!available && option.value !== state[axis]) {
button.disabled = true;
button.title = 'No leaderboard for this combination';
}
button.addEventListener('click', function () {
state[axis] = option.value;
renderLeaderboard();
writeHash();
});
container.appendChild(button);
});
}
function renderLeaderboard() {
var options = axisOptions();
['tasks', 'model', 'budget'].forEach(function (axis) { renderChips(axis, options[axis]); });
var info = published[key(state)];
var scope = [
TASK_LABELS[state.tasks] || state.tasks,
state.model === ALL ? 'all downstream models' : (meta.models[state.model] || state.model),
state.budget === ALL ? 'all budgets' : budgetLabel(Number(state.budget), meta.total_budget)
].join(' · ');
var summary = $('summary');
summary.textContent = '';
var strong = document.createElement('strong');
strong.textContent = scope;
summary.appendChild(strong);
if (!info) {
$('subset-missing').hidden = false;
$('subset-content').hidden = true;
return;
}
summary.appendChild(document.createTextNode(
': ' + info.n_methods + ' methods on ' + info.n_datasets + ' datasets, ' +
info.n_comparisons.toLocaleString('en-US') + ' method results compared.'));
$('subset-missing').hidden = true;
$('subset-content').hidden = false;
var dir = subsetDir(state);
setFrame($('frame-figure'), dir + 'elo_explorer.html');
var table = $('frame-table');
if (table.getAttribute('src') !== dir + 'leaderboard_table.html') {
table.style.height = (info.n_methods * 37 + 90) + 'px';
}
setFrame(table, dir + 'leaderboard_table.html');
}
// ---- other tabs (loaded on first view) ----
function loadDatasets() {
if (!meta) { $('datasets-missing').hidden = false; $('frame-datasets').hidden = true; return; }
setFrame($('frame-datasets'), 'data/per_dataset_table.html');
}
function loadRobustness() {
var hasStability = !!(meta && meta.has_stability);
$('stability-missing').hidden = hasStability;
$('frame-stability').hidden = !hasStability;
if (hasStability) setFrame($('frame-stability'), 'data/stability_table.html');
// One validity table per noise level (meta.validity_tables); older data had a single table.
var tables = (meta && meta.validity_tables) || [];
if (!tables.length && meta && meta.has_validity) tables = [{ noise: null, path: 'validity_table.html' }];
$('validity-missing').hidden = tables.length > 0;
var container = $('validity-tables');
if (!container.childElementCount) {
tables.forEach(function (table) {
if (table.noise != null) {
var heading = document.createElement('h3');
heading.textContent = 'Noise level ' + noiseLabel(table.noise) +
(Number(table.noise) === Number(meta.validity_noise) ? ' (used on the leaderboard)' : '');
container.appendChild(heading);
}
var frame = document.createElement('iframe');
frame.className = 'frame sa-frame';
frame.title = 'Validity per method' + (table.noise != null ? ' at noise level ' + noiseLabel(table.noise) : '');
frame.style.height = '640px';
frame.src = 'data/' + table.path;
container.appendChild(frame);
});
}
if (meta && meta.validity_noise != null) $('validity-noise').textContent = noiseLabel(meta.validity_noise);
}
// ---- start ----
function start() {
readHash();
initTabs();
fetch('data/meta.json', { cache: 'no-cache' })
.then(function (response) {
if (!response.ok) throw new Error('HTTP ' + response.status);
return response.json();
})
.then(function (data) {
meta = data;
(meta.subsets || []).forEach(function (s) { published[key(s)] = s; });
if (!published[key(state)]) { state.tasks = ALL; state.model = ALL; state.budget = ALL; }
$('leaderboard-content').hidden = false;
renderFacts();
renderLeaderboard();
showTab(state.tab);
})
.catch(function () {
meta = null;
$('no-results').hidden = false;
renderFacts();
showTab(state.tab);
});
}
start();
})();