kaveh commited on
Commit
d0d44b9
·
1 Parent(s): 253fc7e

added hover on doughnut and tooltip on experiment image

Browse files
streamlit_hf/home.py CHANGED
@@ -76,6 +76,43 @@ def _downsample_latent_df(df, max_points: int = 6500, seed: int = 42):
76
  return df.sample(n=max_points, random_state=seed)
77
 
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  ui.inject_app_styles()
80
  ui.inject_home_landing_styles()
81
 
@@ -94,7 +131,7 @@ with st.container(border=True):
94
  fig_col, text_col = st.columns([0.42, 0.58], gap="large")
95
  with fig_col:
96
  if _EXPERIMENT_SVG.is_file():
97
- st.image(str(_EXPERIMENT_SVG), width=_EXPERIMENT_FIGURE_WIDTH_PX)
98
  else:
99
  st.caption("Experimental schematic (`static/experiment.svg`) is missing.")
100
  with text_col:
@@ -219,6 +256,7 @@ if bundle is not None and df_features is not None:
219
  top_n_pie=_HOME_PIE_TOP_N,
220
  chart_outline=False,
221
  modality_mix_hole=0.66,
 
222
  )
223
  fig_g.update_layout(title_text="", margin=dict(l=36, r=36, t=48, b=100))
224
  fig_g.update_annotations(font_size=12)
@@ -269,6 +307,7 @@ elif df_features is not None:
269
  top_n_pie=_HOME_PIE_TOP_N,
270
  chart_outline=False,
271
  modality_mix_hole=0.66,
 
272
  )
273
  fig_g.update_layout(title_text="", margin=dict(l=36, r=36, t=48, b=100))
274
  st.plotly_chart(fig_g, width="stretch", config={"displayModeBar": False, "displaylogo": False})
 
76
  return df.sample(n=max_points, random_state=seed)
77
 
78
 
79
+ def _render_experiment_schematic(width_px: int) -> None:
80
+ """Show the schematic as inline SVG so each group can use CSS hover and native tooltips."""
81
+ raw = _EXPERIMENT_SVG.read_text(encoding="utf-8")
82
+ if raw.lstrip().startswith("<?xml"):
83
+ raw = raw.split("?>", 1)[1].lstrip()
84
+ html_doc = f"""<!DOCTYPE html>
85
+ <html><head><meta charset="utf-8"/><style>
86
+ html, body {{ margin: 0; padding: 0; overflow: hidden; background: transparent; }}
87
+ .ff-experiment-svg-wrap {{ width: {width_px}px; max-width: 100%; }}
88
+ .ff-experiment-svg-wrap svg {{ width: 100%; height: auto; display: block; }}
89
+ .ff-experiment-svg-wrap svg g[id] {{
90
+ cursor: help;
91
+ transition: filter 0.15s ease;
92
+ }}
93
+ .ff-experiment-svg-wrap svg g[id]:hover {{
94
+ filter: brightness(1.12) drop-shadow(0 0 1.5px rgba(79, 70, 229, 0.55));
95
+ }}
96
+ /* Microscope: decorative only (no tooltip); ignore pointer so it does not steal hovers. */
97
+ .ff-experiment-svg-wrap svg #microscope,
98
+ .ff-experiment-svg-wrap svg #microscope * {{
99
+ pointer-events: none;
100
+ }}
101
+ .ff-experiment-svg-wrap svg text {{
102
+ cursor: help;
103
+ transition: filter 0.15s ease;
104
+ }}
105
+ .ff-experiment-svg-wrap svg text:hover {{
106
+ filter: brightness(1.08);
107
+ }}
108
+ </style></head><body>
109
+ <div class="ff-experiment-svg-wrap">
110
+ {raw}
111
+ </div>
112
+ </body></html>"""
113
+ st.iframe(html_doc, width=width_px, height="content")
114
+
115
+
116
  ui.inject_app_styles()
117
  ui.inject_home_landing_styles()
118
 
 
131
  fig_col, text_col = st.columns([0.42, 0.58], gap="large")
132
  with fig_col:
133
  if _EXPERIMENT_SVG.is_file():
134
+ _render_experiment_schematic(_EXPERIMENT_FIGURE_WIDTH_PX)
135
  else:
136
  st.caption("Experimental schematic (`static/experiment.svg`) is missing.")
137
  with text_col:
 
256
  top_n_pie=_HOME_PIE_TOP_N,
257
  chart_outline=False,
258
  modality_mix_hole=0.66,
259
+ modality_mix_hover_feature_list=True,
260
  )
261
  fig_g.update_layout(title_text="", margin=dict(l=36, r=36, t=48, b=100))
262
  fig_g.update_annotations(font_size=12)
 
307
  top_n_pie=_HOME_PIE_TOP_N,
308
  chart_outline=False,
309
  modality_mix_hole=0.66,
310
+ modality_mix_hover_feature_list=True,
311
  )
312
  fig_g.update_layout(title_text="", margin=dict(l=36, r=36, t=48, b=100))
313
  st.plotly_chart(fig_g, width="stretch", config={"displayModeBar": False, "displaylogo": False})
streamlit_hf/lib/plots.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
 
5
  from typing import Any
6
 
7
  import numpy as np
