cellestial 0.48.0__tar.gz → 0.48.2__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.
- {cellestial-0.48.0 → cellestial-0.48.2}/PKG-INFO +1 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/frames/operations.py +3 -5
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/dimensional.py +4 -6
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/dotplot.py +5 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/heatmap.py +10 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/stacked_violin.py +5 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/quick/elbow.py +4 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/spatial/spatial.py +9 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/__init__.py +2 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/dendrogram.py +9 -10
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/utilities.py +92 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/pyproject.toml +1 -1
- {cellestial-0.48.0 → cellestial-0.48.2}/LICENSE +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/README.md +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/_version.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/datasets/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/datasets/datasets.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/frames/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/frames/build.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/_deferred.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/arrow.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/bracket.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/ondata_legend.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/outline.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/stream.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/layers/utilities.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/base/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/base/base.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/basic/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/basic/bar.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/basic/scatter.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/common/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/common/xyplot.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/common/xyplots.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/distribution.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/distributions.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/subdimensional.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/core/subdimensionals.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/differential/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/differential/markers.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/differential/volcano.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/_key_groups.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/heatmap/_rank_genes_groups.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/quick/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/quick/highest.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/single/quick/ridge.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/spatial/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/spatial/_components.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/spatial/spatials.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/themes/__init__.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/themes/_distributions.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/themes/_heatmaps.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/themes/_scatters.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/colors.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/errors.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/operations.py +0 -0
- {cellestial-0.48.0 → cellestial-0.48.2}/cellestial/util/save.py +0 -0
|
@@ -50,15 +50,13 @@ def _pca_variance_frame(
|
|
|
50
50
|
n_pcs: int | None = None,
|
|
51
51
|
component_column: str = "Principal Component",
|
|
52
52
|
variance_column: str = "Variance Ratio",
|
|
53
|
+
use_key: str = "pca",
|
|
53
54
|
) -> DataFrame:
|
|
54
55
|
"""Get PCA variance ratio per principal component as a polars DataFrame."""
|
|
55
56
|
if isinstance(data, AnnData):
|
|
56
|
-
pca_uns = data.uns.get(
|
|
57
|
+
pca_uns = data.uns.get(use_key)
|
|
57
58
|
if pca_uns is None or "variance_ratio" not in pca_uns:
|
|
58
|
-
msg =
|
|
59
|
-
"PCA variance ratio is not available on this data. "
|
|
60
|
-
"Run PCA first (e.g., `sc.tl.pca(data)`)."
|
|
61
|
-
)
|
|
59
|
+
msg = f"PCA variance ratio not found under `{use_key}`. Run PCA first."
|
|
62
60
|
raise ValueError(msg)
|
|
63
61
|
variance_ratio = np.asarray(pca_uns["variance_ratio"]).ravel()
|
|
64
62
|
n_available = variance_ratio.size
|
|
@@ -24,6 +24,7 @@ from cellestial.themes import _THEME_DIMENSION
|
|
|
24
24
|
from cellestial.util import (
|
|
25
25
|
_color_gradient,
|
|
26
26
|
_is_variable_key,
|
|
27
|
+
_resolve_embedding_key,
|
|
27
28
|
_resolve_tooltips,
|
|
28
29
|
_validate_tooltips,
|
|
29
30
|
_warn,
|
|
@@ -228,12 +229,9 @@ def dimensional(
|
|
|
228
229
|
if len(xy) != 2:
|
|
229
230
|
msg = f"xy MUST be of length 2, (len(xy)=={len(xy)})"
|
|
230
231
|
raise KeyError(msg)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
else:
|
|
235
|
-
x = f"{use_key}{xy[0]}" # e.g. X_UMAP1
|
|
236
|
-
y = f"{use_key}{xy[1]}" # e.g. X_UMAP2
|
|
232
|
+
prefix = _resolve_embedding_key(data=data, dimensions=dimensions, use_key=use_key, xy=xy)
|
|
233
|
+
x = f"{prefix}{xy[0]}" # e.g. X_UMAP1
|
|
234
|
+
y = f"{prefix}{xy[1]}" # e.g. X_UMAP2
|
|
237
235
|
|
|
238
236
|
# HANDLE: variable_keys
|
|
239
237
|
if variable_keys is None:
|
|
@@ -69,6 +69,7 @@ def dotplot(
|
|
|
69
69
|
dendrogram: bool = False,
|
|
70
70
|
dendrogram_color: str = "black",
|
|
71
71
|
dendrogram_size: float = 0.5,
|
|
72
|
+
dendrogram_key: str | None = None,
|
|
72
73
|
dendrogram_kwargs: dict | None = None,
|
|
73
74
|
rectangle_size: float = 0.8,
|
|
74
75
|
rectangle_color: str = "#3f3f3f",
|
|
@@ -144,6 +145,9 @@ def dotplot(
|
|
|
144
145
|
Color of the dendrogram segments.
|
|
145
146
|
dendrogram_size : float, default=0.5
|
|
146
147
|
Size (thickness) of the dendrogram segments.
|
|
148
|
+
dendrogram_key : str | None, default=None
|
|
149
|
+
Specific key holding the precomputed dendrogram.
|
|
150
|
+
By default, `dendrogram_{group_by}` is used.
|
|
147
151
|
dendrogram_kwargs : dict | None, default=None
|
|
148
152
|
Additional parameters to pass to the dendrogram geom_segment.
|
|
149
153
|
rectangle_size : float, default=0.8
|
|
@@ -339,7 +343,7 @@ def dotplot(
|
|
|
339
343
|
|
|
340
344
|
# DETERMINE: y order of groups
|
|
341
345
|
if dendrogram:
|
|
342
|
-
y_order_groups, paths = _get_dendrogram(data, group_by)
|
|
346
|
+
y_order_groups, paths = _get_dendrogram(data, group_by, use_key=dendrogram_key)
|
|
343
347
|
else:
|
|
344
348
|
y_order_groups = (
|
|
345
349
|
frame.select(group_by).unique(maintain_order=True)[group_by].cast(pl.String).to_list()
|
|
@@ -209,6 +209,7 @@ def heatmap(
|
|
|
209
209
|
group_lines_size: float = 0.6,
|
|
210
210
|
dendrogram_color: str = "black",
|
|
211
211
|
dendrogram_size: float = 0.5,
|
|
212
|
+
dendrogram_key: str | None = None,
|
|
212
213
|
group_lines_kwargs: dict | None = None,
|
|
213
214
|
dendrogram_kwargs: dict | None = None,
|
|
214
215
|
key_labels: bool = True,
|
|
@@ -284,6 +285,9 @@ def heatmap(
|
|
|
284
285
|
Color of the dendrogram segments.
|
|
285
286
|
dendrogram_size : float, default=0.5
|
|
286
287
|
Size (thickness) of the dendrogram segments.
|
|
288
|
+
dendrogram_key : str | None, default=None
|
|
289
|
+
Specific key holding the precomputed dendrogram.
|
|
290
|
+
By default, `dendrogram_{group_by}` is used.
|
|
287
291
|
group_lines_kwargs : dict | None, default=None
|
|
288
292
|
Additional parameters to pass to the group separator lines geom_segment.
|
|
289
293
|
dendrogram_kwargs : dict | None, default=None
|
|
@@ -499,7 +503,7 @@ def heatmap(
|
|
|
499
503
|
|
|
500
504
|
# DETERMINE: y order of groups
|
|
501
505
|
if dendrogram:
|
|
502
|
-
y_order_groups, paths = _get_dendrogram(data, group_by)
|
|
506
|
+
y_order_groups, paths = _get_dendrogram(data, group_by, use_key=dendrogram_key)
|
|
503
507
|
else:
|
|
504
508
|
y_order_groups = (
|
|
505
509
|
frame.select(group_by).unique(maintain_order=True)[group_by].cast(pl.String).to_list()
|
|
@@ -662,6 +666,7 @@ def matrixplot(
|
|
|
662
666
|
group_lines_size: float = 0.6,
|
|
663
667
|
dendrogram_color: str = "black",
|
|
664
668
|
dendrogram_size: float = 0.5,
|
|
669
|
+
dendrogram_key: str | None = None,
|
|
665
670
|
group_lines_kwargs: dict | None = None,
|
|
666
671
|
dendrogram_kwargs: dict | None = None,
|
|
667
672
|
key_labels: bool = True,
|
|
@@ -731,6 +736,9 @@ def matrixplot(
|
|
|
731
736
|
Color of the dendrogram segments.
|
|
732
737
|
dendrogram_size : float, default=0.5
|
|
733
738
|
Size (thickness) of the dendrogram segments.
|
|
739
|
+
dendrogram_key : str | None, default=None
|
|
740
|
+
Specific key holding the precomputed dendrogram.
|
|
741
|
+
By default, `dendrogram_{group_by}` is used.
|
|
734
742
|
group_lines_kwargs : dict | None, default=None
|
|
735
743
|
Additional parameters to pass to the group separator lines geom_segment.
|
|
736
744
|
dendrogram_kwargs : dict | None, default=None
|
|
@@ -842,6 +850,7 @@ def matrixplot(
|
|
|
842
850
|
group_lines_size=group_lines_size,
|
|
843
851
|
dendrogram_color=dendrogram_color,
|
|
844
852
|
dendrogram_size=dendrogram_size,
|
|
853
|
+
dendrogram_key=dendrogram_key,
|
|
845
854
|
group_lines_kwargs=group_lines_kwargs,
|
|
846
855
|
dendrogram_kwargs=dendrogram_kwargs,
|
|
847
856
|
value_column=value_column,
|
|
@@ -199,6 +199,7 @@ def stacked_violin(
|
|
|
199
199
|
dendrogram: bool = False,
|
|
200
200
|
dendrogram_color: str = "black",
|
|
201
201
|
dendrogram_size: float = 0.5,
|
|
202
|
+
dendrogram_key: str | None = None,
|
|
202
203
|
dendrogram_kwargs: dict | None = None,
|
|
203
204
|
rectangle: bool = True,
|
|
204
205
|
rectangle_size: float = 0.8,
|
|
@@ -292,6 +293,9 @@ def stacked_violin(
|
|
|
292
293
|
Color of the dendrogram segments.
|
|
293
294
|
dendrogram_size : float, default=0.5
|
|
294
295
|
Size (thickness) of the dendrogram segments.
|
|
296
|
+
dendrogram_key : str | None, default=None
|
|
297
|
+
Specific key holding the precomputed dendrogram.
|
|
298
|
+
By default, `dendrogram_{group_by}` is used.
|
|
295
299
|
dendrogram_kwargs : dict | None, default=None
|
|
296
300
|
Additional parameters to pass to the dendrogram geom_path.
|
|
297
301
|
rectangle : bool, default=True
|
|
@@ -456,7 +460,7 @@ def stacked_violin(
|
|
|
456
460
|
|
|
457
461
|
# DETERMINE: y order of groups (dendrogram or first-seen order)
|
|
458
462
|
if dendrogram:
|
|
459
|
-
y_order_groups, paths = _get_dendrogram(data, group_by)
|
|
463
|
+
y_order_groups, paths = _get_dendrogram(data, group_by, use_key=dendrogram_key)
|
|
460
464
|
else:
|
|
461
465
|
y_order_groups = (
|
|
462
466
|
frame.select(group_by).unique(maintain_order=True)[group_by].cast(pl.String).to_list()
|
|
@@ -36,6 +36,7 @@ def elbow(
|
|
|
36
36
|
label: bool = False,
|
|
37
37
|
label_size: float = 4.0,
|
|
38
38
|
label_every: int = 5,
|
|
39
|
+
pca_key: str = "pca",
|
|
39
40
|
**geom_kwargs,
|
|
40
41
|
) -> PlotSpec:
|
|
41
42
|
"""
|
|
@@ -73,6 +74,8 @@ def elbow(
|
|
|
73
74
|
label_every : int, default=5
|
|
74
75
|
Only components whose number is a multiple of this value are labeled
|
|
75
76
|
(used when `label=True`). For example, `5` labels PC5, PC10, PC15, ...
|
|
77
|
+
pca_key : str, default='pca'
|
|
78
|
+
Specific key holding the PCA results.
|
|
76
79
|
**geom_kwargs
|
|
77
80
|
Additional parameters for the `geom_point` layer.
|
|
78
81
|
For more information on geom_point parameters, see:
|
|
@@ -124,6 +127,7 @@ def elbow(
|
|
|
124
127
|
n_pcs=n_pcs,
|
|
125
128
|
component_column=component_column,
|
|
126
129
|
variance_column=variance_column,
|
|
130
|
+
use_key=pca_key,
|
|
127
131
|
)
|
|
128
132
|
|
|
129
133
|
# HANDLE: mapping
|
|
@@ -104,7 +104,15 @@ def _spatial_components(
|
|
|
104
104
|
|
|
105
105
|
library = spatial_uns[library_id]
|
|
106
106
|
scale_factors = library.get("scalefactors", {})
|
|
107
|
-
|
|
107
|
+
scalef_key = f"tissue_{image_key}_scalef"
|
|
108
|
+
scale_factor = scale_factors.get(scalef_key)
|
|
109
|
+
if scale_factor is None:
|
|
110
|
+
if image:
|
|
111
|
+
_warn(
|
|
112
|
+
f"Scale factor `{scalef_key}` missing; "
|
|
113
|
+
"spots may not align with the image."
|
|
114
|
+
)
|
|
115
|
+
scale_factor = 1.0
|
|
108
116
|
spot_coordinates = data.obsm[spatial_key] * scale_factor
|
|
109
117
|
|
|
110
118
|
image_array = None
|
|
@@ -11,6 +11,7 @@ from cellestial.util.utilities import (
|
|
|
11
11
|
_is_observation_key,
|
|
12
12
|
_is_variable_key,
|
|
13
13
|
_range_inclusive,
|
|
14
|
+
_resolve_embedding_key,
|
|
14
15
|
_resolve_tooltips,
|
|
15
16
|
_select_variable_keys,
|
|
16
17
|
_share_axis,
|
|
@@ -30,6 +31,7 @@ __all__ = [
|
|
|
30
31
|
"_is_observation_key",
|
|
31
32
|
"_is_variable_key",
|
|
32
33
|
"_range_inclusive",
|
|
34
|
+
"_resolve_embedding_key",
|
|
33
35
|
"_resolve_tooltips",
|
|
34
36
|
"_select_variable_keys",
|
|
35
37
|
"_share_axis",
|
|
@@ -4,22 +4,21 @@ import polars as pl
|
|
|
4
4
|
from anndata import AnnData
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def _get_dendrogram(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"""
|
|
7
|
+
def _get_dendrogram(
|
|
8
|
+
data: AnnData,
|
|
9
|
+
group_by: str,
|
|
10
|
+
*,
|
|
11
|
+
use_key: str | None = None,
|
|
12
|
+
) -> tuple[list[str], pl.DataFrame]:
|
|
13
|
+
"""Get or compute the dendrogram for `group_by` and extract paths."""
|
|
15
14
|
import numpy as np
|
|
16
15
|
|
|
17
16
|
if isinstance(data, AnnData):
|
|
18
|
-
key = f"dendrogram_{group_by}"
|
|
17
|
+
key = use_key if use_key is not None else f"dendrogram_{group_by}"
|
|
19
18
|
if key not in data.uns:
|
|
20
19
|
import scanpy as sc
|
|
21
20
|
|
|
22
|
-
sc.tl.dendrogram(data, groupby=group_by)
|
|
21
|
+
sc.tl.dendrogram(data, groupby=group_by, key_added=key)
|
|
23
22
|
|
|
24
23
|
dendro = data.uns[key]
|
|
25
24
|
categories_ordered = list(dendro["categories_ordered"])
|
|
@@ -24,7 +24,7 @@ from lets_plot import (
|
|
|
24
24
|
from lets_plot.plot.core import FeatureSpec
|
|
25
25
|
from lets_plot.plot.subplots import SupPlotsSpec
|
|
26
26
|
|
|
27
|
-
from cellestial.util.errors import CellestialWarning
|
|
27
|
+
from cellestial.util.errors import CellestialWarning, KeyNotFoundError, UnsupportedDataTypeError
|
|
28
28
|
|
|
29
29
|
_PACKAGE_ROOT = str(Path(__file__).parents[1])
|
|
30
30
|
|
|
@@ -532,6 +532,97 @@ def _are_variable_features(data: AnnData, keys: Sequence[str] | None) -> bool:
|
|
|
532
532
|
return result
|
|
533
533
|
|
|
534
534
|
|
|
535
|
+
def _resolve_embedding_key(
|
|
536
|
+
data: AnnData,
|
|
537
|
+
dimensions: str,
|
|
538
|
+
use_key: str | None,
|
|
539
|
+
xy: Sequence[int],
|
|
540
|
+
) -> str:
|
|
541
|
+
"""
|
|
542
|
+
Resolve the column-name prefix used to index an embedding in the built frame.
|
|
543
|
+
|
|
544
|
+
`build_frame` emits embedding columns as ``f"{KEY.upper()}{n}"``, so callers
|
|
545
|
+
compose axis names like ``X_UMAP1`` / ``X_UMAP2`` by appending the axis
|
|
546
|
+
index to the prefix returned here.
|
|
547
|
+
|
|
548
|
+
Resolution rules
|
|
549
|
+
----------------
|
|
550
|
+
1. If ``use_key`` is given, return it uppercased.
|
|
551
|
+
2. Otherwise, against ``f"X_{dimensions.upper()}"``:
|
|
552
|
+
- exact (case-insensitive) match -> return it silently.
|
|
553
|
+
- no exact, but prefix matches exist -> pick the candidate whose
|
|
554
|
+
dimensionality is sufficient for ``max(xy)`` (shortest name on ties),
|
|
555
|
+
warn the user, and suggest ``use_key`` to silence.
|
|
556
|
+
- no candidate -> raise ``KeyNotFoundError``.
|
|
557
|
+
|
|
558
|
+
Parameters
|
|
559
|
+
----------
|
|
560
|
+
data : AnnData
|
|
561
|
+
Single-cell data object providing the embedding store.
|
|
562
|
+
dimensions : str
|
|
563
|
+
Embedding family, e.g. ``"umap"``, ``"pca"``, ``"tsne"``.
|
|
564
|
+
use_key : str | None
|
|
565
|
+
Explicit embedding key. When provided, no search is performed.
|
|
566
|
+
xy : Sequence[int]
|
|
567
|
+
Axis indices requested (1-based); used to filter shape-eligible
|
|
568
|
+
candidates during fallback.
|
|
569
|
+
|
|
570
|
+
Returns
|
|
571
|
+
-------
|
|
572
|
+
str
|
|
573
|
+
Uppercase column-name prefix.
|
|
574
|
+
|
|
575
|
+
Raises
|
|
576
|
+
------
|
|
577
|
+
UnsupportedDataTypeError
|
|
578
|
+
If `data` is not a supported single-cell data object.
|
|
579
|
+
KeyNotFoundError
|
|
580
|
+
If no embedding matches the requested family.
|
|
581
|
+
"""
|
|
582
|
+
if use_key is not None:
|
|
583
|
+
return use_key.upper()
|
|
584
|
+
|
|
585
|
+
if isinstance(data, AnnData):
|
|
586
|
+
candidates = list(data.obsm.keys())
|
|
587
|
+
shapes = {key: data.obsm[key].shape[1] for key in candidates}
|
|
588
|
+
else:
|
|
589
|
+
msg = f"Unsupported data type: `{type(data)}`"
|
|
590
|
+
raise UnsupportedDataTypeError(msg)
|
|
591
|
+
|
|
592
|
+
target = f"X_{dimensions.upper()}"
|
|
593
|
+
needed = max(xy)
|
|
594
|
+
search_targets = (target, dimensions.upper()) # accept bare `UMAP` too, not only `X_UMAP`
|
|
595
|
+
|
|
596
|
+
for key in candidates:
|
|
597
|
+
if key.upper() in search_targets:
|
|
598
|
+
return key.upper()
|
|
599
|
+
|
|
600
|
+
prefix_matches = [
|
|
601
|
+
key for key in candidates
|
|
602
|
+
if any(key.upper().startswith(t) for t in search_targets)
|
|
603
|
+
]
|
|
604
|
+
if not prefix_matches:
|
|
605
|
+
msg = (
|
|
606
|
+
f"No embedding found for `dimensions='{dimensions}'`\n"
|
|
607
|
+
f"(looked for `{target}` or any key starting with it).\n"
|
|
608
|
+
f"Available embeddings: {candidates}."
|
|
609
|
+
)
|
|
610
|
+
raise KeyNotFoundError(msg)
|
|
611
|
+
|
|
612
|
+
eligible = [key for key in prefix_matches if shapes[key] >= needed]
|
|
613
|
+
pool = eligible or prefix_matches
|
|
614
|
+
chosen = sorted(pool, key=lambda key: (len(key), key))[0]
|
|
615
|
+
|
|
616
|
+
alternatives = sorted(prefix_matches)
|
|
617
|
+
_warn(
|
|
618
|
+
f"No embedding named `{target}` found; "
|
|
619
|
+
f"using `{chosen}` with (shape={shapes[chosen]})\n"
|
|
620
|
+
f"Alternatives: {alternatives}, Rest: {list(set(candidates) - set(alternatives))}.\n"
|
|
621
|
+
"Pass `use_key='...'` to use a specific key."
|
|
622
|
+
)
|
|
623
|
+
return chosen.upper()
|
|
624
|
+
|
|
625
|
+
|
|
535
626
|
def _determine_axis(
|
|
536
627
|
data: AnnData,
|
|
537
628
|
keys: str | Sequence[str],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|