Spaces:
Sleeping
Sleeping
Marlin Lee
UI redesign: consistent design system, card layout, unified colors and typography
4a5ed93 | """ | |
| Pure feature display logic — no Bokeh dependencies. | |
| Builds the data needed to render a feature's detail view: stats HTML, | |
| top MEI image list, and NSD sample basename. Called by panels/feature.py. | |
| """ | |
| import os | |
| from PIL import Image as _PILImage | |
| from .rendering import ( | |
| THUMB, load_image, render_zoomed_overlay, _img_pool, | |
| ) | |
| def build_stats_html(feat: int, freq_val, feat_name: str, | |
| auto_name: str) -> str: | |
| """Return the feature header HTML (name + label).""" | |
| if freq_val == 0: | |
| label = ('<span style="color:#dc2626;font-size:13px;margin-left:8px;' | |
| 'font-weight:500">dead feature</span>') | |
| elif feat_name: | |
| label = (f'<div style="color:#2563eb;font-style:italic;' | |
| f'font-size:14px;margin-top:4px">{feat_name}</div>') | |
| elif auto_name: | |
| label = (f'<div style="color:#059669;font-style:italic;' | |
| f'font-size:14px;margin-top:4px">{auto_name}</div>') | |
| else: | |
| label = '' | |
| return (f'<h2 style="margin:4px 0;font-size:22px;font-weight:700;' | |
| f'color:#1a1d23">Feature {feat}</h2>' + label) | |
| def build_top_mei_items(feat: int, ds: dict, n_display: int = 9, | |
| zoom_patches: int = 16, | |
| heatmap_alpha: float = 1.0): | |
| """Load and render top MEI images for a feature. | |
| Returns (top_infos, top_img_is, subset_label) where: | |
| top_infos — list of (PIL.Image, caption_str) tuples | |
| top_img_is — parallel list of dataset image indices | |
| subset_label — " [NSD sub01]" or "" | |
| """ | |
| use_nsd = ds.get('nsd_top_img_idx') is not None | |
| top_idx = ds['nsd_top_img_idx'] if use_nsd else ds['top_img_idx'] | |
| top_hm = ds.get('nsd_top_heatmaps') if use_nsd else ds.get('top_heatmaps') | |
| subset_label = " [NSD sub01]" if use_nsd else "" | |
| def _render_one(ranking_idx): | |
| img_i = top_idx[feat, ranking_idx].item() | |
| try: | |
| hm = None | |
| if top_hm is not None and ds['heatmap_patch_grid'] > 1: | |
| hm = top_hm[feat, ranking_idx].float().numpy() | |
| hm = hm.reshape(ds['heatmap_patch_grid'], | |
| ds['heatmap_patch_grid']) | |
| if hm is None: | |
| plain = load_image(img_i).resize((THUMB, THUMB)) | |
| return (plain, "") | |
| img_out = render_zoomed_overlay( | |
| img_i, hm, size=THUMB, | |
| zoom_patches=zoom_patches, | |
| alpha=heatmap_alpha, | |
| center='peak', | |
| ) | |
| return (img_out, "") | |
| except (FileNotFoundError, OSError): | |
| return None | |
| except Exception as e: | |
| return (_PILImage.new("RGB", (THUMB, THUMB), "gray"), | |
| f"Error: {e}") | |
| # Build work list | |
| work = [] | |
| for j in range(min(n_display, top_idx.shape[1])): | |
| img_i = top_idx[feat, j].item() | |
| if img_i < 0: | |
| break | |
| work.append((j, img_i)) | |
| # Load MEIs in parallel | |
| top_infos = [] | |
| top_img_is = [] | |
| for (j, img_i), item in zip( | |
| work, _img_pool.map(lambda w: _render_one(w[0]), work)): | |
| if item is not None: | |
| top_infos.append(item) | |
| top_img_is.append(img_i) | |
| return top_infos, top_img_is, subset_label | |
| def get_nsd_sample_basename(feat: int, ds: dict) -> str | None: | |
| """Return the NSD basename for the top image of a feature, or None.""" | |
| if ds.get('nsd_top_img_idx') is None: | |
| return None | |
| top_i = ds['nsd_top_img_idx'][feat, 0].item() | |
| if top_i < 0: | |
| return None | |
| return os.path.splitext(os.path.basename(ds['image_paths'][top_i]))[0] | |