schaeferbasti commited on
Commit
8b380f6
·
verified ·
1 Parent(s): f77b3a8

Upload 2 files

Browse files
Files changed (2) hide show
  1. assets/app.js +233 -0
  2. assets/style.css +111 -0
assets/app.js ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SelectArena leaderboard: a static page over the generated files in data/.
2
+ //
3
+ // data/meta.json lists every published subset; each subset folder
4
+ // data/subsets/tasks_<t>/models_<m>/budgets_<b>/ holds elo_explorer.html and leaderboard_table.html,
5
+ // which are embedded as iframes. The folder names mirror selectarena.website.subsets.Subset.rel_path.
6
+ // Every embedded page posts {saFrameHeight: <px>} to this window; the listener below resizes its iframe.
7
+ (function () {
8
+ 'use strict';
9
+
10
+ var ALL = 'all';
11
+ var TASK_LABELS = {
12
+ all: 'All tasks',
13
+ classification: 'Classification',
14
+ binary: 'Binary',
15
+ multiclass: 'Multiclass',
16
+ regression: 'Regression'
17
+ };
18
+ var TABS = ['leaderboard', 'datasets', 'robustness', 'about'];
19
+ var state = { tab: 'leaderboard', tasks: ALL, model: ALL, budget: ALL };
20
+ var meta = null;
21
+ var published = {};
22
+
23
+ function $(id) { return document.getElementById(id); }
24
+ function key(s) { return s.tasks + '|' + s.model + '|' + s.budget; }
25
+ function subsetDir(s) {
26
+ return 'data/subsets/tasks_' + s.tasks + '/models_' + s.model + '/budgets_' + s.budget + '/';
27
+ }
28
+ function withAxis(axis, value) {
29
+ var s = { tasks: state.tasks, model: state.model, budget: state.budget };
30
+ s[axis] = value;
31
+ return s;
32
+ }
33
+
34
+ function budgetLabel(index, total) {
35
+ var label = 'Budget ' + (index + 1);
36
+ if (total && index === 0) return label + ' (smallest)';
37
+ if (total && index === total - 1) return label + ' (largest)';
38
+ return label;
39
+ }
40
+
41
+ // ---- URL hash: #tab=...&tasks=...&model=...&budget=... (shareable selections) ----
42
+ function readHash() {
43
+ var params = new URLSearchParams(window.location.hash.slice(1));
44
+ ['tab', 'tasks', 'model', 'budget'].forEach(function (k) {
45
+ var v = params.get(k);
46
+ if (v) state[k] = v;
47
+ });
48
+ if (TABS.indexOf(state.tab) < 0) state.tab = 'leaderboard';
49
+ }
50
+ function writeHash() {
51
+ var params = new URLSearchParams();
52
+ if (state.tab !== 'leaderboard') params.set('tab', state.tab);
53
+ ['tasks', 'model', 'budget'].forEach(function (k) { if (state[k] !== ALL) params.set(k, state[k]); });
54
+ var hash = params.toString();
55
+ try {
56
+ history.replaceState(null, '', hash ? '#' + hash : window.location.pathname + window.location.search);
57
+ } catch (e) { /* sandboxed frame: the selection still works, it just is not in the URL */ }
58
+ }
59
+
60
+ // ---- iframes ----
61
+ function setFrame(frame, src) {
62
+ if (frame.getAttribute('src') !== src) frame.setAttribute('src', src);
63
+ }
64
+ window.addEventListener('message', function (event) {
65
+ var data = event.data;
66
+ if (!data || typeof data.saFrameHeight !== 'number') return;
67
+ document.querySelectorAll('iframe.sa-frame').forEach(function (frame) {
68
+ if (frame.contentWindow === event.source) frame.style.height = data.saFrameHeight + 'px';
69
+ });
70
+ });
71
+
72
+ // ---- header ----
73
+ function renderFacts() {
74
+ var version = document.querySelector('meta[name="selectarena-version"]').getAttribute('content');
75
+ $('current-version').textContent = 'v' + version;
76
+ var facts = [];
77
+ if (meta) {
78
+ var models = Object.keys(meta.models || {}).map(function (k) { return meta.models[k]; });
79
+ facts.push(meta.n_methods + ' methods', meta.n_datasets + ' datasets');
80
+ if (models.length) facts.push('downstream models: ' + models.join(', '));
81
+ facts.push('updated ' + meta.generated_at);
82
+ }
83
+ facts.push('v' + version);
84
+ var list = $('facts');
85
+ list.textContent = '';
86
+ facts.forEach(function (text) {
87
+ var li = document.createElement('li');
88
+ li.textContent = text;
89
+ list.appendChild(li);
90
+ });
91
+ }
92
+
93
+ // ---- tabs ----
94
+ function showTab(tab) {
95
+ state.tab = tab;
96
+ TABS.forEach(function (t) {
97
+ $('tab-' + t).setAttribute('aria-selected', String(t === tab));
98
+ $('tab-' + t).tabIndex = t === tab ? 0 : -1;
99
+ $('panel-' + t).hidden = t !== tab;
100
+ });
101
+ if (tab === 'datasets') loadDatasets();
102
+ if (tab === 'robustness') loadRobustness();
103
+ writeHash();
104
+ }
105
+ function initTabs() {
106
+ document.querySelectorAll('[role="tab"]').forEach(function (button) {
107
+ button.addEventListener('click', function () { showTab(button.dataset.tab); });
108
+ button.addEventListener('keydown', function (event) {
109
+ var i = TABS.indexOf(button.dataset.tab);
110
+ if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
111
+ var next = TABS[(i + (event.key === 'ArrowRight' ? 1 : TABS.length - 1)) % TABS.length];
112
+ showTab(next);
113
+ $('tab-' + next).focus();
114
+ }
115
+ });
116
+ });
117
+ }
118
+
119
+ // ---- leaderboard ----
120
+ function axisOptions() {
121
+ var taskTypes = meta.task_types || [ALL];
122
+ var models = meta.models || {};
123
+ return {
124
+ tasks: Object.keys(TASK_LABELS)
125
+ .filter(function (k) { return taskTypes.indexOf(k) >= 0; })
126
+ .map(function (k) { return { value: k, label: TASK_LABELS[k] }; }),
127
+ model: [{ value: ALL, label: 'All models' }].concat(
128
+ Object.keys(models).map(function (k) { return { value: k, label: models[k] }; })),
129
+ budget: [{ value: ALL, label: 'All budgets' }].concat(
130
+ (meta.budgets || []).map(function (b) { return { value: String(b), label: budgetLabel(b, meta.total_budget) }; }))
131
+ };
132
+ }
133
+
134
+ function renderChips(axis, options) {
135
+ var container = $('chips-' + axis);
136
+ container.textContent = '';
137
+ options.forEach(function (option) {
138
+ var button = document.createElement('button');
139
+ button.type = 'button';
140
+ button.className = 'chip';
141
+ button.textContent = option.label;
142
+ button.setAttribute('aria-pressed', String(option.value === state[axis]));
143
+ var available = published[key(withAxis(axis, option.value))];
144
+ if (!available && option.value !== state[axis]) {
145
+ button.disabled = true;
146
+ button.title = 'No leaderboard for this combination';
147
+ }
148
+ button.addEventListener('click', function () {
149
+ state[axis] = option.value;
150
+ renderLeaderboard();
151
+ writeHash();
152
+ });
153
+ container.appendChild(button);
154
+ });
155
+ }
156
+
157
+ function renderLeaderboard() {
158
+ var options = axisOptions();
159
+ ['tasks', 'model', 'budget'].forEach(function (axis) { renderChips(axis, options[axis]); });
160
+
161
+ var info = published[key(state)];
162
+ var scope = [
163
+ TASK_LABELS[state.tasks] || state.tasks,
164
+ state.model === ALL ? 'all downstream models' : (meta.models[state.model] || state.model),
165
+ state.budget === ALL ? 'all budgets' : budgetLabel(Number(state.budget), meta.total_budget)
166
+ ].join(' · ');
167
+ var summary = $('summary');
168
+ summary.textContent = '';
169
+ var strong = document.createElement('strong');
170
+ strong.textContent = scope;
171
+ summary.appendChild(strong);
172
+ if (!info) {
173
+ $('subset-missing').hidden = false;
174
+ $('subset-content').hidden = true;
175
+ return;
176
+ }
177
+ summary.appendChild(document.createTextNode(
178
+ ': ' + info.n_methods + ' methods on ' + info.n_datasets + ' datasets, ' +
179
+ info.n_comparisons.toLocaleString('en-US') + ' method results compared.'));
180
+ $('subset-missing').hidden = true;
181
+ $('subset-content').hidden = false;
182
+ var dir = subsetDir(state);
183
+ setFrame($('frame-figure'), dir + 'elo_explorer.html');
184
+ var table = $('frame-table');
185
+ if (table.getAttribute('src') !== dir + 'leaderboard_table.html') {
186
+ table.style.height = (info.n_methods * 37 + 90) + 'px';
187
+ }
188
+ setFrame(table, dir + 'leaderboard_table.html');
189
+ }
190
+
191
+ // ---- other tabs (loaded on first view) ----
192
+ function loadDatasets() {
193
+ if (!meta) { $('datasets-missing').hidden = false; $('frame-datasets').hidden = true; return; }
194
+ setFrame($('frame-datasets'), 'data/per_dataset_table.html');
195
+ }
196
+ function loadRobustness() {
197
+ [['stability', meta && meta.has_stability], ['validity', meta && meta.has_validity]].forEach(function (entry) {
198
+ var name = entry[0];
199
+ $(name + '-missing').hidden = !!entry[1];
200
+ $('frame-' + name).hidden = !entry[1];
201
+ if (entry[1]) setFrame($('frame-' + name), 'data/' + name + '_table.html');
202
+ });
203
+ if (meta && meta.validity_noise != null) $('validity-noise').textContent = Number(meta.validity_noise).toFixed(1);
204
+ }
205
+
206
+ // ---- start ----
207
+ function start() {
208
+ readHash();
209
+ initTabs();
210
+ fetch('data/meta.json', { cache: 'no-cache' })
211
+ .then(function (response) {
212
+ if (!response.ok) throw new Error('HTTP ' + response.status);
213
+ return response.json();
214
+ })
215
+ .then(function (data) {
216
+ meta = data;
217
+ (meta.subsets || []).forEach(function (s) { published[key(s)] = s; });
218
+ if (!published[key(state)]) { state.tasks = ALL; state.model = ALL; state.budget = ALL; }
219
+ $('leaderboard-content').hidden = false;
220
+ renderFacts();
221
+ renderLeaderboard();
222
+ showTab(state.tab);
223
+ })
224
+ .catch(function () {
225
+ meta = null;
226
+ $('no-results').hidden = false;
227
+ renderFacts();
228
+ showTab(state.tab);
229
+ });
230
+ }
231
+
232
+ start();
233
+ })();
assets/style.css ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* SelectArena leaderboard. Colors are tokens so light and dark mode stay in sync with the
2
+ generated pages in data/ (they use the same palette). */
3
+ :root {
4
+ --fg: #1f2328;
5
+ --muted: #59636e;
6
+ --bg: #ffffff;
7
+ --surface: #f6f8fa;
8
+ --line: #d1d9e0;
9
+ --accent: #0072b2;
10
+ --accent-soft: #e6f1f8;
11
+ --validity: #d55e00;
12
+ --on-accent: #ffffff;
13
+ --radius: 10px;
14
+ }
15
+ @media (prefers-color-scheme: dark) {
16
+ :root {
17
+ --fg: #e6edf3;
18
+ --muted: #9198a1;
19
+ --bg: #0d1117;
20
+ --surface: #151b23;
21
+ --line: #3d444d;
22
+ --accent: #4aa3df;
23
+ --accent-soft: #10273a;
24
+ --validity: #f08a4b;
25
+ --on-accent: #0d1117;
26
+ }
27
+ }
28
+
29
+ * { box-sizing: border-box; }
30
+ html { -webkit-text-size-adjust: 100%; }
31
+ body {
32
+ margin: 0;
33
+ background: var(--bg);
34
+ color: var(--fg);
35
+ font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
36
+ }
37
+ a { color: var(--accent); }
38
+ .page { max-width: 1200px; margin: 0 auto; padding: 24px 16px 48px; }
39
+
40
+ /* Header */
41
+ .header h1 { font-size: 2.1rem; line-height: 1.15; margin: 0; letter-spacing: -0.015em; }
42
+ .header h1 .mark { color: var(--accent); }
43
+ .subtitle { margin: 4px 0 12px; color: var(--muted); font-size: 1.05rem; }
44
+ .facts { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
45
+ .facts li {
46
+ font-size: 0.8rem; padding: 2px 10px; border-radius: 999px;
47
+ border: 1px solid var(--line); color: var(--muted);
48
+ }
49
+ .links { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 10px; font-size: 0.95rem; }
50
+ .intro { max-width: 75ch; color: var(--fg); margin: 16px 0 8px; }
51
+
52
+ /* Tabs */
53
+ .tabs {
54
+ display: flex; gap: 2px; margin: 20px 0 16px; border-bottom: 1px solid var(--line);
55
+ overflow-x: auto; scrollbar-width: none;
56
+ }
57
+ .tabs button {
58
+ font: inherit; font-weight: 600; color: var(--muted); background: none; border: 0;
59
+ padding: 10px 14px; border-bottom: 2px solid transparent; margin-bottom: -1px;
60
+ cursor: pointer; white-space: nowrap;
61
+ }
62
+ .tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent); }
63
+ .tabs button:hover { color: var(--fg); }
64
+ .tabs button:focus-visible, .chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
65
+ [role="tabpanel"][hidden] { display: none; }
66
+
67
+ /* Selection controls */
68
+ .controls {
69
+ display: grid; gap: 12px; padding: 14px 16px; margin-bottom: 14px;
70
+ background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
71
+ }
72
+ .control { display: grid; grid-template-columns: 150px 1fr; align-items: center; gap: 10px; }
73
+ .control-label { font-size: 0.85rem; font-weight: 600; color: var(--muted); }
74
+ .chips { display: flex; flex-wrap: wrap; gap: 6px; }
75
+ .chip {
76
+ font: inherit; font-size: 0.85rem; color: var(--fg); background: var(--bg);
77
+ border: 1px solid var(--line); border-radius: 999px; padding: 3px 12px; cursor: pointer;
78
+ }
79
+ .chip:hover { border-color: var(--accent); }
80
+ .chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
81
+ .chip:disabled { opacity: 0.4; cursor: not-allowed; }
82
+ @media (max-width: 640px) {
83
+ .control { grid-template-columns: 1fr; gap: 6px; }
84
+ }
85
+
86
+ .summary { margin: 0 0 10px; color: var(--muted); font-size: 0.95rem; }
87
+ .summary strong { color: var(--fg); }
88
+ .caption { font-size: 0.88rem; color: var(--muted); max-width: 95ch; margin: 6px 0 22px; }
89
+ .caption .stab { color: var(--accent); font-weight: 600; }
90
+ .caption .val { color: var(--validity); font-weight: 600; }
91
+
92
+ .frame { width: 100%; border: 0; display: block; }
93
+ .notice {
94
+ padding: 18px; border: 1px dashed var(--line); border-radius: var(--radius);
95
+ color: var(--muted); margin: 8px 0 16px;
96
+ }
97
+ h2 { font-size: 1.2rem; margin: 26px 0 8px; }
98
+ .prose { max-width: 80ch; }
99
+ .prose li { margin: 4px 0; }
100
+ code { font-size: 0.88em; background: var(--surface); padding: 1px 5px; border-radius: 4px; }
101
+
102
+ /* Footer */
103
+ footer { margin-top: 36px; border-top: 1px solid var(--line); padding-top: 12px; }
104
+ details { margin: 8px 0; }
105
+ details summary { cursor: pointer; font-weight: 600; }
106
+ pre {
107
+ background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
108
+ padding: 12px; overflow-x: auto; font-size: 0.82rem;
109
+ }
110
+ .history { padding-left: 18px; }
111
+ .history li { margin: 6px 0; }