@@ -557,6 +558,18 @@ def attention_cohort_view(
557
  return fig
558
 
559
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  def global_rank_triple_panel(
561
  df_features,
562
  top_n: int = 20,
@@ -564,6 +577,7 @@ def global_rank_triple_panel(
564
  *,
565
  chart_outline: bool = True,
566
  modality_mix_hole: float = 0.0,
 
567
  ):
568
  """
569
  Global top-N by latent-shift and by attention (min-max scaled), plus pie or donut of modality mix
@@ -571,6 +585,8 @@ def global_rank_triple_panel(
571
 
572
  Set ``chart_outline=False`` for a flatter look (e.g. home page); Feature Insights keeps outlines by default.
573
  Set ``modality_mix_hole`` in (0, 1), e.g. ``0.66``, for a donut instead of a full pie (e.g. home page).
 
 
574
  """
575
  d = df_features.copy()
576
  for col in ("importance_shift", "importance_att"):
@@ -636,20 +652,37 @@ def global_rank_triple_panel(
636
  _hole = float(modality_mix_hole) if modality_mix_hole and modality_mix_hole > 0 else 0.0
637
  # Narrow third subplot: "auto" avoids clipped outside labels on donuts.
638
  _pie_textpos = "auto"
639
- fig.add_trace(
640
- go.Pie(
641
- labels=pie_labels,
642
- values=pie_vals,
643
- marker=dict(
644
- colors=[MODALITY_PIE_COLOR.get(l, "#64748b") for l in pie_labels],
645
- line=pie_line,
646
- ),
647
- textinfo="label+percent",
648
- textfont_size=12,
649
- textposition=_pie_textpos,
650
- hole=_hole,
651
- showlegend=False,
652
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  row=1,
654
  col=3,
655
  )
 
2
 
3
  from __future__ import annotations
4
 
5
+ import html
6
  from typing import Any
7
 
8
  import numpy as np
 
558
  return fig
559
 
560
 
561
+ def _pie_hover_feature_lines(names: list[str], *, names_per_line: int = 5) -> str:
562
+ """Join feature names with commas; start a new hover row every ``names_per_line`` items (HTML ``<br>``)."""
563
+ if not names:
564
+ return "—"
565
+ safe = [html.escape(str(n), quote=False) for n in names]
566
+ step = max(1, int(names_per_line))
567
+ lines: list[str] = []
568
+ for i in range(0, len(safe), step):
569
+ lines.append(", ".join(safe[i : i + step]))
570
+ return "<br>".join(lines)
571
+
572
+
573
  def global_rank_triple_panel(
574
  df_features,
575
  top_n: int = 20,
 
577
  *,
578
  chart_outline: bool = True,
579
  modality_mix_hole: float = 0.0,
580
+ modality_mix_hover_feature_list: bool = False,
581
  ):
582
  """
583
  Global top-N by latent-shift and by attention (min-max scaled), plus pie or donut of modality mix
 
585
 
586
  Set ``chart_outline=False`` for a flatter look (e.g. home page); Feature Insights keeps outlines by default.
587
  Set ``modality_mix_hole`` in (0, 1), e.g. ``0.66``, for a donut instead of a full pie (e.g. home page).
588
+ Set ``modality_mix_hover_feature_list=True`` to show comma-separated feature names per donut slice on hover
589
+ (same pool as the pie: strongest by mean rank within each modality), wrapped every few names for readability.
590
  """
591
  d = df_features.copy()
592
  for col in ("importance_shift", "importance_att"):
 
652
  _hole = float(modality_mix_hole) if modality_mix_hole and modality_mix_hole > 0 else 0.0
653
  # Narrow third subplot: "auto" avoids clipped outside labels on donuts.
654
  _pie_textpos = "auto"
655
+ _pie_kwargs: dict = dict(
656
+ labels=pie_labels,
657
+ values=pie_vals,
658
+ marker=dict(
659
+ colors=[MODALITY_PIE_COLOR.get(l, "#64748b") for l in pie_labels],
660
+ line=pie_line,
 
 
 
 
 
 
 
661
  ),
662
+ textinfo="label+percent",
663
+ textfont_size=12,
664
+ textposition=_pie_textpos,
665
+ hole=_hole,
666
+ showlegend=False,
667
+ )
668
+ if modality_mix_hover_feature_list:
669
+ _hover_texts: list[str] = []
670
+ for lab in pie_labels:
671
+ sub = pie_pool[pie_pool["modality"] == lab]
672
+ if sub.empty:
673
+ _hover_texts.append("—")
674
+ else:
675
+ sub = sub.sort_values("mean_rank", ascending=True, kind="mergesort")
676
+ _per_line = 1 if lab == "Flux" else 5
677
+ _hover_texts.append(
678
+ _pie_hover_feature_lines(sub["feature"].astype(str).tolist(), names_per_line=_per_line)
679
+ )
680
+ _pie_kwargs["hovertext"] = _hover_texts
681
+ _pie_kwargs["hovertemplate"] = (
682
+ "<b>%{label}</b> · %{value} features (%{percent:.1%})<br><br>%{hovertext}<extra></extra>"
683
+ )
684
+ fig.add_trace(
685
+ go.Pie(**_pie_kwargs),
686
  row=1,
687
  col=3,
688
  )
streamlit_hf/static/experiment.svg CHANGED