zmap-tools 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zmap-tools
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: API for working with ZMAP (Zebrafish Multi-Atlas Project)
5
5
  Author-email: Daniel Wagner <Daniel.Wagner@ucsf.edu>
6
6
  License: BSD 3-Clause License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "zmap-tools"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "API for working with ZMAP (Zebrafish Multi-Atlas Project)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -962,7 +962,7 @@ def predict_labels_kNN(
962
962
  )
963
963
 
964
964
  # compact digest to validate cache
965
- _mask_digest = [int(n_ref_keep), int(np.sum(np.flatnonzero(ref_keep_mask.to_numpy()) % 1048573))]
965
+ _mask_digest = [str(int(n_ref_keep)), str(int(np.sum(np.flatnonzero(ref_keep_mask.to_numpy()) % 1048573)))]
966
966
 
967
967
  # filtered reference arrays
968
968
  X_ref_all = adata_ref.obsm[ref_basis]
@@ -1101,7 +1101,7 @@ def predict_labels_kNN(
1101
1101
 
1102
1102
  predicted_labels = sorted_classes[np.argmax(probabilities_sorted, axis=1)]
1103
1103
  predicted_labels = predicted_labels.astype(object)
1104
- predicted_labels[~has_votes] = pd.NA
1104
+ predicted_labels[~has_votes] = np.nan
1105
1105
 
1106
1106
  # ---------- outputs ----------
1107
1107
  if omit_labels:
@@ -1224,7 +1224,7 @@ def predict_labels_kNN(
1224
1224
  adata_query.obs[col_reject] = ~accept
1225
1225
 
1226
1226
  # Mask rejected predictions
1227
- adata_query.obs.loc[~accept, col_main] = pd.NA
1227
+ adata_query.obs.loc[~accept, col_main] = np.nan
1228
1228
 
1229
1229
  n_total = len(accept)
1230
1230
  n_accept = int(accept.sum())
@@ -1285,7 +1285,7 @@ def predict_labels_kNN(
1285
1285
  rare_labels = label_counts[label_counts < min_cells_per_label].index
1286
1286
  if len(rare_labels) > 0:
1287
1287
  adata_query.obs[col_rareflag] = adata_query.obs[col_main].isin(rare_labels)
1288
- adata_query.obs.loc[adata_query.obs[col_rareflag], col_main] = pd.NA
1288
+ adata_query.obs.loc[adata_query.obs[col_rareflag], col_main] = np.nan
1289
1289
  adata_query.uns.setdefault('zmap_labels', {}).setdefault(space, {})
1290
1290
  adata_query.uns['zmap_labels'][space]['Rare Labels'] = list(rare_labels)
1291
1291
  _zlog(f"Filtered {len(rare_labels)} rare labels: {list(rare_labels[:10])}{'...' if len(rare_labels) > 10 else ''}")
@@ -1671,8 +1671,8 @@ def predict_labels_tissue_kNN(
1671
1671
  )
1672
1672
 
1673
1673
  mask_digest = [
1674
- int(n_ref_keep),
1675
- int(np.sum(np.flatnonzero(ref_keep_mask.to_numpy()) % 1048573)),
1674
+ str(int(n_ref_keep)),
1675
+ str(int(np.sum(np.flatnonzero(ref_keep_mask.to_numpy()) % 1048573))),
1676
1676
  ]
1677
1677
 
1678
1678
  p_thresh_use = p_thresh
@@ -2061,6 +2061,8 @@ def summarize_knn_run(adata_query, label_key):
2061
2061
  ("pct_assigned", cov.get("pct_assigned")),
2062
2062
  ], columns=["Key", "Value"])
2063
2063
 
2064
+ df["Value"] = df["Value"].astype(str)
2065
+
2064
2066
  return df
2065
2067
 
2066
2068
 
@@ -2305,6 +2307,11 @@ def build_cell_annotations_table(
2305
2307
  df.index.name = "cell_id"
2306
2308
  df = df.reset_index()
2307
2309
 
2310
+ # Ensure object columns are pure str (np.nan in object dtype is not h5ad-serializable in uns)
2311
+ for col in df.columns:
2312
+ if df[col].dtype == object:
2313
+ df[col] = df[col].fillna("").astype(str)
2314
+
2308
2315
  if save_csv:
2309
2316
  os.makedirs(output_dir, exist_ok=True)
2310
2317
  out_path = os.path.join(output_dir, f"{label_space}_cell_annotations.csv")
@@ -2573,9 +2580,11 @@ def plot_embedding_with_ondata_labels(
2573
2580
  figsize: tuple[float, float] = (6, 6),
2574
2581
  dpi: int = 200,
2575
2582
 
2576
- # ---- point/legend style ----
2583
+ # ---- point style ----
2577
2584
  ref_size: float = 2,
2585
+ ref_alpha: float = 0.3,
2578
2586
  test_size: float = 2,
2587
+ test_alpha: float = 1.0,
2579
2588
  cmap: str = "jet",
2580
2589
  frameon: bool = False,
2581
2590
  sort_order: bool = True,
@@ -2583,6 +2592,9 @@ def plot_embedding_with_ondata_labels(
2583
2592
  legend_fontsize: float = 5,
2584
2593
  legend_fontweight: str = "normal",
2585
2594
 
2595
+ # ---- label visibility ----
2596
+ show_labels: bool = True,
2597
+
2586
2598
  # ---- label styling ----
2587
2599
  recolor_labels_from_palette: bool = True,
2588
2600
  text_stroke_width: float = 1.0,
@@ -2653,15 +2665,29 @@ def plot_embedding_with_ondata_labels(
2653
2665
  Figure size in inches ``(width, height)``.
2654
2666
  dpi : int, default ``200``
2655
2667
  Figure resolution.
2656
- ref_size, test_size : float, default ``2``
2657
- Scatter point sizes for reference background and query cells respectively.
2668
+ ref_size : float, default ``2``
2669
+ Scatter point size for reference background cells.
2670
+ ref_alpha : float, default ``0.3``
2671
+ Opacity of reference background points. Lower values push the
2672
+ reference further into the background.
2673
+ test_size : float, default ``2``
2674
+ Scatter point size for query (projected) cells.
2675
+ test_alpha : float, default ``1.0``
2676
+ Opacity of query overlay points.
2658
2677
  cmap : str, default ``"jet"``
2659
2678
  Colormap used for the reference background scatter.
2660
2679
  legend_loc : str, default ``"on data"``
2661
2680
  Where to place the category legend. ``"on data"`` draws labels directly
2662
2681
  at centroid positions; other values follow matplotlib legend conventions.
2682
+ Ignored when ``show_labels=False`` (forced to ``"none"``).
2663
2683
  legend_fontsize, legend_fontweight : float and str, default ``5`` and ``"normal"``
2664
2684
  Font size and weight for on-data legend labels.
2685
+ show_labels : bool, default ``True``
2686
+ If ``True``, draw on-data text labels at category centroids with
2687
+ ``adjustText`` repositioning and optional arrow connectors. If
2688
+ ``False``, suppress all text labels and arrows — only the colored
2689
+ scatter is shown, which is useful for clean figures or when the
2690
+ number of categories is too large for readable labels.
2665
2691
  replace_underscores : bool, default ``True``
2666
2692
  Replace underscores in label strings with line breaks for cleaner
2667
2693
  on-data annotation.
@@ -2669,17 +2695,23 @@ def plot_embedding_with_ondata_labels(
2669
2695
  ``(x_expand, y_expand)`` passed to ``adjustText`` for label placement.
2670
2696
  match_arrow_color_to_text : bool, default ``True``
2671
2697
  Color annotation arrows to match their corresponding text label.
2698
+ ref_kwargs : dict or None, default ``None``
2699
+ Extra keyword arguments forwarded to the reference ``sc.pl.embedding``
2700
+ call. Explicit ``ref_alpha`` takes priority over ``alpha`` in this dict.
2701
+ test_kwargs : dict or None, default ``None``
2702
+ Extra keyword arguments forwarded to the query ``sc.pl.embedding``
2703
+ call. Explicit ``test_alpha`` takes priority over ``alpha`` in this dict.
2672
2704
  show : bool, default ``False``
2673
2705
  Call ``plt.show()`` after rendering.
2674
2706
  save : bool, default ``True``
2675
- Save the figure as PNG and PDF to ``./zmap/predict/``.
2707
+ Save the figure as PNG and PDF to ``output_dir``.
2676
2708
  return_ax : bool, default ``False``
2677
2709
  Return the main ``matplotlib.axes.Axes`` object.
2678
2710
 
2679
2711
  Returns
2680
2712
  -------
2681
- matplotlib.axes.Axes or None
2682
- The main axes when ``return_ax=True``, otherwise ``None``.
2713
+ tuple or None
2714
+ ``(fig, ax_umap, ax_strip)`` when ``return_ax=True``, otherwise ``None``.
2683
2715
  """
2684
2716
  # ---- prepare test AnnData (drop NAs on requested key, cast to categorical) ----
2685
2717
  if filter_na:
@@ -2745,6 +2777,13 @@ def plot_embedding_with_ondata_labels(
2745
2777
  test_kwargs = {} if test_kwargs is None else dict(test_kwargs)
2746
2778
  time_strip_kwargs = {} if time_strip_kwargs is None else dict(time_strip_kwargs)
2747
2779
 
2780
+ # ---- Inject alpha into kwargs (explicit params take priority) ----
2781
+ ref_kwargs.setdefault("alpha", ref_alpha)
2782
+ test_kwargs.setdefault("alpha", test_alpha)
2783
+
2784
+ # ---- Resolve legend_loc: suppress labels when show_labels=False ----
2785
+ legend_loc_use = legend_loc if show_labels else "none"
2786
+
2748
2787
  # ---- Check if we actually have a time vector ----
2749
2788
  has_time = (
2750
2789
  show_time_strip and
@@ -2793,7 +2832,7 @@ def plot_embedding_with_ondata_labels(
2793
2832
  basis=basis,
2794
2833
  sort_order=sort_order,
2795
2834
  size=test_size,
2796
- legend_loc=legend_loc,
2835
+ legend_loc=legend_loc_use,
2797
2836
  legend_fontweight=legend_fontweight,
2798
2837
  ax=ax,
2799
2838
  show=False,
@@ -2802,41 +2841,42 @@ def plot_embedding_with_ondata_labels(
2802
2841
  **test_kwargs,
2803
2842
  )
2804
2843
 
2805
- # --- obtain existing on-data labels ---
2806
- texts = [t for t in ax.texts]
2844
+ # --- on-data label styling (only when show_labels=True) ---
2845
+ if show_labels:
2846
+ texts = [t for t in ax.texts]
2807
2847
 
2808
- # --- recolor existing on-data text labels by palette ---
2809
- if recolor_labels_from_palette:
2810
- for t in texts:
2811
- label = t.get_text()
2812
- if label in palette:
2813
- t.set_color(palette[label])
2814
-
2815
- # --- add white border to text labels ---
2816
- for t in texts:
2817
- t.set_path_effects([pe.withStroke(linewidth=text_stroke_width, foreground='white')])
2848
+ # --- recolor existing on-data text labels by palette ---
2849
+ if recolor_labels_from_palette:
2850
+ for t in texts:
2851
+ label = t.get_text()
2852
+ if label in palette:
2853
+ t.set_color(palette[label])
2818
2854
 
2819
- # --- replace underscores with line breaks ---
2820
- if replace_underscores:
2855
+ # --- add white border to text labels ---
2821
2856
  for t in texts:
2822
- t.set_text(t.get_text().replace(linebreak_from, linebreak_to))
2823
-
2824
- # --- adjust label positions with slim arrows ---
2825
- if len(texts) > 0:
2826
- adjust_text(
2827
- texts,
2828
- ax=ax,
2829
- expand=adjust_expand,
2830
- arrowprops=arrowprops,
2831
- min_arrow_len=min_arrow_len,
2832
- )
2857
+ t.set_path_effects([pe.withStroke(linewidth=text_stroke_width, foreground='white')])
2858
+
2859
+ # --- replace underscores with line breaks ---
2860
+ if replace_underscores:
2861
+ for t in texts:
2862
+ t.set_text(t.get_text().replace(linebreak_from, linebreak_to))
2863
+
2864
+ # --- adjust label positions with slim arrows ---
2865
+ if len(texts) > 0:
2866
+ adjust_text(
2867
+ texts,
2868
+ ax=ax,
2869
+ expand=adjust_expand,
2870
+ arrowprops=arrowprops,
2871
+ min_arrow_len=min_arrow_len,
2872
+ )
2833
2873
 
2834
- # --- match arrow color to label color ---
2835
- if match_arrow_color_to_text and len(texts) > 0:
2836
- arrows = [p for p in ax.patches if isinstance(p, FancyArrowPatch)]
2837
- for t, a in zip(texts, arrows[-len(texts):]):
2838
- a.set_color(t.get_color())
2839
- a.set_alpha(arrow_alpha)
2874
+ # --- match arrow color to label color ---
2875
+ if match_arrow_color_to_text and len(texts) > 0:
2876
+ arrows = [p for p in ax.patches if isinstance(p, FancyArrowPatch)]
2877
+ for t, a in zip(texts, arrows[-len(texts):]):
2878
+ a.set_color(t.get_color())
2879
+ a.set_alpha(arrow_alpha)
2840
2880
 
2841
2881
  # ---- time distribution strip on the right (rotated) ----
2842
2882
  if has_time and ax_strip is not None:
@@ -2920,7 +2960,6 @@ def plot_embedding_with_ondata_labels(
2920
2960
  return None
2921
2961
 
2922
2962
 
2923
-
2924
2963
  # ================================================================
2925
2964
  # 6. Overlap matrix & plot
2926
2965
  # ================================================================
@@ -4186,8 +4225,14 @@ def plot_embedding(
4186
4225
  label_space: str | None = None,
4187
4226
  *,
4188
4227
  save: bool = False,
4228
+ show_labels: bool = True,
4229
+ ref_size: float = 2,
4230
+ ref_alpha: float = 0.3,
4231
+ test_size: float = 2,
4232
+ test_alpha: float = 1.0,
4233
+ return_ax: bool = False,
4189
4234
  **kwargs,
4190
- ) -> None:
4235
+ ) -> tuple | None:
4191
4236
  """
4192
4237
  Re-plot the UMAP overlay with on-data labels and time strip.
4193
4238
 
@@ -4202,8 +4247,26 @@ def plot_embedding(
4202
4247
  Label namespace. When ``None``, uses the most recent run.
4203
4248
  save : bool, default ``False``
4204
4249
  Save the figure to the run's output directory.
4250
+ show_labels : bool, default ``True``
4251
+ If ``True``, draw on-data text labels at category centroids.
4252
+ If ``False``, suppress all text labels and arrows.
4253
+ ref_size : float, default ``2``
4254
+ Scatter point size for reference background cells.
4255
+ ref_alpha : float, default ``0.3``
4256
+ Opacity of reference background points.
4257
+ test_size : float, default ``2``
4258
+ Scatter point size for query (projected) cells.
4259
+ test_alpha : float, default ``1.0``
4260
+ Opacity of query overlay points.
4261
+ return_ax : bool, default ``False``
4262
+ Return ``(fig, ax_umap, ax_strip)`` instead of ``None``.
4205
4263
  **kwargs
4206
4264
  Extra keyword arguments forwarded to ``plot_embedding_with_ondata_labels``.
4265
+
4266
+ Returns
4267
+ -------
4268
+ tuple or None
4269
+ ``(fig, ax_umap, ax_strip)`` when ``return_ax=True``, otherwise ``None``.
4207
4270
  """
4208
4271
  label_space, config = _resolve_config(adata_query, label_space)
4209
4272
  space_store = adata_query.uns.get("zmap_labels", {}).get(label_space, {})
@@ -4226,13 +4289,19 @@ def plot_embedding(
4226
4289
  time_key = config.get("time_col", "ZMAP_time_id_predicted")
4227
4290
  space_dir = config.get("output_dir", os.path.join("zmap_predict", label_space))
4228
4291
 
4229
- plot_embedding_with_ondata_labels(
4292
+ return plot_embedding_with_ondata_labels(
4230
4293
  adata_ref_mini,
4231
4294
  adata_query,
4232
4295
  color_key=color_key,
4233
4296
  time_key=time_key,
4234
4297
  show=True,
4235
4298
  save=save,
4299
+ show_labels=show_labels,
4300
+ ref_size=ref_size,
4301
+ ref_alpha=ref_alpha,
4302
+ test_size=test_size,
4303
+ test_alpha=test_alpha,
4304
+ return_ax=return_ax,
4236
4305
  output_dir=space_dir,
4237
4306
  **kwargs,
4238
4307
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zmap-tools
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: API for working with ZMAP (Zebrafish Multi-Atlas Project)
5
5
  Author-email: Daniel Wagner <Daniel.Wagner@ucsf.edu>
6
6
  License: BSD 3-Clause License
File without changes
File without changes
File without changes