/* The static tables beside the browser: the named features and their published evidence, and the annotation sources. All of it is read out of data/sae/index.json. Captions are authored in sae-features.html as the first child of each table, so filling a table keeps the caption that is already there. */ (async function () { const named = document.getElementById('named-table'); const prov = document.getElementById('feat-prov'); const sources = document.getElementById('sources-body'); if (!named) return; const esc = value => String(value ?? '').replace(/[&<>"']/g, ch => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ch])); /* A caption has to stay the table's first child, so it is lifted out and put back ahead of the generated head and body. */ const fill = (table, html) => { const caption = table.querySelector('caption'); table.innerHTML = (caption ? caption.outerHTML : '') + html; }; /* The report's own vocabulary for what a feature resolves. */ const LEVEL = { site: 'base-level', range: 'region-level', motif: 'motif', pattern: 'pattern', }; /* Reading order: the detectors the report validates against annotation, then the cis-element motifs and repeat patterns, then the two candidates it rejects. Anything the index adds later lands in a fourth group rather than disappearing. */ const GROUPS = [ { title: 'Validated against annotation', ids: [4131, 2634, 586, 7708, 3930, 2618, 1200] }, { title: 'Cis-element motifs and repeat patterns', ids: [4567, 145, 5804, 1474, 5349] }, { title: 'Other named features', ids: [] }, ]; /* Best detector of its class in all four annotated genomes. */ const BEST_IN_CLASS = new Set([4131, 586, 7708]); /* MCC gets its own numeric column, so it comes off the front of the evidence string; the validation-selected threshold is stated once in the caption. */ function splitEvidence(text) { const raw = String(text ?? '').trim(); const hit = /^MCC\s+([0-9.]+)/.exec(raw); return { mcc: hit ? hit[1] : '' }; } try { const index = await (await fetch('data/sae/index.json')).json(); const s = index.sae; prov.textContent = `${s.model_name}, layer ${s.layer}, ${s.d_sae} features, k = ${s.k}`; prov.title = `${s.sae_id} · sha256 ${s.sae_sha256.slice(0, 16)}… · ${s.threshold_mode} threshold ${s.sae_threshold.toFixed(4)}`; const features = new Map(Object.entries(index.curated_features) .map(([id, f]) => [Number(id), f])); const grouped = new Set(GROUPS.flatMap(g => g.ids)); GROUPS[GROUPS.length - 1].ids = [...features.keys()].filter(id => !grouped.has(id)); const row = id => { const f = features.get(id); const { mcc } = splitEvidence(f.evidence); const label = String(f.label ?? '').replace(/\s*\(rejected\)$/, ''); return `
${esc(src.intro)}
`; html += '| Species | Assembly | Tracks built from | ' + 'Gene models shown | Status |
|---|---|---|---|---|
| ${esc(r.binomial)} | ` + `${esc(r.assembly)} ${esc(r.assembly_accession)} | ` +
`${esc(r.annotation_build)} | ` + `${r.url ? `${esc(r.annotation_current)}` : esc(r.annotation_current)}` +
`${r.released ? ` released ${esc(r.released)}` : ''} | ` +
`${badge(r)} | ` + '
${esc(r.binomial)}
`; if (r.currency_note) html += `${esc(r.currency_note)}
`; if (r.superseded_by) html += `Superseded by: ${esc(r.superseded_by)}
`; if (r.licence) html += `Licence: ${esc(r.licence)}
`; if (r.citation) html += `${esc(r.citation)}
`; html += '${esc(reg.intro)}
`; if (reg.verdicts && reg.verdicts.length) { html += '| Register | Answers | Version | Covers | ' + '
|---|---|---|---|
| ${r.url ? `${esc(r.name)}` : esc(r.name)} | ` + `${esc(r.role)} | ` + `${esc(r.version)} | ` + `${esc(r.scope)} | ` + '
${esc(r.name)}
` + `${esc(r.content)}
` + (r.caveat ? `Cannot answer: ${esc(r.caveat)}
` : '') + (r.citation ? `${esc(r.citation)}
` : '') + '${esc(reg.note)}
`; return html; } /* Until then: the assemblies the windows themselves name, and nothing more. */ function renderPendingSources(host, windows) { const rows = new Map(); for (const w of windows) { const key = `${w.species_binomial}|${w.assembly}`; rows.set(key, (rows.get(key) || 0) + 1); } const body = [...rows.entries()] .sort((a, b) => a[0].localeCompare(b[0])) .map(([key, n]) => { const [binomial, assembly] = key.split('|'); return `| Species | Assembly | Windows |
|---|
The annotation release, download URL, citation and licence behind each ' + 'of these assemblies are being verified and will be listed here.
'; } })();