model bars: derive gradient from name (procedural, not per-name CSS)
The CSS-rule-per-canonical-name approach was wrong: any name the producer publishes that wasn't in the hardcoded list (mlp_realistic, cnn_oracle, knn_semi, anything new tomorrow) rendered grey because no .model-fill.<name> rule matched. Replace with a deterministic FNV-1a hash of the model string → hue, applied inline as an OKLCH gradient when the row is created. Every model string gets a stable, distinct color regardless of suffix or case. Inline style beats any CSS rule, so this works whatever's in dashboard.css. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
53d2b80009
commit
984300ba21
2 changed files with 25 additions and 7 deletions
|
|
@ -1760,24 +1760,42 @@ def train_nn(*, model, X_train, y_train, X_val, y_val,
|
|||
root.innerHTML = '';
|
||||
root.appendChild(awaitingNote('awaiting model_metric events · turn demo on for examples'));
|
||||
}
|
||||
// Derive a gradient deterministically from the model name. Any
|
||||
// string the producer publishes (mlp / mlp_realistic / cnn_oracle
|
||||
// / knn_semi / something we never anticipated) maps to a stable
|
||||
// hue, so the bar always paints. Beats hardcoding CSS rules per
|
||||
// known name and missing whatever the producer adds tomorrow.
|
||||
function modelHue(s) {
|
||||
// FNV-1a 32-bit, cheap and deterministic across browsers.
|
||||
let h = 2166136261;
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
h ^= s.charCodeAt(i);
|
||||
h = (h * 16777619) >>> 0;
|
||||
}
|
||||
return h % 360;
|
||||
}
|
||||
function gradientFor(model) {
|
||||
const hue = modelHue(String(model));
|
||||
return `linear-gradient(90deg, oklch(72% 0.18 ${hue}), oklch(46% 0.20 ${hue}))`;
|
||||
}
|
||||
function ensureRow(model) {
|
||||
if (rows.has(model)) return rows.get(model);
|
||||
if (root.querySelector('.awaiting')) root.innerHTML = '';
|
||||
const row = document.createElement('div'); row.className = 'model-row';
|
||||
row.innerHTML = `
|
||||
<div class="model-name">${model}</div>
|
||||
<div class="model-track"><div class="model-fill ${model}" style="width:0%"></div></div>
|
||||
<div class="model-track"><div class="model-fill" style="width:0%"></div></div>
|
||||
<div class="model-acc">0.000</div>`;
|
||||
root.appendChild(row);
|
||||
const entry = { row, fill: row.querySelector('.model-fill'), acc: row.querySelector('.model-acc') };
|
||||
const fill = row.querySelector('.model-fill');
|
||||
// Inline style beats any CSS rule, so the gradient survives no
|
||||
// matter what's in dashboard.css.
|
||||
fill.style.background = gradientFor(model);
|
||||
const entry = { row, fill, acc: row.querySelector('.model-acc') };
|
||||
rows.set(model, entry); return entry;
|
||||
}
|
||||
function render(model, accuracy) {
|
||||
const r = ensureRow(model);
|
||||
// Full 0–1 visible scale. The previous (acc-0.5)/0.5 mapping
|
||||
// clamped honest-low cross-host F1s to 0% width and made the
|
||||
// bars look unpopulated. Producer-side change — see
|
||||
// docs/dashboard-request-scenes-7-8-12.md for context.
|
||||
const visible = Math.max(0, Math.min(1, accuracy));
|
||||
r.fill.style.width = (visible * 100).toFixed(1) + '%';
|
||||
r.acc.textContent = accuracy.toFixed(3);
|
||||
|
|
|
|||
|
|
@ -648,6 +648,6 @@
|
|||
</article>
|
||||
</div>
|
||||
|
||||
<script src="/static/dashboard.js?v=960c0baa"></script>
|
||||
<script src="/static/dashboard.js?v=d16a0e1c"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue