Spaces:
Running
Running
| <!-- Baseline Heatmap: Interactive comparison table of methods x datasets --> | |
| <div class="baseline-heatmap"></div> | |
| <style> | |
| .baseline-heatmap { position: relative; width: 100%; } | |
| .baseline-heatmap .controls { display: flex; gap: 12px; margin-bottom: 12px; align-items: center; flex-wrap: wrap; } | |
| .baseline-heatmap .seg-control { | |
| display: inline-flex; background: var(--surface-bg); | |
| border: 1px solid var(--border-color); border-radius: 8px; | |
| padding: 3px; gap: 2px; | |
| } | |
| .baseline-heatmap .seg-control button { | |
| padding: 5px 14px; border-radius: 6px; border: none; | |
| background: transparent; font-size: 12px; font-weight: 500; | |
| color: var(--text-color); cursor: pointer; transition: all 0.15s ease; | |
| opacity: 0.6; | |
| } | |
| .baseline-heatmap .seg-control button:hover { opacity: 0.8; } | |
| .baseline-heatmap .seg-control button.active { | |
| background: var(--text-color); color: var(--page-bg); | |
| opacity: 1; font-weight: 600; | |
| } | |
| .baseline-heatmap .table-wrap { | |
| overflow-x: auto; border: 1px solid var(--border-color); border-radius: 10px; | |
| } | |
| .baseline-heatmap table { | |
| border-collapse: separate; border-spacing: 0; width: 100%; | |
| font-size: 12px; line-height: 1.4; font-variant-numeric: tabular-nums; | |
| } | |
| .baseline-heatmap thead th { | |
| background: var(--surface-bg); color: var(--text-color); font-weight: 600; | |
| padding: 10px 10px; text-align: center; white-space: nowrap; | |
| position: sticky; top: 0; z-index: 2; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .baseline-heatmap thead th:first-child { | |
| text-align: left; position: sticky; left: 0; z-index: 3; | |
| border-right: 1px solid var(--border-color); | |
| } | |
| .baseline-heatmap tbody td { | |
| padding: 8px 10px; text-align: center; | |
| border-bottom: 1px solid color-mix(in srgb, var(--border-color) 40%, transparent); | |
| transition: background 0.15s ease, opacity 0.25s ease; | |
| } | |
| .baseline-heatmap tbody td:first-child { | |
| text-align: left; font-weight: 600; background: var(--surface-bg); | |
| position: sticky; left: 0; z-index: 1; white-space: nowrap; | |
| border-right: 1px solid var(--border-color); | |
| } | |
| .baseline-heatmap tbody tr:last-child td { border-bottom: none; } | |
| .baseline-heatmap tbody tr:hover td { background: color-mix(in srgb, var(--text-color) 6%, transparent); } | |
| .baseline-heatmap tbody tr:hover td:first-child { background: color-mix(in srgb, var(--text-color) 8%, var(--surface-bg)); } | |
| .baseline-heatmap td.best { font-weight: 700; } | |
| .baseline-heatmap td.col-hover { background: color-mix(in srgb, var(--text-color) 4%, transparent) ; } | |
| .baseline-heatmap td.fade-in { animation: bh-fade 0.3s ease forwards; } | |
| @keyframes bh-fade { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } | |
| </style> | |
| <script> | |
| (() => { | |
| const container = document.querySelector('.baseline-heatmap:not([data-mounted])'); | |
| if (!container) return; | |
| container.dataset.mounted = 'true'; | |
| const datasets = ['SWE-smith','SWE-agent','WebArena','AgentNet','ATBench','OSWorld','tau2-air','tau2-ret','tau2-tel','W&W','M2W','GUI-Ody']; | |
| const statesData = { | |
| 'Ours': [10, 25, 25, 25, 15, 27, 18, 19, 43, 9, 8, 7], | |
| 'RPNI': [11631, 59510, 382, 62495, 899, 38232, 6506, 14249, 63897, 971, 476, 21255], | |
| 'Alergia': [10, 35, 149, 45, 15, 31, 23, 25, 75, 12, 8, 24], | |
| 'HMM': [10, 25, 25, 25, 15, 27, 18, 19, 43, 9, 8, 7], | |
| 'EDSM': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
| }; | |
| const fitnessData = { | |
| 'Ours': [1.000, 0.999, 1.000, 1.000, 1.000, 0.997, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], | |
| 'RPNI': [0.761, 0.646, 1.000, 0.742, 0.984, 0.706, 0.844, 0.837, 0.491, 0.984, 0.970, 0.929], | |
| 'Alergia': [1.000, 0.999, 1.000, 1.000, 1.000, 0.999, 0.999, 1.000, 0.999, 1.000, 1.000, 1.000], | |
| 'HMM': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], | |
| 'EDSM': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], | |
| }; | |
| const methods = Object.keys(statesData); | |
| let metric = 'states'; | |
| // --- Controls --- | |
| const controls = document.createElement('div'); | |
| controls.className = 'controls'; | |
| const seg = document.createElement('div'); | |
| seg.className = 'seg-control'; | |
| const btnStates = document.createElement('button'); | |
| btnStates.textContent = 'State Count'; btnStates.className = 'active'; | |
| const btnFitness = document.createElement('button'); | |
| btnFitness.textContent = 'Fitness'; | |
| seg.appendChild(btnStates); seg.appendChild(btnFitness); | |
| controls.appendChild(seg); | |
| container.prepend(controls); | |
| btnStates.addEventListener('click', () => { metric = 'states'; btnStates.className = 'active'; btnFitness.className = ''; renderTable(); }); | |
| btnFitness.addEventListener('click', () => { metric = 'fitness'; btnFitness.className = 'active'; btnStates.className = ''; renderTable(); }); | |
| // --- Table wrapper --- | |
| const wrap = document.createElement('div'); | |
| wrap.className = 'table-wrap'; | |
| container.appendChild(wrap); | |
| // --- Best value per column (returns the value, so EVERY tied cell can be bolded) --- | |
| function findBestVal(colIndex, data) { | |
| let bestVal = null; | |
| methods.forEach((m) => { | |
| const v = data[m][colIndex]; | |
| if (v === '-') return; | |
| if (metric === 'states') { | |
| // Best = lowest non-degenerate (>1) | |
| if (v > 1 && (bestVal === null || v < bestVal)) bestVal = v; | |
| } else { | |
| // Best = highest | |
| if (bestVal === null || v > bestVal) bestVal = v; | |
| } | |
| }); | |
| return bestVal; | |
| } | |
| // A cell is "best" if it equals the column's best value (ties all qualify). | |
| function isBest(val, bestVal) { | |
| if (bestVal === null || val === '-') return false; | |
| if (metric === 'states') return typeof val === 'number' && val > 1 && val === bestVal; | |
| return val === bestVal; | |
| } | |
| // --- Color logic --- | |
| function cellBg(val, m) { | |
| if (val === '-') return 'transparent'; | |
| if (metric === 'states') { | |
| if (m === 'EDSM') return 'rgba(200,200,200,0.12)'; | |
| const logVal = Math.log10(Math.max(1, val)); | |
| const t = Math.min(1, logVal / 5); | |
| // low states = teal tint, high = rust tint | |
| if (t < 0.3) return `rgba(42,157,143,${0.08 + t * 0.15})`; | |
| return `rgba(61, 90, 128,${0.06 + (t - 0.3) * 0.2})`; | |
| } else { | |
| const t = Math.max(0, (val - 0.5) / 0.5); | |
| return `rgba(42,157,143,${t * 0.35})`; | |
| } | |
| } | |
| // --- Column hover --- | |
| let hoveredCol = -1; | |
| function updateColHover(colIdx) { | |
| if (hoveredCol === colIdx) return; | |
| hoveredCol = colIdx; | |
| const cells = wrap.querySelectorAll('td, th'); | |
| cells.forEach(c => c.classList.remove('col-hover')); | |
| if (colIdx < 0) return; | |
| const rows = wrap.querySelectorAll('tr'); | |
| rows.forEach(row => { | |
| const cell = row.children[colIdx]; | |
| if (cell) cell.classList.add('col-hover'); | |
| }); | |
| } | |
| function renderTable() { | |
| wrap.innerHTML = ''; | |
| const currentData = metric === 'states' ? statesData : fitnessData; | |
| // Precompute best per column | |
| const bestPerCol = datasets.map((_, ci) => findBestVal(ci, currentData)); | |
| const table = document.createElement('table'); | |
| // --- Header --- | |
| const thead = document.createElement('thead'); | |
| const hr = document.createElement('tr'); | |
| const th0 = document.createElement('th'); | |
| th0.textContent = 'Method'; | |
| hr.appendChild(th0); | |
| datasets.forEach((d, ci) => { | |
| const th = document.createElement('th'); | |
| th.textContent = d; | |
| th.addEventListener('mouseenter', () => updateColHover(ci + 1)); | |
| th.addEventListener('mouseleave', () => updateColHover(-1)); | |
| hr.appendChild(th); | |
| }); | |
| thead.appendChild(hr); | |
| table.appendChild(thead); | |
| // --- Body --- | |
| const tbody = document.createElement('tbody'); | |
| methods.forEach((method, mi) => { | |
| const tr = document.createElement('tr'); | |
| const td0 = document.createElement('td'); | |
| td0.textContent = method; | |
| tr.appendChild(td0); | |
| currentData[method].forEach((val, ci) => { | |
| const td = document.createElement('td'); | |
| td.style.background = cellBg(val, method); | |
| td.className = 'fade-in'; | |
| td.style.animationDelay = `${mi * 20 + ci * 10}ms`; | |
| if (val === '-') { | |
| td.textContent = '-'; | |
| td.style.opacity = '0.35'; | |
| } else if (metric === 'states') { | |
| td.textContent = typeof val === 'number' ? val.toLocaleString() : val; | |
| } else { | |
| td.textContent = typeof val === 'number' ? val.toFixed(3) : val; | |
| } | |
| if (isBest(val, bestPerCol[ci])) td.classList.add('best'); | |
| td.addEventListener('mouseenter', () => updateColHover(ci + 1)); | |
| td.addEventListener('mouseleave', () => updateColHover(-1)); | |
| tr.appendChild(td); | |
| }); | |
| tbody.appendChild(tr); | |
| }); | |
| table.appendChild(tbody); | |
| wrap.appendChild(table); | |
| } | |
| renderTable(); | |
| })(); | |
| </script> | |