Spaces:
Sleeping
Sleeping
Marlin Lee
Fix Bokeh _pending_writes error by deferring on_change work; guard slider access against stale sessions
b7739d5 | """ | |
| Feature detail panel: stats header, top NSD MEI grid, cortical profile. | |
| Pure display logic lives in explorer.feature_logic. | |
| Exports: | |
| update_feature_display(feat) | |
| select_and_display(feat) | |
| status_div, stats_div, top_heatmap_div, brain_div | |
| add_steer_btn | |
| """ | |
| import threading | |
| from bokeh.io import curdoc | |
| from bokeh.models import Button, Div | |
| from ..state import _S, active_ds | |
| from ..brain import HAS_DYNADIFF, render_cortical_profile | |
| from ..feature_logic import build_stats_html, build_top_mei_items | |
| from ..rendering import status_html, make_image_grid_html | |
| from .. import widgets | |
| N_DISPLAY = 9 | |
| # ---------- Divs ---------- | |
| status_div = Div(text=status_html('idle', 'Select a feature to begin.'), width=680) | |
| stats_div = Div(text="<h3>Select a feature to explore it</h3>", width=530) | |
| top_heatmap_div = Div(text="", width=680) | |
| brain_div = Div(text="", width=680) | |
| add_steer_btn = Button( | |
| label="+ Add to Steer", | |
| button_type="success", | |
| width=140, | |
| visible=HAS_DYNADIFF, | |
| ) | |
| # ---------- Core display logic ---------- | |
| def update_feature_display(feature_idx): | |
| feat = int(feature_idx) | |
| _S.render_token += 1 | |
| my_token = _S.render_token | |
| ds = active_ds() | |
| freq_val = ds['feature_frequency'][feat].item() | |
| feat_name = ds['feature_names'].get(feat, "") | |
| auto_name = ds['auto_interp_names'].get(feat, "") | |
| stats_div.text = build_stats_html(feat, freq_val, feat_name, auto_name) | |
| # Sync name-editing widget | |
| from .feature_list import name_input | |
| name_input.value = feat_name | |
| if freq_val == 0: | |
| status_div.text = status_html('dead', f'Feature {feat} never activated.') | |
| brain_div.text = render_cortical_profile(feat) | |
| top_heatmap_div.text = "" | |
| add_steer_btn.visible = False | |
| return | |
| add_steer_btn.visible = HAS_DYNADIFF | |
| status_div.text = status_html('loading', '⏳ Loading...') | |
| doc = curdoc() | |
| def _render(): | |
| if _S.render_token != my_token: | |
| return | |
| _ds = active_ds() | |
| try: | |
| zp = int(widgets.zoom_slider.value) | |
| ha = widgets.heatmap_alpha_slider.value | |
| except Exception: | |
| zp, ha = 16, 1.0 | |
| top_infos, top_img_is, subset_label = build_top_mei_items( | |
| feat, _ds, n_display=N_DISPLAY, | |
| zoom_patches=zp, | |
| heatmap_alpha=ha, | |
| ) | |
| top_heatmap_div.text = make_image_grid_html( | |
| top_infos, f"Top MEIs (feature {feat}){subset_label}", | |
| img_indices=top_img_is, cols=3) | |
| status_div.text = status_html('idle', '') | |
| # Render cortical profile in background thread so the UI stays responsive | |
| brain_div.text = "" | |
| def _render_brain(): | |
| html = render_cortical_profile(feat) | |
| def _update_brain(): | |
| if _S.render_token == my_token: | |
| brain_div.text = html | |
| doc.add_next_tick_callback(_update_brain) | |
| threading.Thread(target=_render_brain, daemon=True).start() | |
| doc.add_next_tick_callback(_render) | |
| def select_and_display(feat: int): | |
| """Display feature detail and highlight it.""" | |
| widgets.feature_input.value = str(feat) | |
| update_feature_display(feat) | |
| # ---------- Add-to-Steer callback ---------- | |
| def _on_add_steer(): | |
| try: | |
| feat = int(widgets.feature_input.value) | |
| except ValueError: | |
| return | |
| from .steering import add_feature | |
| add_feature(feat) | |
| add_steer_btn.on_click(_on_add_steer) | |
| # ---------- Re-render on zoom/alpha changes ---------- | |
| def _rerender_current(attr, old, new): | |
| try: | |
| feat = int(widgets.feature_input.value) | |
| if 0 <= feat < active_ds()['d_model']: | |
| update_feature_display(feat) | |
| except ValueError: | |
| pass | |
| widgets.zoom_slider.on_change('value', _rerender_current) | |
| widgets.heatmap_alpha_slider.on_change('value', _rerender_current) | |