kaveh commited on
Commit
a09fc4e
·
1 Parent(s): fa3d48f

fixed tooltip and hnf4a

Browse files
streamlit_hf/home.py CHANGED
@@ -55,7 +55,7 @@ _APP_SUBTITLE = (
55
  )
56
 
57
  _EXPERIMENTAL_SYSTEM_MD = f"""
58
- Mouse embryonic fibroblasts (**MEFs**) were reprogrammed toward induced endoderm progenitors (**iEPs**) **in vitro** through *Foxa1* and *HNF4A* induction.
59
 
60
  This process produces **mixed outcomes**: some cells successfully reach the **iEP fate**, whereas others diverge into **off-target** trajectories and stall in **dead-end states**.
61
 
@@ -193,7 +193,7 @@ html, body {{
193
  ui.inject_app_styles()
194
  ui.inject_home_landing_styles()
195
 
196
- # Bordered Streamlit blocks use overflow that clips iframe tooltips; allow paint past the card edge.
197
  st.markdown(
198
  """
199
  <style>
@@ -203,82 +203,56 @@ section[data-testid="stMain"] div[data-testid="stVerticalBlockBorderWrapper"]:ha
203
  section[data-testid="stMain"] div[data-testid="stVerticalBlockBorderWrapper"]:has(iframe) > div {
204
  overflow: visible !important;
205
  }
206
- </style>
207
- """,
208
- unsafe_allow_html=True,
209
- )
210
-
211
- st.markdown(
212
- f"""<div class="ff-hero"><div class="ff-hero-inner"><div class="ff-hero-text">
213
- <div class="ff-hero-title-row">
214
- <span class="ff-hero-emoji" aria-hidden="true">{_HERO_EMOJI}</span>
215
- <h1>{html.escape(_APP_NAME)}</h1>
216
- </div>
217
- <p class="ff-hero-sub">{html.escape(_APP_SUBTITLE)}</p>
218
- </div></div></div>""",
219
- unsafe_allow_html=True,
220
- )
221
-
222
- with st.container(border=True):
223
- # Wider text column → fewer wrapped lines; tighter gap; center figure vs text when heights differ.
224
- try:
225
- fig_col, text_col = st.columns([0.33, 0.67], gap="medium", vertical_alignment="center")
226
- except TypeError:
227
- fig_col, text_col = st.columns([0.33, 0.67], gap="medium")
228
- with fig_col:
229
- if _EXPERIMENT_SVG.is_file():
230
- _render_experiment_schematic(_EXPERIMENT_FIGURE_WIDTH_PX)
231
- else:
232
- st.caption("Experimental schematic (`static/experiment.svg`) is missing.")
233
- with text_col:
234
- st.markdown(_EXPERIMENTAL_SYSTEM_MD)
235
-
236
- bundle = io.load_latent_bundle()
237
- df_features = io.load_df_features()
238
- samples = io.load_samples_df()
239
- ready = _cache_ok()
240
-
241
- if not ready:
242
- st.warning(
243
- "Precomputed validation caches are incomplete or missing. "
244
- "Publish `latent_umap.pkl` and `df_features.parquet` under `streamlit_hf/cache/`, then reload."
245
- )
246
-
247
- # --- Metrics strip ---
248
- mcols = st.columns(4)
249
- if bundle is not None:
250
- n_cells = len(bundle["umap_x"])
251
- with mcols[0]:
252
- st.metric("Validation cells", f"{n_cells:,}")
253
- with mcols[1]:
254
- st.metric("Validation ROC-AUC", f"{_VALIDATION_ROC_AUC:.2f}")
255
- else:
256
- with mcols[0]:
257
- st.metric("Validation cells", "n/a")
258
- with mcols[1]:
259
- st.metric("Validation ROC-AUC", "n/a")
260
-
261
- if df_features is not None:
262
- nf = len(df_features)
263
- n_mod = df_features["modality"].nunique() if "modality" in df_features.columns else 0
264
- with mcols[2]:
265
- st.metric("Ranked features", f"{nf:,}")
266
- with mcols[3]:
267
- st.metric("Modalities", str(n_mod) if n_mod else "n/a")
268
- else:
269
- with mcols[2]:
270
- st.metric("Ranked features", "n/a")
271
- with mcols[3]:
272
- st.metric("Modalities", "n/a")
273
-
274
- # --- Workspace cards (directly under metrics); hidden spans pair with CSS for per-card colours ---
275
- _NAV_SLOT = '<span id="ff-nav-slot-{}" class="ff-nav-slot-marker" aria-hidden="true"></span>'
276
-
277
- # Inject per-card colour rules here (rather than in lib.ui) so Streamlit hot-reload picks up
278
- # tweaks without needing to reimport the cached lib module.
279
- st.markdown(
280
- """
281
- <style>
282
  /*
283
  * Home workspace nav cards (Streamlit 1.56+).
284
  * Marker row: take it out of normal flow so it cannot reserve vertical space (fixes top gap).
@@ -328,7 +302,6 @@ section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-
328
  margin-bottom: 0 !important;
329
  padding-top: 0 !important;
330
  padding-bottom: 0 !important;
331
- /* Subtitle flush with icon / link row (starts under the icon, not under the title text) */
332
  padding-left: 0 !important;
