Ensemble UI: vote summary + p(ASD) histogram + collapsed per-site details
Browse files
app.py
CHANGED
|
@@ -546,21 +546,80 @@ def run_gcn(file_path):
|
|
| 546 |
<div><div style="font-size:0.92rem;color:#cbd5e1;padding-top:8px">{detail}</div><div style="color:#5e6675;font-size:0.7rem;margin-top:2px">Ensemble vote</div></div>
|
| 547 |
</div></div>"""
|
| 548 |
|
| 549 |
-
# ── Ensemble ──
|
| 550 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
for site, p in per_model:
|
| 552 |
lbl = "ASD" if p > 0.5 else "TC"
|
| 553 |
clr = "#ef4444" if p > 0.5 else "#22c55e"
|
| 554 |
-
|
| 555 |
-
<td style="padding:
|
| 556 |
-
<td style="padding:
|
| 557 |
-
<div style="background:{clr};height:
|
| 558 |
-
<td style="padding:
|
| 559 |
-
<td style="padding:
|
| 560 |
|
| 561 |
ensemble = f"""<div style="background:#161922;border:1px solid #252a35;border-radius:8px;padding:18px 24px;margin-top:10px">
|
| 562 |
-
<div style="font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:
|
| 563 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 564 |
<div style="margin-top:12px;padding-top:10px;border-top:1px solid #252a35;color:#5e6675;font-size:0.76rem">
|
| 565 |
LOSO AUC = 0.7260 · 1,102 held-out subjects · 20 acquisition sites
|
| 566 |
</div></div>"""
|
|
|
|
| 546 |
<div><div style="font-size:0.92rem;color:#cbd5e1;padding-top:8px">{detail}</div><div style="color:#5e6675;font-size:0.7rem;margin-top:2px">Ensemble vote</div></div>
|
| 547 |
</div></div>"""
|
| 548 |
|
| 549 |
+
# ── Ensemble (vote summary + histogram + collapsed details) ──
|
| 550 |
+
asd_votes = sum(1 for _, p in per_model if p > 0.5)
|
| 551 |
+
tc_votes = n_models - asd_votes
|
| 552 |
+
asd_pct = (asd_votes / n_models) * 100 if n_models else 0
|
| 553 |
+
tc_pct = 100 - asd_pct
|
| 554 |
+
|
| 555 |
+
p_values = sorted(p for _, p in per_model)
|
| 556 |
+
p_min, p_max = (p_values[0], p_values[-1]) if p_values else (0.0, 0.0)
|
| 557 |
+
|
| 558 |
+
majority_asd = asd_votes >= tc_votes
|
| 559 |
+
maj_count = asd_votes if majority_asd else tc_votes
|
| 560 |
+
maj_clr = "#ef4444" if majority_asd else "#22c55e"
|
| 561 |
+
maj_lbl = "ASD" if majority_asd else "TC"
|
| 562 |
+
|
| 563 |
+
# Histogram: bin p values into 10 buckets of width 0.1
|
| 564 |
+
bins = [0] * 10
|
| 565 |
+
for p in p_values:
|
| 566 |
+
bins[min(int(p * 10), 9)] += 1
|
| 567 |
+
max_bin = max(bins) or 1
|
| 568 |
+
hist_bars = ""
|
| 569 |
+
for i, c in enumerate(bins):
|
| 570 |
+
h = max(int(c / max_bin * 36), 2 if c > 0 else 1)
|
| 571 |
+
clr = "#ef4444" if i >= 5 else "#22c55e"
|
| 572 |
+
op = 0.9 if c > 0 else 0.12
|
| 573 |
+
hist_bars += (
|
| 574 |
+
f'<div style="flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;height:40px">'
|
| 575 |
+
f'<div style="color:#5e6675;font-size:0.62rem;margin-bottom:2px;height:9px">{c if c>0 else ""}</div>'
|
| 576 |
+
f'<div style="background:{clr};opacity:{op};width:78%;height:{h}px;border-radius:1px"></div>'
|
| 577 |
+
f'</div>'
|
| 578 |
+
)
|
| 579 |
+
|
| 580 |
+
# Per-site detail rows (collapsed)
|
| 581 |
+
detail_rows = ""
|
| 582 |
for site, p in per_model:
|
| 583 |
lbl = "ASD" if p > 0.5 else "TC"
|
| 584 |
clr = "#ef4444" if p > 0.5 else "#22c55e"
|
| 585 |
+
detail_rows += f"""<tr>
|
| 586 |
+
<td style="padding:6px 0;color:#cbd5e1;font-size:0.82rem;width:110px">{site}-blind</td>
|
| 587 |
+
<td style="padding:6px 14px;width:200px"><div style="background:#252a35;border-radius:2px;height:4px;width:180px;overflow:hidden">
|
| 588 |
+
<div style="background:{clr};height:4px;width:{int(p*100)}%"></div></div></td>
|
| 589 |
+
<td style="padding:6px 14px;color:{clr};font-weight:600;font-size:0.78rem;width:40px">{lbl}</td>
|
| 590 |
+
<td style="padding:6px 0;color:#8b95a7;font-size:0.78rem;font-variant-numeric:tabular-nums">p = {p:.3f}</td></tr>"""
|
| 591 |
|
| 592 |
ensemble = f"""<div style="background:#161922;border:1px solid #252a35;border-radius:8px;padding:18px 24px;margin-top:10px">
|
| 593 |
+
<div style="font-size:0.65rem;color:#8b95a7;letter-spacing:2px;text-transform:uppercase;margin-bottom:14px;font-weight:500">Cross-Site Consensus · {n_models} Site-Blind Models</div>
|
| 594 |
+
|
| 595 |
+
<div style="display:flex;align-items:baseline;gap:12px;margin-bottom:10px;flex-wrap:wrap">
|
| 596 |
+
<div style="font-size:1.7rem;font-weight:700;color:{maj_clr};line-height:1;font-variant-numeric:tabular-nums">{maj_count}<span style="font-size:1rem;color:#5e6675;font-weight:500"> / {n_models}</span></div>
|
| 597 |
+
<div style="color:#cbd5e1;font-size:0.86rem">site-blind models predict <span style="color:{maj_clr};font-weight:600">{maj_lbl}</span></div>
|
| 598 |
+
<div style="margin-left:auto;color:#8b95a7;font-size:0.78rem">mean p = <span style="color:#cbd5e1;font-weight:600">{p_mean:.3f}</span> · range [{p_min:.2f}, {p_max:.2f}]</div>
|
| 599 |
+
</div>
|
| 600 |
+
|
| 601 |
+
<div style="background:#252a35;border-radius:3px;height:9px;width:100%;overflow:hidden;display:flex;margin-bottom:6px">
|
| 602 |
+
<div style="background:#ef4444;height:9px;width:{asd_pct}%" title="{asd_votes} predict ASD"></div>
|
| 603 |
+
<div style="background:#22c55e;height:9px;width:{tc_pct}%" title="{tc_votes} predict TC"></div>
|
| 604 |
+
</div>
|
| 605 |
+
<div style="display:flex;justify-content:space-between;color:#5e6675;font-size:0.7rem;margin-bottom:18px">
|
| 606 |
+
<span><span style="color:#ef4444;font-weight:600">{asd_votes}</span> ASD</span>
|
| 607 |
+
<span><span style="color:#22c55e;font-weight:600">{tc_votes}</span> TC</span>
|
| 608 |
+
</div>
|
| 609 |
+
|
| 610 |
+
<div style="background:#0e1015;border:1px solid #1e2330;border-radius:6px;padding:10px 14px 8px;margin-bottom:12px">
|
| 611 |
+
<div style="display:flex;align-items:flex-end;gap:2px">{hist_bars}</div>
|
| 612 |
+
<div style="display:flex;justify-content:space-between;color:#5e6675;font-size:0.62rem;margin-top:3px;padding:0 1px">
|
| 613 |
+
<span>0.0</span><span>0.25</span><span style="border-left:1px dashed #3a4150;height:6px"></span><span>0.75</span><span>1.0</span>
|
| 614 |
+
</div>
|
| 615 |
+
<div style="text-align:center;color:#5e6675;font-size:0.68rem;margin-top:4px">Distribution of p(ASD) across all {n_models} site-blind models · tight clustering = strong cross-site agreement</div>
|
| 616 |
+
</div>
|
| 617 |
+
|
| 618 |
+
<details style="margin-top:6px">
|
| 619 |
+
<summary style="color:#8b95a7;font-size:0.76rem;cursor:pointer;font-weight:500;padding:6px 0;user-select:none">▸ Per-site breakdown · all {n_models} models</summary>
|
| 620 |
+
<table style="width:100%;border-collapse:collapse;margin-top:6px">{detail_rows}</table>
|
| 621 |
+
</details>
|
| 622 |
+
|
| 623 |
<div style="margin-top:12px;padding-top:10px;border-top:1px solid #252a35;color:#5e6675;font-size:0.76rem">
|
| 624 |
LOSO AUC = 0.7260 · 1,102 held-out subjects · 20 acquisition sites
|
| 625 |
</div></div>"""
|