// Layer view — feature browser table for a single layer. function LayerView({ layer, landingSummary, onPickFeature, onOpenCaseStudy, layersAvailable }) { const idx = useFetch(() => API.index(layer), [layer]); const [filter, setFilter] = React.useState("all"); const [search, setSearch] = React.useState(""); const [sortKey, setSortKey] = React.useState("m7_score"); const [sortDir, setSortDir] = React.useState("desc"); const all = idx.data || []; const rows = React.useMemo(() => { let xs = all.filter((r) => { const cat = rowCategory(r); if (filter !== "all" && cat !== filter) return false; if (search) { const s = search.toLowerCase(); const fid = String(r.feature_id); if (!fid.includes(s) && !((r.m7_label || "").toLowerCase().includes(s)) && !((r.m1_label || "").toLowerCase().includes(s)) && !((r.m2_label || "").toLowerCase().includes(s)) && !((r.m6_label || "").toLowerCase().includes(s))) return false; } return true; }); xs = [...xs].sort((a, b) => { const av = a[sortKey], bv = b[sortKey]; if (av == null) return 1; if (bv == null) return -1; if (typeof av === "string") return sortDir === "desc" ? bv.localeCompare(av) : av.localeCompare(bv); return sortDir === "desc" ? bv - av : av - bv; }); return xs; }, [all, filter, search, sortKey, sortDir]); // No cap — render all rows. The wrap is overflow:auto so the user // scrolls inside the table; the sticky thead keeps headers in view. const visible = rows; const layerMeta = (landingSummary?.layers || []).find(L => L.layer === layer) || {}; function sortBy(k) { if (sortKey === k) setSortDir(d => d === "desc" ? "asc" : "desc"); else { setSortKey(k); setSortDir("desc"); } } const arrow = (k) => sortKey === k ? (sortDir === "desc" ? " ↓" : " ↑") : ""; if (idx.loading) return
; if (idx.error) return
; return (
Layer {layer}

{(layerMeta.num_features || all.length).toLocaleString()} features in layer {layer}

Each row is one SAE feature. Columns show the score under each annotation method; the geometric column is the paper's novel test. Highlighted cells are q < 0.05. Click a row to open the feature.

Annotated (any)
{fmt(layerMeta.any_pct, 1)}%
Database only
{fmt((layerMeta.bio_pct ?? 0) - (layerMeta.both_pct ?? 0), 1)}%
Geometry only
{fmt(layerMeta.geom_pct ? (layerMeta.geom_pct - (layerMeta.both_pct ?? 0)) : null, 1)}%
Both
{fmt(layerMeta.both_pct, 1)}%
{/* Case-study tiles, scoped to this layer */} {onOpenCaseStudy && (
{[ { id: 'geom-fills-db', n: '01', t: 'Geometry annotates features missing DB labels' }, { id: 'granularity', n: '02', t: 'Geometry is more granular than biology' }, { id: 'metagenomic', n: '03', t: 'Transfer to metagenomic proteins' }, ].map((c, i, arr) => ( ))}
)} {/* Controls */}
Significance
{[ ["all", "All"], ["geom_only", "Geom only"], ["bio_only", "Database only"], ["both", "Both"], ["none", "None"], ].map(([v, l]) => ( ))}
Search
setSearch(e.target.value)} />
{rows.length.toLocaleString()} of {all.length.toLocaleString()} features
{visible.map((r) => { const cat = rowCategory(r); const radarArr = radarFromObj(r.geometry_radar); return ( onPickFeature(layer, r.feature_id)}> ); })}
Activity Geometric — Cα backbone MEME motif InterPro residue InterPro protein Compact
sortBy("feature_id")} style={{cursor:'pointer'}}>ID{arrow("feature_id")} Profile Sig 1·2·3·4·5·6·7 sortBy("pct_proteins_activated")} style={{cursor:'pointer'}}>% prot{arrow("pct_proteins_activated")} sortBy("max_activation")} style={{cursor:'pointer'}}>Max act{arrow("max_activation")} sortBy("m7_score")} style={{cursor:'pointer'}}>PR-AUC{arrow("m7_score")} Top geom label sortBy("m6_score")} style={{cursor:'pointer'}}>PR-AUC{arrow("m6_score")} Top motif sortBy("m2_score")} style={{cursor:'pointer'}}>F1{arrow("m2_score")} IPR residue label sortBy("m1_score")} style={{cursor:'pointer'}}>F1{arrow("m1_score")} IPR protein label CATH·R CATH·P Pos
f/{r.feature_id} {radarArr ? ( ) : null} {fmt(r.pct_proteins_activated, 1)} {fmt(r.max_activation, 2)} {fmt(r.m7_score, 2)} {r.m7_label || "—"} {fmt(r.m6_score, 2)} {r.m6_label || "—"} {fmt(r.m2_score, 2)} {r.m2_label || "—"} {fmt(r.m1_score, 2)} {r.m1_label || "—"} {fmt(r.m4_score, 2)} {fmt(r.m3_score, 2)} {fmt(r.m5_score, 2)}
); } window.LayerView = LayerView;