Spaces:
Running
```
Browse filesValueError: A function (gen_single_export) didn't return enough output values
(needed: 6, returned: 5).
Output components: [textbox, image, file, file, file, file]
```
Reproduced on HF Space after clicking π¨οΈ Export PNG / PDF / SVG.
The `outputs` list in both export button wirings has 6 components:
```python
outputs=[single_status, single_preview, # 1: status text
dl_s_png, dl_s_pdf, dl_s_svg, dl_s_zip] # 2: image preview
# 3-6: file downloads
```
But all return paths in `gen_single_export` and `gen_compare_export`
returned only 5 values β `single_preview` (the PNG image component)
was in the outputs list but had no corresponding return value.
All return paths in both functions updated from 5 β 6 values.
The PNG path is reused for both the image preview and the PNG download:
```python
return status, png, pdf, svg, zip_p
return status, png, png, pdf, svg, zip_p
```
Early-exit error paths also fixed (None count: 5 β 6):
```python
return "Please select a model.", None, None, None, None
return "Please select a model.", None, None, None, None, None
```
`ui/tab_plot.py` only. 6 return statements updated:
| Function | Line | Change |
|----------|------|--------|
| `gen_single_export` | early exit: no model_id | `NoneΓ5` β `NoneΓ6` |
| `gen_single_export` | early exit: df empty | `NoneΓ5` β `NoneΓ6` |
| `gen_single_export` | normal return | `5 values` β `6 values` |
| `gen_compare_export` | early exit: same model | `NoneΓ5` β `NoneΓ6` |
| `gen_compare_export` | early exit: df empty | `NoneΓ5` β `NoneΓ6` |
| `gen_compare_export` | normal return | `5 values` β `6 values` |
No logic changes. No UI changes. No other files touched.
```
outputs list : [status, preview, png, pdf, svg, zip] β 6 β
return (normal): status, png, png, pdf, svg, zip_p β 6 β
return (error) : "msg", None, None, None, None, None β 6 β
```
- ui/tab_plot.py +96 -94
|
@@ -1,9 +1,11 @@
|
|
| 1 |
# ui/tab_plot.py
|
| 2 |
"""
|
| 3 |
Tab5: Plot β Publication-quality figure generation
|
| 4 |
-
-
|
| 5 |
-
-
|
| 6 |
-
|
|
|
|
|
|
|
| 7 |
"""
|
| 8 |
|
| 9 |
import os
|
|
@@ -82,14 +84,13 @@ def _make_zip(paths: list) -> str | None:
|
|
| 82 |
|
| 83 |
def gen_single_plotly(model_id, modality, start_l, end_l, show_band,
|
| 84 |
progress=gr.Progress()):
|
| 85 |
-
"""Fast path: native Plotly, no matplotlib involved."""
|
| 86 |
if not model_id:
|
| 87 |
return None, "Please select a model."
|
| 88 |
progress(0.2, desc="Loading data from DB...")
|
| 89 |
df = _load_df(model_id, modality, start_l, end_l)
|
| 90 |
if df.empty:
|
| 91 |
return None, f"No data for {model_id}. Run Tab 2 analysis first."
|
| 92 |
-
progress(0.7, desc="Building
|
| 93 |
fig = plotly_single(df, _short(model_id), show_band=show_band)
|
| 94 |
status = (
|
| 95 |
f"β
{model_id} | {df['layer'].nunique()} layers "
|
|
@@ -101,33 +102,35 @@ def gen_single_plotly(model_id, modality, start_l, end_l, show_band,
|
|
| 101 |
|
| 102 |
def gen_single_export(model_id, modality, start_l, end_l, show_band,
|
| 103 |
progress=gr.Progress()):
|
| 104 |
-
"""Export path: matplotlib β PNG/PDF/SVG."""
|
| 105 |
if not model_id:
|
| 106 |
-
return "Please select a model.", None, None, None, None
|
| 107 |
progress(0.15, desc="Loading data from DB...")
|
| 108 |
df = _load_df(model_id, modality, start_l, end_l)
|
| 109 |
if df.empty:
|
| 110 |
-
return f"No data for {model_id}.", None, None, None, None
|
| 111 |
head_dim, d_model = _infer_dims(df)
|
| 112 |
-
progress(0.40, desc="Rendering matplotlib figure (
|
| 113 |
import matplotlib.pyplot as plt
|
| 114 |
-
fig = plot_single_model(
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
|
|
|
|
|
|
| 118 |
base = _safe_path(f"single_{_short(model_id)}_L{int(start_l)}-{int(end_l)}")
|
| 119 |
paths = save_figure(fig, base)
|
| 120 |
plt.close(fig)
|
| 121 |
-
zip_p
|
| 122 |
status = (
|
| 123 |
-
f"Exported: {', '.join(os.path.basename(p) for p in paths)}\n"
|
| 124 |
-
f"head_dim={head_dim} d_model={d_model}"
|
| 125 |
)
|
| 126 |
progress(1.0)
|
| 127 |
png = paths[0] if len(paths) > 0 else None
|
| 128 |
pdf = paths[1] if len(paths) > 1 else None
|
| 129 |
svg = paths[2] if len(paths) > 2 else None
|
| 130 |
-
|
|
|
|
| 131 |
|
| 132 |
|
| 133 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -148,7 +151,7 @@ def gen_compare_plotly(model_a, model_b, modality, start_l, end_l,
|
|
| 148 |
return None, f"No data for Model A ({model_a})."
|
| 149 |
if df_b.empty:
|
| 150 |
return None, f"No data for Model B ({model_b})."
|
| 151 |
-
progress(0.65, desc="Building
|
| 152 |
fig = plotly_compare(df_a, df_b, _short(model_a), _short(model_b),
|
| 153 |
show_band=show_band, show_delta=show_delta)
|
| 154 |
status = (
|
|
@@ -162,12 +165,12 @@ def gen_compare_plotly(model_a, model_b, modality, start_l, end_l,
|
|
| 162 |
def gen_compare_export(model_a, model_b, modality, start_l, end_l,
|
| 163 |
show_band, show_delta, progress=gr.Progress()):
|
| 164 |
if not model_a or not model_b or model_a == model_b:
|
| 165 |
-
return "Select two different models.", None, None, None, None
|
| 166 |
progress(0.10, desc="Loading data...")
|
| 167 |
df_a = _load_df(model_a, modality, start_l, end_l)
|
| 168 |
df_b = _load_df(model_b, modality, start_l, end_l)
|
| 169 |
if df_a.empty or df_b.empty:
|
| 170 |
-
return "Missing data for one or both models.", None, None, None, None
|
| 171 |
head_dim_a, d_model_a = _infer_dims(df_a)
|
| 172 |
head_dim_b, d_model_b = _infer_dims(df_b)
|
| 173 |
head_dim = (head_dim_a + head_dim_b) // 2
|
|
@@ -185,20 +188,21 @@ def gen_compare_export(model_a, model_b, modality, start_l, end_l,
|
|
| 185 |
)
|
| 186 |
paths = save_figure(fig, base)
|
| 187 |
plt.close(fig)
|
| 188 |
-
zip_p
|
| 189 |
status = (
|
| 190 |
-
f"Exported: {', '.join(os.path.basename(p) for p in paths)}\n"
|
| 191 |
-
f"head_dimβ{head_dim} d_modelβ{d_model}"
|
| 192 |
)
|
| 193 |
progress(1.0)
|
| 194 |
png = paths[0] if len(paths) > 0 else None
|
| 195 |
pdf = paths[1] if len(paths) > 1 else None
|
| 196 |
svg = paths[2] if len(paths) > 2 else None
|
| 197 |
-
|
|
|
|
| 198 |
|
| 199 |
|
| 200 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 201 |
-
# Tab5 UI
|
| 202 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 203 |
|
| 204 |
def build_tab_plot():
|
|
@@ -206,11 +210,10 @@ def build_tab_plot():
|
|
| 206 |
gr.Markdown("""
|
| 207 |
## Wang's Five Laws β Figures
|
| 208 |
|
| 209 |
-
|
| 210 |
-
|
|
| 211 |
-
|
|
| 212 |
-
| **
|
| 213 |
-
| **Export** | Matplotlib 18Γ20 in @ 300 dpi | Slower | Paper submission (PNG/PDF/SVG) |
|
| 214 |
|
| 215 |
> Run **Tab 2 (Analyze)** first to populate the database.
|
| 216 |
""")
|
|
@@ -224,13 +227,14 @@ def build_tab_plot():
|
|
| 224 |
start_l = gr.Number(value=0, precision=0, label="Start Layer", scale=1)
|
| 225 |
end_l = gr.Number(value=47, precision=0, label="End Layer", scale=1)
|
| 226 |
show_band_chk = gr.Checkbox(
|
| 227 |
-
value=True, label="Show IQR band
|
| 228 |
)
|
| 229 |
|
| 230 |
gr.Markdown("---")
|
| 231 |
|
| 232 |
# ββ Single model ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 233 |
with gr.Accordion("π Single Model", open=True):
|
|
|
|
| 234 |
choices = _get_model_choices()
|
| 235 |
single_model = gr.Dropdown(
|
| 236 |
choices=choices,
|
|
@@ -240,39 +244,38 @@ def build_tab_plot():
|
|
| 240 |
info="Refresh page after new analysis to update this list.",
|
| 241 |
)
|
| 242 |
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
dl_s_svg = gr.File(label="β¬ SVG (vector)")
|
| 270 |
-
dl_s_zip = gr.File(label="β¬ ZIP (all)")
|
| 271 |
|
| 272 |
gr.Markdown("---")
|
| 273 |
|
| 274 |
# ββ Two-model comparison ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 275 |
with gr.Accordion("π Two-Model Comparison", open=False):
|
|
|
|
| 276 |
with gr.Row():
|
| 277 |
model_a = gr.Dropdown(
|
| 278 |
choices=choices,
|
|
@@ -290,66 +293,65 @@ def build_tab_plot():
|
|
| 290 |
value=True, label="Show Ξ fill (B β A)", scale=1
|
| 291 |
)
|
| 292 |
|
| 293 |
-
with gr.
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
dl_c_svg = gr.File(label="β¬ SVG (vector)")
|
| 317 |
-
dl_c_zip = gr.File(label="β¬ ZIP (all)")
|
| 318 |
|
| 319 |
gr.Markdown("""
|
| 320 |
---
|
| 321 |
**Reading the figures**
|
| 322 |
-
- **IQR band**
|
| 323 |
-
Narrow band β heads
|
| 324 |
-
- **Dotted vertical lines**
|
| 325 |
-
- **Dashed horizontal lines**
|
| 326 |
or random baselines (cosU: 1/βd_head Β· cosV: 1/βd_model).
|
| 327 |
-
- **Super-orthogonality** (Law 4)
|
| 328 |
-
the random baseline
|
| 329 |
""")
|
| 330 |
|
| 331 |
# ββ Wiring ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 332 |
single_plotly_btn.click(
|
| 333 |
fn=gen_single_plotly,
|
| 334 |
inputs=[single_model, modality_sel, start_l, end_l, show_band_chk],
|
| 335 |
-
outputs=[single_plotly_fig,
|
| 336 |
)
|
| 337 |
single_export_btn.click(
|
| 338 |
fn=gen_single_export,
|
| 339 |
inputs=[single_model, modality_sel, start_l, end_l, show_band_chk],
|
| 340 |
-
outputs=[
|
| 341 |
dl_s_png, dl_s_pdf, dl_s_svg, dl_s_zip],
|
| 342 |
)
|
| 343 |
cmp_plotly_btn.click(
|
| 344 |
fn=gen_compare_plotly,
|
| 345 |
inputs=[model_a, model_b, modality_sel,
|
| 346 |
start_l, end_l, show_band_chk, show_delta_chk],
|
| 347 |
-
outputs=[cmp_plotly_fig,
|
| 348 |
)
|
| 349 |
cmp_export_btn.click(
|
| 350 |
fn=gen_compare_export,
|
| 351 |
inputs=[model_a, model_b, modality_sel,
|
| 352 |
start_l, end_l, show_band_chk, show_delta_chk],
|
| 353 |
-
outputs=[
|
| 354 |
dl_c_png, dl_c_pdf, dl_c_svg, dl_c_zip],
|
| 355 |
)
|
|
|
|
| 1 |
# ui/tab_plot.py
|
| 2 |
"""
|
| 3 |
Tab5: Plot β Publication-quality figure generation
|
| 4 |
+
- Plotly native β interactive browser preview (12Γ1, full-width, fast)
|
| 5 |
+
- matplotlib β PNG / PDF / SVG export (300 dpi, paper-ready)
|
| 6 |
+
|
| 7 |
+
NO nested gr.Tabs() β avoids Gradio rendering bugs with Accordion+Tabs nesting.
|
| 8 |
+
Two side-by-side buttons instead: β‘ Interactive | π¨οΈ Export
|
| 9 |
"""
|
| 10 |
|
| 11 |
import os
|
|
|
|
| 84 |
|
| 85 |
def gen_single_plotly(model_id, modality, start_l, end_l, show_band,
|
| 86 |
progress=gr.Progress()):
|
|
|
|
| 87 |
if not model_id:
|
| 88 |
return None, "Please select a model."
|
| 89 |
progress(0.2, desc="Loading data from DB...")
|
| 90 |
df = _load_df(model_id, modality, start_l, end_l)
|
| 91 |
if df.empty:
|
| 92 |
return None, f"No data for {model_id}. Run Tab 2 analysis first."
|
| 93 |
+
progress(0.7, desc="Building Plotly figure...")
|
| 94 |
fig = plotly_single(df, _short(model_id), show_band=show_band)
|
| 95 |
status = (
|
| 96 |
f"β
{model_id} | {df['layer'].nunique()} layers "
|
|
|
|
| 102 |
|
| 103 |
def gen_single_export(model_id, modality, start_l, end_l, show_band,
|
| 104 |
progress=gr.Progress()):
|
|
|
|
| 105 |
if not model_id:
|
| 106 |
+
return "Please select a model.", None, None, None, None, None
|
| 107 |
progress(0.15, desc="Loading data from DB...")
|
| 108 |
df = _load_df(model_id, modality, start_l, end_l)
|
| 109 |
if df.empty:
|
| 110 |
+
return f"No data for {model_id}.", None, None, None, None, None
|
| 111 |
head_dim, d_model = _infer_dims(df)
|
| 112 |
+
progress(0.40, desc="Rendering matplotlib figure (18Γ20 in, 300 dpi)...")
|
| 113 |
import matplotlib.pyplot as plt
|
| 114 |
+
fig = plot_single_model(
|
| 115 |
+
df, _short(model_id),
|
| 116 |
+
show_band=show_band,
|
| 117 |
+
head_dim=head_dim, d_model=d_model,
|
| 118 |
+
)
|
| 119 |
+
progress(0.78, desc="Saving PNG / PDF / SVG...")
|
| 120 |
base = _safe_path(f"single_{_short(model_id)}_L{int(start_l)}-{int(end_l)}")
|
| 121 |
paths = save_figure(fig, base)
|
| 122 |
plt.close(fig)
|
| 123 |
+
zip_p = _make_zip(paths)
|
| 124 |
status = (
|
| 125 |
+
f"β
Exported: {', '.join(os.path.basename(p) for p in paths)}\n"
|
| 126 |
+
f" head_dim={head_dim} d_model={d_model}"
|
| 127 |
)
|
| 128 |
progress(1.0)
|
| 129 |
png = paths[0] if len(paths) > 0 else None
|
| 130 |
pdf = paths[1] if len(paths) > 1 else None
|
| 131 |
svg = paths[2] if len(paths) > 2 else None
|
| 132 |
+
# 6 values: status, preview(=png), png_dl, pdf_dl, svg_dl, zip
|
| 133 |
+
return status, png, png, pdf, svg, zip_p
|
| 134 |
|
| 135 |
|
| 136 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 151 |
return None, f"No data for Model A ({model_a})."
|
| 152 |
if df_b.empty:
|
| 153 |
return None, f"No data for Model B ({model_b})."
|
| 154 |
+
progress(0.65, desc="Building Plotly comparison figure...")
|
| 155 |
fig = plotly_compare(df_a, df_b, _short(model_a), _short(model_b),
|
| 156 |
show_band=show_band, show_delta=show_delta)
|
| 157 |
status = (
|
|
|
|
| 165 |
def gen_compare_export(model_a, model_b, modality, start_l, end_l,
|
| 166 |
show_band, show_delta, progress=gr.Progress()):
|
| 167 |
if not model_a or not model_b or model_a == model_b:
|
| 168 |
+
return "Select two different models.", None, None, None, None, None
|
| 169 |
progress(0.10, desc="Loading data...")
|
| 170 |
df_a = _load_df(model_a, modality, start_l, end_l)
|
| 171 |
df_b = _load_df(model_b, modality, start_l, end_l)
|
| 172 |
if df_a.empty or df_b.empty:
|
| 173 |
+
return "Missing data for one or both models.", None, None, None, None, None
|
| 174 |
head_dim_a, d_model_a = _infer_dims(df_a)
|
| 175 |
head_dim_b, d_model_b = _infer_dims(df_b)
|
| 176 |
head_dim = (head_dim_a + head_dim_b) // 2
|
|
|
|
| 188 |
)
|
| 189 |
paths = save_figure(fig, base)
|
| 190 |
plt.close(fig)
|
| 191 |
+
zip_p = _make_zip(paths)
|
| 192 |
status = (
|
| 193 |
+
f"β
Exported: {', '.join(os.path.basename(p) for p in paths)}\n"
|
| 194 |
+
f" head_dimβ{head_dim} d_modelβ{d_model}"
|
| 195 |
)
|
| 196 |
progress(1.0)
|
| 197 |
png = paths[0] if len(paths) > 0 else None
|
| 198 |
pdf = paths[1] if len(paths) > 1 else None
|
| 199 |
svg = paths[2] if len(paths) > 2 else None
|
| 200 |
+
# 6 values: status, preview(=png), png_dl, pdf_dl, svg_dl, zip
|
| 201 |
+
return status, png, png, pdf, svg, zip_p
|
| 202 |
|
| 203 |
|
| 204 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 205 |
+
# Tab5 UI β NO nested gr.Tabs() inside Accordion
|
| 206 |
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 207 |
|
| 208 |
def build_tab_plot():
|
|
|
|
| 210 |
gr.Markdown("""
|
| 211 |
## Wang's Five Laws β Figures
|
| 212 |
|
| 213 |
+
| Button | Engine | Speed | Output |
|
| 214 |
+
|--------|--------|-------|--------|
|
| 215 |
+
| β‘ **Interactive** | Native Plotly 12Γ1 full-width | ~2 s | In-page, hover/zoom |
|
| 216 |
+
| π¨οΈ **Export** | Matplotlib 18Γ20 in @ 300 dpi | ~30 s | PNG Β· PDF Β· SVG download |
|
|
|
|
| 217 |
|
| 218 |
> Run **Tab 2 (Analyze)** first to populate the database.
|
| 219 |
""")
|
|
|
|
| 227 |
start_l = gr.Number(value=0, precision=0, label="Start Layer", scale=1)
|
| 228 |
end_l = gr.Number(value=47, precision=0, label="End Layer", scale=1)
|
| 229 |
show_band_chk = gr.Checkbox(
|
| 230 |
+
value=True, label="Show IQR band", scale=1
|
| 231 |
)
|
| 232 |
|
| 233 |
gr.Markdown("---")
|
| 234 |
|
| 235 |
# ββ Single model ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 236 |
with gr.Accordion("π Single Model", open=True):
|
| 237 |
+
|
| 238 |
choices = _get_model_choices()
|
| 239 |
single_model = gr.Dropdown(
|
| 240 |
choices=choices,
|
|
|
|
| 244 |
info="Refresh page after new analysis to update this list.",
|
| 245 |
)
|
| 246 |
|
| 247 |
+
# Two side-by-side buttons β no nested Tabs
|
| 248 |
+
with gr.Row():
|
| 249 |
+
single_plotly_btn = gr.Button(
|
| 250 |
+
"β‘ Interactive (Plotly)", variant="primary", scale=1
|
| 251 |
+
)
|
| 252 |
+
single_export_btn = gr.Button(
|
| 253 |
+
"π¨οΈ Export PNG / PDF / SVG", variant="secondary", scale=1
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
single_status = gr.Textbox(
|
| 257 |
+
lines=2, interactive=False, label="Status"
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
# Interactive output β always visible, populated on demand
|
| 261 |
+
single_plotly_fig = gr.Plot(label="Interactive figure")
|
| 262 |
+
|
| 263 |
+
# Export outputs β always visible, populated on demand
|
| 264 |
+
gr.Markdown("#### π¨οΈ Export outputs")
|
| 265 |
+
single_preview = gr.Image(
|
| 266 |
+
type="filepath", label="PNG preview (click to enlarge)", height=350
|
| 267 |
+
)
|
| 268 |
+
with gr.Row():
|
| 269 |
+
dl_s_png = gr.File(label="β¬ PNG (300 dpi)")
|
| 270 |
+
dl_s_pdf = gr.File(label="β¬ PDF (vector)")
|
| 271 |
+
dl_s_svg = gr.File(label="β¬ SVG (vector)")
|
| 272 |
+
dl_s_zip = gr.File(label="β¬ ZIP (all formats)")
|
|
|
|
|
|
|
| 273 |
|
| 274 |
gr.Markdown("---")
|
| 275 |
|
| 276 |
# ββ Two-model comparison ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 277 |
with gr.Accordion("π Two-Model Comparison", open=False):
|
| 278 |
+
|
| 279 |
with gr.Row():
|
| 280 |
model_a = gr.Dropdown(
|
| 281 |
choices=choices,
|
|
|
|
| 293 |
value=True, label="Show Ξ fill (B β A)", scale=1
|
| 294 |
)
|
| 295 |
|
| 296 |
+
with gr.Row():
|
| 297 |
+
cmp_plotly_btn = gr.Button(
|
| 298 |
+
"β‘ Interactive (Plotly)", variant="primary", scale=1
|
| 299 |
+
)
|
| 300 |
+
cmp_export_btn = gr.Button(
|
| 301 |
+
"π¨οΈ Export PNG / PDF / SVG", variant="secondary", scale=1
|
| 302 |
+
)
|
| 303 |
+
|
| 304 |
+
cmp_status = gr.Textbox(
|
| 305 |
+
lines=2, interactive=False, label="Status"
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
cmp_plotly_fig = gr.Plot(label="Interactive comparison figure")
|
| 309 |
+
|
| 310 |
+
gr.Markdown("#### π¨οΈ Export outputs")
|
| 311 |
+
cmp_preview = gr.Image(
|
| 312 |
+
type="filepath", label="PNG preview", height=350
|
| 313 |
+
)
|
| 314 |
+
with gr.Row():
|
| 315 |
+
dl_c_png = gr.File(label="β¬ PNG (300 dpi)")
|
| 316 |
+
dl_c_pdf = gr.File(label="β¬ PDF (vector)")
|
| 317 |
+
dl_c_svg = gr.File(label="β¬ SVG (vector)")
|
| 318 |
+
dl_c_zip = gr.File(label="β¬ ZIP (all formats)")
|
|
|
|
|
|
|
| 319 |
|
| 320 |
gr.Markdown("""
|
| 321 |
---
|
| 322 |
**Reading the figures**
|
| 323 |
+
- **IQR band** β 25%β75% quantile across attention heads per layer.
|
| 324 |
+
Narrow band β heads are consistent β model is well-organized.
|
| 325 |
+
- **Dotted vertical lines** β global (K=V shared) layers (Gemma-4 only).
|
| 326 |
+
- **Dashed horizontal lines** β theoretical ideals (r=1, SSR=0, Ξ±=1)
|
| 327 |
or random baselines (cosU: 1/βd_head Β· cosV: 1/βd_model).
|
| 328 |
+
- **Super-orthogonality** (Law 4) β cosU(QβV) and cosU(KβV) sit *below*
|
| 329 |
+
the random baseline; pretraining actively pushes V away from Q/K.
|
| 330 |
""")
|
| 331 |
|
| 332 |
# ββ Wiring ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 333 |
+
|
| 334 |
single_plotly_btn.click(
|
| 335 |
fn=gen_single_plotly,
|
| 336 |
inputs=[single_model, modality_sel, start_l, end_l, show_band_chk],
|
| 337 |
+
outputs=[single_plotly_fig, single_status],
|
| 338 |
)
|
| 339 |
single_export_btn.click(
|
| 340 |
fn=gen_single_export,
|
| 341 |
inputs=[single_model, modality_sel, start_l, end_l, show_band_chk],
|
| 342 |
+
outputs=[single_status, single_preview,
|
| 343 |
dl_s_png, dl_s_pdf, dl_s_svg, dl_s_zip],
|
| 344 |
)
|
| 345 |
cmp_plotly_btn.click(
|
| 346 |
fn=gen_compare_plotly,
|
| 347 |
inputs=[model_a, model_b, modality_sel,
|
| 348 |
start_l, end_l, show_band_chk, show_delta_chk],
|
| 349 |
+
outputs=[cmp_plotly_fig, cmp_status],
|
| 350 |
)
|
| 351 |
cmp_export_btn.click(
|
| 352 |
fn=gen_compare_export,
|
| 353 |
inputs=[model_a, model_b, modality_sel,
|
| 354 |
start_l, end_l, show_band_chk, show_delta_chk],
|
| 355 |
+
outputs=[cmp_status, cmp_preview,
|
| 356 |
dl_c_png, dl_c_pdf, dl_c_svg, dl_c_zip],
|
| 357 |
)
|