333
  box-sizing: border-box !important;
334
  }
@@ -343,15 +316,12 @@ section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-
343
  section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-testid="stElementContainer"] span[id^="ff-nav-slot-"]) [data-testid="stCaptionContainer"] p {
344
  margin-bottom: 0 !important;
345
  }
346
- /* Row of four columns: drop default block margin below the nav cards */
347
  section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has(span#ff-nav-slot-1):has(span#ff-nav-slot-4) {
348
  margin-bottom: 0 !important;
349
  }
350
- /* Each column’s outer vertical block often keeps trailing margin */
351
  section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has(span#ff-nav-slot-1):has(span#ff-nav-slot-4) > div[data-testid="stVerticalBlock"] {
352
  margin-bottom: 0 !important;
353
  }
354
- /* Fine dot lattice on a flat tinted base (no banded multi-stop gradients) */
355
  section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-testid="stElementContainer"] span#ff-nav-slot-1) {
356
  background-color: #f1f3fa !important;
357
  background-image: radial-gradient(rgba(67, 56, 202, 0.07) 0.9px, transparent 1px) !important;
@@ -416,6 +386,73 @@ section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-
416
  """,
417
  unsafe_allow_html=True,
418
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  c1, c2, c3, c4 = st.columns(4, gap="small")
420
  with c1:
421
  with st.container(border=True):
 
55
  )
56
 
57
  _EXPERIMENTAL_SYSTEM_MD = f"""
58
+ Mouse embryonic fibroblasts (**MEFs**) were reprogrammed toward induced endoderm progenitors (**iEPs**) **in vitro** through *Foxa1* and *Hnf4a* induction.
59
 
60
  This process produces **mixed outcomes**: some cells successfully reach the **iEP fate**, whereas others diverge into **off-target** trajectories and stall in **dead-end states**.
61
 
 
193
  ui.inject_app_styles()
194
  ui.inject_home_landing_styles()
195
 
196
+ # Home-only layout/CSS (injected once up-front so nothing sits between metrics row and nav cards).
197
  st.markdown(
198
  """
199
  <style>
 
203
  section[data-testid="stMain"] div[data-testid="stVerticalBlockBorderWrapper"]:has(iframe) > div {
204
  overflow: visible !important;
205
  }
206
+ /*
207
+ * Home metrics strip (four st.metric above nav cards): centre each metric in its column.
208
+ * Scope with :not(:has([id^="ff-nav-slot-"])) so the nav-card row (which also uses 4 columns) is excluded.
209
+ */
210
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) > div[data-testid="stVerticalBlock"] > div[data-testid="stElementContainer"] {
211
+ display: flex !important;
212
+ justify-content: center !important;
213
+ width: 100% !important;
214
+ }
215
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) [data-testid="stMetric"] {
216
+ width: auto !important;
217
+ max-width: 100% !important;
218
+ align-items: center !important;
219
+ text-align: center !important;
220
+ }
221
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) [data-testid="stMetricLabel"] {
222
+ display: flex !important;
223
+ justify-content: center !important;
224
+ width: 100% !important;
225
+ grid-template-columns: unset !important;
226
+ }
227
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) [data-testid="stMetricValue"] {
228
+ text-align: center !important;
229
+ width: 100% !important;
230
+ }
231
+ /* Close vertical gap between metrics row and nav cards (Streamlit block margins) */
232
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) {
233
+ margin-bottom: 0 !important;
234
+ }
235
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) > div[data-testid="stVerticalBlock"] {
236
+ margin-bottom: 0 !important;
237
+ }
238
+ section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) [data-testid="stMetric"] {
239
+ margin-bottom: 0 !important;
240
+ }
241
+ section[data-testid="stMain"] div[data-testid="stVerticalBlock"] > div[data-testid="stElementContainer"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) {
242
+ margin-bottom: 0 !important;
243
+ padding-bottom: 0 !important;
244
+ }
245
+ section[data-testid="stMain"] div[data-testid="stVerticalBlock"] > div[data-testid="stElementContainer"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"])) + div[data-testid="stElementContainer"]:has([id^="ff-nav-slot-"]) {
246
+ margin-top: 0 !important;
247
+ padding-top: 0 !important;
248
+ }
249
+ section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(
250
+ > div[data-testid="stElementContainer"]:has([data-testid="stMetric"]):not(:has([id^="ff-nav-slot-"]))
251
+ + div[data-testid="stElementContainer"]:has([id^="ff-nav-slot-"])
252
+ ) {
253
+ gap: 0 !important;
254
+ row-gap: 0 !important;
255
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  /*
257
  * Home workspace nav cards (Streamlit 1.56+).
258
  * Marker row: take it out of normal flow so it cannot reserve vertical space (fixes top gap).
 
302
  margin-bottom: 0 !important;
303
  padding-top: 0 !important;
304
  padding-bottom: 0 !important;
 
305
  padding-left: 0 !important;
306
  box-sizing: border-box !important;
307
  }
 
316
  section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-testid="stElementContainer"] span[id^="ff-nav-slot-"]) [data-testid="stCaptionContainer"] p {
317
  margin-bottom: 0 !important;
318
  }
 
319
  section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has(span#ff-nav-slot-1):has(span#ff-nav-slot-4) {
320
  margin-bottom: 0 !important;
321
  }
 
322
  section[data-testid="stMain"] div[data-testid="stHorizontalBlock"]:has(span#ff-nav-slot-1):has(span#ff-nav-slot-4) > div[data-testid="stVerticalBlock"] {
323
  margin-bottom: 0 !important;
324
  }
 
325
  section[data-testid="stMain"] div[data-testid="stVerticalBlock"]:has(> div[data-testid="stElementContainer"] span#ff-nav-slot-1) {
326
  background-color: #f1f3fa !important;
327
  background-image: radial-gradient(rgba(67, 56, 202, 0.07) 0.9px, transparent 1px) !important;
 
386
  """,
387
  unsafe_allow_html=True,
388
  )
