Marlin Lee commited on
Commit
f84765f
Β·
1 Parent(s): f7be737

Sync explorer_app.py and clip_utils.py from main repo

Browse files
Files changed (1) hide show
  1. scripts/explorer_app.py +67 -8
scripts/explorer_app.py CHANGED
@@ -557,6 +557,57 @@ def make_image_grid_html(images_info, title, cols=9):
557
  return html
558
 
559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  # ---------- UMAP data source ----------
561
  # live_mask / live_indices / freq / mean_act / log_freq / umap_backup are all
562
  # already set by _apply_dataset_globals(0) above β€” just build the source from them.
@@ -699,6 +750,7 @@ mean_heatmap_div = Div(text="", width=900)
699
  mean_zoom_div = Div(text="", width=900)
700
  p75_heatmap_div = Div(text="", width=900)
701
  p75_zoom_div = Div(text="", width=900)
 
702
 
703
  # Name editing widget (defined here so update_feature_display can reference it)
704
  name_input = TextInput(
@@ -786,7 +838,8 @@ def update_feature_display(feature_idx):
786
  'dead', f'Feature {feat} is dead β€” it never activated on the precompute set.')
787
  for div in [top_heatmap_div, top_zoom_div,
788
  mean_heatmap_div, mean_zoom_div,
789
- p75_heatmap_div, p75_zoom_div]:
 
790
  div.text = ""
791
  return
792
 
@@ -879,6 +932,10 @@ def update_feature_display(feature_idx):
879
  p75_zoom_div.text = make_image_grid_html(
880
  p75_zm_infos, f"75th Percentile β€” Zoomed to peak patch (feature {feat})")
881
 
 
 
 
 
882
  status_div.text = _status_html('ok', f'✓ Feature {feat} ready.')
883
  _update_view_visibility()
884
 
@@ -888,13 +945,14 @@ def update_feature_display(feature_idx):
888
  # ---------- View visibility ----------
889
  def _update_view_visibility():
890
  v = view_select.value
891
- compare_all = (v == "Compare aggregations")
892
- top_heatmap_div.visible = compare_all or (v == "Top (max activation)")
893
- top_zoom_div.visible = compare_all or (v == "Top (max activation)")
894
- mean_heatmap_div.visible = compare_all or (v == "Mean activation")
895
- mean_zoom_div.visible = compare_all or (v == "Mean activation")
896
- p75_heatmap_div.visible = compare_all or (v == "75th percentile")
897
- p75_zoom_div.visible = compare_all or (v == "75th percentile")
 
898
 
899
  view_select.on_change('value', lambda attr, old, new: _update_view_visibility())
900
  _update_view_visibility() # set initial state