389
+
390
+ st.markdown(
391
+ f"""<div class="ff-hero"><div class="ff-hero-inner"><div class="ff-hero-text">
392
+ <div class="ff-hero-title-row">
393
+ <span class="ff-hero-emoji" aria-hidden="true">{_HERO_EMOJI}</span>
394
+ <h1>{html.escape(_APP_NAME)}</h1>
395
+ </div>
396
+ <p class="ff-hero-sub">{html.escape(_APP_SUBTITLE)}</p>
397
+ </div></div></div>""",
398
+ unsafe_allow_html=True,
399
+ )
400
+
401
+ with st.container(border=True):
402
+ # Wider text column → fewer wrapped lines; tighter gap; center figure vs text when heights differ.
403
+ try:
404
+ fig_col, text_col = st.columns([0.33, 0.67], gap="medium", vertical_alignment="center")
405
+ except TypeError:
406
+ fig_col, text_col = st.columns([0.33, 0.67], gap="medium")
407
+ with fig_col:
408
+ if _EXPERIMENT_SVG.is_file():
409
+ _render_experiment_schematic(_EXPERIMENT_FIGURE_WIDTH_PX)
410
+ else:
411
+ st.caption("Experimental schematic (`static/experiment.svg`) is missing.")
412
+ with text_col:
413
+ st.markdown(_EXPERIMENTAL_SYSTEM_MD)
414
+
415
+ bundle = io.load_latent_bundle()
416
+ df_features = io.load_df_features()
417
+ samples = io.load_samples_df()
418
+ ready = _cache_ok()
419
+
420
+ if not ready:
421
+ st.warning(
422
+ "Precomputed validation caches are incomplete or missing. "
423
+ "Publish `latent_umap.pkl` and `df_features.parquet` under `streamlit_hf/cache/`, then reload."
424
+ )
425
+
426
+ # --- Metrics strip ---
427
+ mcols = st.columns(4)
428
+ if bundle is not None:
429
+ n_cells = len(bundle["umap_x"])
430
+ with mcols[0]:
431
+ st.metric("Validation cells", f"{n_cells:,}")
432
+ with mcols[1]:
433
+ st.metric("Validation ROC-AUC", f"{_VALIDATION_ROC_AUC:.2f}")
434
+ else:
435
+ with mcols[0]:
436
+ st.metric("Validation cells", "n/a")
437
+ with mcols[1]:
438
+ st.metric("Validation ROC-AUC", "n/a")
439
+
440
+ if df_features is not None:
441
+ nf = len(df_features)
442
+ n_mod = df_features["modality"].nunique() if "modality" in df_features.columns else 0
443
+ with mcols[2]:
444
+ st.metric("Ranked features", f"{nf:,}")
445
+ with mcols[3]:
446
+ st.metric("Modalities", str(n_mod) if n_mod else "n/a")
447
+ else:
448
+ with mcols[2]:
449
+ st.metric("Ranked features", "n/a")
450
+ with mcols[3]:
451
+ st.metric("Modalities", "n/a")
452
+
453
+ # --- Workspace cards (directly under metrics); styles injected above with other home CSS ---
454
+ _NAV_SLOT = '<span id="ff-nav-slot-{}" class="ff-nav-slot-marker" aria-hidden="true"></span>'
455
+
456
  c1, c2, c3, c4 = st.columns(4, gap="small")
457
  with c1:
458
  with st.container(border=True):
streamlit_hf/static/experiment.svg CHANGED