@@ -1727,6 +1785,7 @@ middle_panel = column(
1727
  stats_div,
1728
  name_panel,
1729
  row(view_select, zoom_slider, heatmap_alpha_slider),
 
1730
  top_heatmap_div, top_zoom_div,
1731
  mean_heatmap_div, mean_zoom_div,
1732
  p75_heatmap_div, p75_zoom_div,
 
557
  return html
558
 
559
 
560
+ def make_compare_aggregations_html(top_infos, mean_infos, p75_infos, feat, n_each=5):
561
+ """Paper-ready side-by-side comparison of Top / Mean / 75th-percentile aggregations.
562
+
563
+ Each method gets its own column with a styled header. Images are shown at a
564
+ reduced size so all three columns fit comfortably for a screenshot.
565
+ """
566
+ col_thumb = min(THUMB, 160)
567
+
568
+ sections = [
569
+ ("Top (Max Activation)", "#2563a8", top_infos),
570
+ ("Mean Activation", "#1a7a4a", mean_infos),
571
+ ("75th Percentile", "#7a3a9a", p75_infos),
572
+ ]
573
+
574
+ html = (
575
+ '<div style="font-family:Arial,Helvetica,sans-serif;background:#ffffff;'
576
+ 'padding:14px 16px 10px 16px;border:1px solid #d0d0d0;border-radius:6px;'
577
+ 'display:inline-block;box-shadow:0 1px 4px rgba(0,0,0,0.08)">'
578
+ f'<div style="font-size:12px;color:#666;margin-bottom:10px;letter-spacing:0.2px">'
579
+ f'<b>Feature {feat}</b> β€” aggregation method comparison</div>'
580
+ '<div style="display:flex;gap:20px;align-items:flex-start">'
581
+ )
582
+
583
+ for method_name, color, infos in sections:
584
+ html += (
585
+ '<div style="min-width:0">'
586
+ f'<div style="background:{color};color:#ffffff;font-size:12px;font-weight:bold;'
587
+ f'text-align:center;padding:5px 14px;border-radius:4px;margin-bottom:8px;'
588
+ f'letter-spacing:0.5px">{method_name}</div>'
589
+ '<div style="display:flex;gap:6px;flex-wrap:wrap">'
590
+ )
591
+ shown = (infos or [])[:n_each]
592
+ if not shown:
593
+ html += '<div style="color:#aaa;font-style:italic;font-size:11px;padding:8px">No images</div>'
594
+ for img, caption in shown:
595
+ url = pil_to_data_url(img)
596
+ parts = caption.split('<br>')
597
+ cap_html = '<br>'.join(parts)
598
+ html += (
599
+ f'<div style="text-align:center">'
600
+ f'<img src="{url}" width="{col_thumb}" height="{col_thumb}"'
601
+ f' style="border:1px solid #ccc;border-radius:3px;display:block"/>'
602
+ f'<div style="font-size:9px;color:#555;margin-top:2px;line-height:1.35">'
603
+ f'{cap_html}</div></div>'
604
+ )
605
+ html += '</div></div>'
606
+
607
+ html += '</div></div>'
608
+ return html
609
+
610
+
611
  # ---------- UMAP data source ----------
612
  # live_mask / live_indices / freq / mean_act / log_freq / umap_backup are all
613
  # already set by _apply_dataset_globals(0) above β€” just build the source from them.
 
750
  mean_zoom_div = Div(text="", width=900)
751
  p75_heatmap_div = Div(text="", width=900)
752
  p75_zoom_div = Div(text="", width=900)
753
+ compare_agg_div = Div(text="", width=1400) # side-by-side aggregation comparison
754
 
755
  # Name editing widget (defined here so update_feature_display can reference it)
756
  name_input = TextInput(
 
838
  'dead', f'Feature {feat} is dead β€” it never activated on the precompute set.')
839
  for div in [top_heatmap_div, top_zoom_div,
840
  mean_heatmap_div, mean_zoom_div,
841
+ p75_heatmap_div, p75_zoom_div,
842
+ compare_agg_div]:
843
  div.text = ""
844
  return
845
 
 
932
  p75_zoom_div.text = make_image_grid_html(
933
  p75_zm_infos, f"75th Percentile β€” Zoomed to peak patch (feature {feat})")
934
 
935
+ # Side-by-side aggregation comparison (paper-ready screenshot view)
936
+ compare_agg_div.text = make_compare_aggregations_html(
937
+ heatmap_infos, mean_hm_infos, p75_hm_infos, feat)
938
+
939
  status_div.text = _status_html('ok', f'&#x2713; Feature {feat} ready.')
940
  _update_view_visibility()
941
 
 
945
  # ---------- View visibility ----------
946
  def _update_view_visibility():
947
  v = view_select.value
948
+ is_compare = (v == "Compare aggregations")
949
+ top_heatmap_div.visible = (v == "Top (max activation)")
950
+ top_zoom_div.visible = (v == "Top (max activation)")
951
+ mean_heatmap_div.visible = (v == "Mean activation")
952
+ mean_zoom_div.visible = (v == "Mean activation")
953
+ p75_heatmap_div.visible = (v == "75th percentile")
954
+ p75_zoom_div.visible = (v == "75th percentile")
955
+ compare_agg_div.visible = is_compare
956
 
957
  view_select.on_change('value', lambda attr, old, new: _update_view_visibility())
958
  _update_view_visibility() # set initial state
 
1785
  stats_div,
1786
  name_panel,
1787
  row(view_select, zoom_slider, heatmap_alpha_slider),
1788
+ compare_agg_div,
1789
  top_heatmap_div, top_zoom_div,
1790
  mean_heatmap_div, mean_zoom_div,
1791
  p75_heatmap_div, p75_zoom_div,