cellestial 0.45.0__tar.gz → 0.46.0__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.
Files changed (62) hide show
  1. {cellestial-0.45.0 → cellestial-0.46.0}/PKG-INFO +1 -1
  2. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/dimensional.py +2 -2
  3. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/distribution.py +3 -4
  4. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/_rank_genes_groups.py +3 -4
  5. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/dotplot.py +24 -16
  6. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/heatmap.py +33 -32
  7. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/stacked_violin.py +14 -16
  8. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/spatial/spatial.py +3 -3
  9. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/__init__.py +2 -0
  10. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/errors.py +4 -0
  11. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/utilities.py +41 -0
  12. {cellestial-0.45.0 → cellestial-0.46.0}/pyproject.toml +1 -1
  13. {cellestial-0.45.0 → cellestial-0.46.0}/LICENSE +0 -0
  14. {cellestial-0.45.0 → cellestial-0.46.0}/README.md +0 -0
  15. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/__init__.py +0 -0
  16. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/_version.py +0 -0
  17. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/datasets/__init__.py +0 -0
  18. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/datasets/datasets.py +0 -0
  19. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/frames/__init__.py +0 -0
  20. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/frames/build.py +0 -0
  21. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/frames/operations.py +0 -0
  22. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/__init__.py +0 -0
  23. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/_deferred.py +0 -0
  24. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/arrow.py +0 -0
  25. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/bracket.py +0 -0
  26. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/ondata_legend.py +0 -0
  27. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/outline.py +0 -0
  28. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/stream.py +0 -0
  29. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/layers/utilities.py +0 -0
  30. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/__init__.py +0 -0
  31. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/base/__init__.py +0 -0
  32. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/base/base.py +0 -0
  33. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/basic/__init__.py +0 -0
  34. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/basic/bar.py +0 -0
  35. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/basic/scatter.py +0 -0
  36. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/common/__init__.py +0 -0
  37. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/common/xyplot.py +0 -0
  38. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/common/xyplots.py +0 -0
  39. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/__init__.py +0 -0
  40. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/distributions.py +0 -0
  41. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/subdimensional.py +0 -0
  42. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/core/subdimensionals.py +0 -0
  43. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/differential/__init__.py +0 -0
  44. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/differential/markers.py +0 -0
  45. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/differential/volcano.py +0 -0
  46. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/__init__.py +0 -0
  47. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/heatmap/_key_groups.py +0 -0
  48. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/quick/__init__.py +0 -0
  49. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/quick/elbow.py +0 -0
  50. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/quick/highest.py +0 -0
  51. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/single/quick/ridge.py +0 -0
  52. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/spatial/__init__.py +0 -0
  53. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/spatial/_components.py +0 -0
  54. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/spatial/spatials.py +0 -0
  55. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/themes/__init__.py +0 -0
  56. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/themes/_distributions.py +0 -0
  57. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/themes/_heatmaps.py +0 -0
  58. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/themes/_scatters.py +0 -0
  59. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/colors.py +0 -0
  60. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/dendrogram.py +0 -0
  61. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/operations.py +0 -0
  62. {cellestial-0.45.0 → cellestial-0.46.0}/cellestial/util/save.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellestial
3
- Version: 0.45.0
3
+ Version: 0.46.0
4
4
  Summary:
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import warnings
4
3
  from collections.abc import Sequence
5
4
  from typing import TYPE_CHECKING, Literal
6
5
 
@@ -27,6 +26,7 @@ from cellestial.util import (
27
26
  _is_variable_key,
28
27
  _resolve_tooltips,
29
28
  _validate_tooltips,
29
+ _warn,
30
30
  )
31
31
  from cellestial.util.errors import UnsupportedDataTypeError
32
32
 
@@ -335,6 +335,6 @@ def dimensional(
335
335
  )
336
336
  elif frame[key].dtype != pl.Categorical:
337
337
  msg = f"key `{key}` is not categorical, legend on data will not be added"
338
- warnings.warn(msg, stacklevel=1)
338
+ _warn(msg)
339
339
 
340
340
  return scttr
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Sequence
4
4
  from typing import TYPE_CHECKING, Any, Literal
5
- from warnings import warn
6
5
 
7
6
  import polars as pl
8
7
  from anndata import AnnData
@@ -27,6 +26,7 @@ from cellestial.util import (
27
26
  _resolve_tooltips,
28
27
  _select_variable_keys,
29
28
  _validate_tooltips,
29
+ _warn,
30
30
  )
31
31
  from cellestial.util.errors import UnsupportedDataTypeError
32
32
 
@@ -131,11 +131,10 @@ def _distribution(
131
131
  if group_by is None:
132
132
  group_by = variable_column
133
133
  elif len(keys) > 1 and group_by != variable_column:
134
- warn(
134
+ _warn(
135
135
  f"Multiple keys provided; `group_by={group_by!r}` cannot share the "
136
136
  f"x-axis with the variable column. Falling back to "
137
- f"`group_by={variable_column!r}`. For a per-key panel, use the plural variant.",
138
- stacklevel=3,
137
+ f"`group_by={variable_column!r}`. For a per-key panel, use the plural variant."
139
138
  )
140
139
  group_by = variable_column
141
140
 
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
- from warnings import warn
5
4
 
6
5
  from anndata import AnnData
7
6
 
7
+ from cellestial.util import _warn
8
8
  from cellestial.util.errors import KeyNotFoundError, UnsupportedDataTypeError
9
9
 
10
10
  if TYPE_CHECKING:
@@ -124,13 +124,12 @@ def _extract_rank_genes_groups(
124
124
  for gene, first, later in dropped[:3]
125
125
  )
126
126
  suffix = f" and {len(dropped) - 3} more" if len(dropped) > 3 else ""
127
- warn(
127
+ _warn(
128
128
  "Some genes ranked highly in multiple groups; "
129
129
  "keeping the first occurrence and dropping the rest "
130
130
  f"({examples}{suffix}). "
131
131
  "Increase `n_genes`, restrict `groups`, "
132
- "or pass an explicit `keys` mapping to control this.",
133
- stacklevel=2,
132
+ "or pass an explicit `keys` mapping to control this."
134
133
  )
135
134
 
136
135
  params = record["params"]
@@ -35,6 +35,7 @@ from cellestial.util import (
35
35
  _get_dendrogram_path_frame,
36
36
  _resolve_tooltips,
37
37
  _validate_tooltips,
38
+ _warn,
38
39
  )
39
40
  from cellestial.util.errors import UnsupportedDataTypeError
40
41
 
@@ -49,7 +50,7 @@ def dotplot(
49
50
  keys: Sequence[str] | Mapping[str, Sequence[str]] | None = None,
50
51
  group_by: str | None = None,
51
52
  *,
52
- rank_genes_groups: bool | str = False,
53
+ markers: bool | str = False,
53
54
  n_genes: int = 5,
54
55
  groups: Sequence[str] | None = None,
55
56
  mapping: FeatureSpec | None = None,
@@ -90,22 +91,20 @@ def dotplot(
90
91
  data : AnnData
91
92
  The AnnData object of the single cell data.
92
93
  keys : Sequence[str] | Mapping[str, Sequence[str]] | None, default=None
93
- The variable keys to include in the dotplot. When a mapping is
94
- provided, each entry maps a group label to the keys belonging to that
95
- group; the keys are placed on the x-axis in mapping order. The same
96
- key cannot appear in more than one group. Must be ``None`` when
97
- ``rank_genes_groups`` is set.
94
+ Variable keys to include, placed on the x-axis. A mapping assigns
95
+ keys to group labels (no key in more than one group). Must be
96
+ ``None`` when ``markers`` is set.
98
97
  group_by : str | None, default=None
99
98
  The key to group the data by. Inferred from a precomputed ranking
100
- when ``rank_genes_groups`` is set.
101
- rank_genes_groups : bool | str, default=False
99
+ when ``markers`` is set.
100
+ markers : bool | str, default=False
102
101
  Derive ``keys`` from a precomputed ranking. Pass ``True`` to use the
103
102
  default ranking key, or a string to read a custom key (e.g.
104
103
  ``"rank_genes_groups_wilcoxon"``).
105
104
  n_genes : int, default=5
106
- Number of top genes to take per group when ``rank_genes_groups`` is set.
105
+ Number of top genes to take per group when ``markers`` is set.
107
106
  groups : Sequence[str] | None, default=None
108
- Subset of groups to include when ``rank_genes_groups`` is set;
107
+ Subset of groups to include when ``markers`` is set;
109
108
  ``None`` keeps all groups in their stored order.
110
109
  mapping : FeatureSpec | None, default=None
111
110
  Aesthetic mappings for the plot, the result of `aes()`.
@@ -187,12 +186,12 @@ def dotplot(
187
186
  UnsupportedDataTypeError
188
187
  If `data` is not a supported single-cell data object.
189
188
  KeyNotFoundError
190
- If `rank_genes_groups` is enabled and the requested ranking result or
189
+ If `markers` is enabled and the requested ranking result or
191
190
  group is missing.
192
191
  DuplicateKeysError
193
192
  If a mapping passed to `keys` assigns the same key to multiple groups.
194
193
  ValueError
195
- If `keys` and `group_by` are missing while `rank_genes_groups` is
194
+ If `keys` and `group_by` are missing while `markers` is
196
195
  disabled.
197
196
 
198
197
  Examples
@@ -253,7 +252,7 @@ def dotplot(
253
252
  .. jupyter-execute::
254
253
 
255
254
  sc.tl.rank_genes_groups(data, groupby="cell_type_lvl1")
256
- cl.dotplot(data, rank_genes_groups=True, n_genes=5)
255
+ cl.dotplot(data, markers=True, n_genes=5)
257
256
 
258
257
  """
259
258
  # HANDLE: Data types
@@ -261,10 +260,10 @@ def dotplot(
261
260
  msg = f"Unsupported data type: `{type(data)}`"
262
261
  raise UnsupportedDataTypeError(msg)
263
262
 
264
- if rank_genes_groups:
263
+ if markers:
265
264
  keys, group_by = _resolve_rank_genes_groups_args(
266
265
  data,
267
- rank_genes_groups=rank_genes_groups,
266
+ rank_genes_groups=markers,
268
267
  n_genes=n_genes,
269
268
  groups=groups,
270
269
  keys=keys,
@@ -273,7 +272,7 @@ def dotplot(
273
272
  elif keys is None or group_by is None:
274
273
  msg = (
275
274
  "`keys` and `group_by` are required "
276
- "(or enable `rank_genes_groups` to derive them)."
275
+ "(or enable `markers` to derive them)."
277
276
  )
278
277
  raise ValueError(msg)
279
278
 
@@ -288,6 +287,15 @@ def dotplot(
288
287
  axis=0,
289
288
  variable_keys=keys,
290
289
  )
290
+ # WARN: negative expression makes the percent-expressed (dot size) misleading
291
+ overall_min = frame.select(pl.min_horizontal(pl.col(keys).min())).item()
292
+ if overall_min is not None and overall_min < 0:
293
+ _warn(
294
+ "Expression matrix contains negative values, which suggests scaled data. "
295
+ "Dot size (percentage of cells above `threshold`, default 0) assumes "
296
+ "non-negative expression and may be misleading here; pass raw or "
297
+ "log-normalized expression, or set `threshold` explicitly."
298
+ )
291
299
  # DROP: rows with null group_by to avoid null labels downstream
292
300
  frame = frame.filter(pl.col(group_by).is_not_null())
293
301
  index_columns = [x for x in frame.columns if x not in keys]
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Literal
4
- from warnings import warn
5
4
 
6
5
  import polars as pl
7
6
  from anndata import AnnData
@@ -29,7 +28,12 @@ from cellestial.single.heatmap._key_groups import (
29
28
  )
30
29
  from cellestial.single.heatmap._rank_genes_groups import _resolve_rank_genes_groups_args
31
30
  from cellestial.themes import _THEME_HEATMAP
32
- from cellestial.util import _fill_gradient, _get_dendrogram, _get_dendrogram_path_frame
31
+ from cellestial.util import (
32
+ _fill_gradient,
33
+ _get_dendrogram,
34
+ _get_dendrogram_path_frame,
35
+ _warn,
36
+ )
33
37
  from cellestial.util.errors import UnsupportedDataTypeError
34
38
 
35
39
  if TYPE_CHECKING:
@@ -188,7 +192,7 @@ def heatmap(
188
192
  keys: Sequence[str] | Mapping[str, Sequence[str]] | None = None,
189
193
  group_by: str | None = None,
190
194
  *,
191
- rank_genes_groups: bool | str = False,
195
+ markers: bool | str = False,
192
196
  n_genes: int = 5,
193
197
  groups: Sequence[str] | None = None,
194
198
  mapping: FeatureSpec | None = None,
@@ -233,21 +237,20 @@ def heatmap(
233
237
  data : AnnData
234
238
  The AnnData object of the single cell data.
235
239
  keys : Sequence[str] | Mapping[str, Sequence[str]] | None, default=None
236
- Variable keys to include. When a mapping is provided, each entry maps a
237
- group label to the keys belonging to that group; the keys are placed
238
- on the x-axis in mapping order. The same key cannot appear in more
239
- than one group. Must be ``None`` when ``rank_genes_groups`` is set.
240
+ Variable keys to include, placed on the x-axis. A mapping assigns
241
+ keys to group labels (no key in more than one group). Must be
242
+ ``None`` when ``markers`` is set.
240
243
  group_by : str | None, default=None
241
244
  The key to group the data by. Inferred from a precomputed ranking
242
- when ``rank_genes_groups`` is set.
243
- rank_genes_groups : bool | str, default=False
245
+ when ``markers`` is set.
246
+ markers : bool | str, default=False
244
247
  Derive ``keys`` from a precomputed ranking. Pass ``True`` to use the
245
248
  default ranking key, or a string to read a custom key (e.g.
246
249
  ``"rank_genes_groups_wilcoxon"``).
247
250
  n_genes : int, default=5
248
- Number of top genes to take per group when ``rank_genes_groups`` is set.
251
+ Number of top genes to take per group when ``markers`` is set.
249
252
  groups : Sequence[str] | None, default=None
250
- Subset of groups to include when ``rank_genes_groups`` is set;
253
+ Subset of groups to include when ``markers`` is set;
251
254
  ``None`` keeps all groups in their stored order.
252
255
  mapping : FeatureSpec | None, default=None
253
256
  Aesthetic mappings for the plot, the result of `aes()`.
@@ -338,12 +341,12 @@ def heatmap(
338
341
  UnsupportedDataTypeError
339
342
  If `data` is not a supported single-cell data object.
340
343
  KeyNotFoundError
341
- If `rank_genes_groups` is enabled and the requested ranking result or
344
+ If `markers` is enabled and the requested ranking result or
342
345
  group is missing.
343
346
  DuplicateKeysError
344
347
  If a mapping passed to `keys` assigns the same key to multiple groups.
345
348
  ValueError
346
- If `keys` and `group_by` are missing while `rank_genes_groups` is
349
+ If `keys` and `group_by` are missing while `markers` is
347
350
  disabled.
348
351
 
349
352
  Examples
@@ -426,7 +429,7 @@ def heatmap(
426
429
  )
427
430
 
428
431
  To plot the top genes from a precomputed ranking, set
429
- ``rank_genes_groups`` and ``n_genes`` (``keys`` and ``group_by`` are
432
+ ``markers`` and ``n_genes`` (``keys`` and ``group_by`` are
430
433
  inferred):
431
434
 
432
435
  .. jupyter-execute::
@@ -434,17 +437,17 @@ def heatmap(
434
437
  import scanpy as sc
435
438
 
436
439
  sc.tl.rank_genes_groups(data, groupby="cell_type_lvl1")
437
- cl.heatmap(data, rank_genes_groups=True, n_genes=5, aggregate=True)
440
+ cl.heatmap(data, markers=True, n_genes=5, aggregate=True)
438
441
 
439
442
  """
440
443
  if not isinstance(data, AnnData):
441
444
  msg = f"Unsupported data type: `{type(data)}`"
442
445
  raise UnsupportedDataTypeError(msg)
443
446
 
444
- if rank_genes_groups:
447
+ if markers:
445
448
  keys, group_by = _resolve_rank_genes_groups_args(
446
449
  data,
447
- rank_genes_groups=rank_genes_groups,
450
+ rank_genes_groups=markers,
448
451
  n_genes=n_genes,
449
452
  groups=groups,
450
453
  keys=keys,
@@ -453,17 +456,16 @@ def heatmap(
453
456
  elif keys is None or group_by is None:
454
457
  msg = (
455
458
  "`keys` and `group_by` are required "
456
- "(or enable `rank_genes_groups` to derive them)."
459
+ "(or enable `markers` to derive them)."
457
460
  )
458
461
  raise ValueError(msg)
459
462
 
460
463
  mapping = mapping or aes()
461
464
 
462
465
  if "tooltips" in geom_kwargs and geom == "raster":
463
- warn(
466
+ _warn(
464
467
  "\nWarning: tooltips are not supported for 'raster' geom and will be ignored."
465
- "\nUse 'tile' geom to enable tooltips.",
466
- stacklevel=1,
468
+ "\nUse 'tile' geom to enable tooltips."
467
469
  )
468
470
  geom_kwargs.pop("tooltips")
469
471
 
@@ -649,7 +651,7 @@ def matrixplot(
649
651
  keys: Sequence[str] | Mapping[str, Sequence[str]] | None = None,
650
652
  group_by: str | None = None,
651
653
  *,
652
- rank_genes_groups: bool | str = False,
654
+ markers: bool | str = False,
653
655
  n_genes: int = 5,
654
656
  groups: Sequence[str] | None = None,
655
657
  mapping: FeatureSpec | None = None,
@@ -692,21 +694,20 @@ def matrixplot(
692
694
  data : AnnData
693
695
  The AnnData object of the single cell data.
694
696
  keys : Sequence[str] | Mapping[str, Sequence[str]] | None, default=None
695
- Variable keys to include. When a mapping is provided, each entry maps
696
- a group label to the keys belonging to that group; the keys are placed
697
- on the x-axis in mapping order. The same key cannot appear in more
698
- than one group. Must be ``None`` when ``rank_genes_groups`` is set.
697
+ Variable keys to include, placed on the x-axis. A mapping assigns
698
+ keys to group labels (no key in more than one group). Must be
699
+ ``None`` when ``markers`` is set.
699
700
  group_by : str | None, default=None
700
701
  The key to group the data by. Inferred from a precomputed ranking
701
- when ``rank_genes_groups`` is set.
702
- rank_genes_groups : bool | str, default=False
702
+ when ``markers`` is set.
703
+ markers : bool | str, default=False
703
704
  Derive ``keys`` from a precomputed ranking. Pass ``True`` to use the
704
705
  default ranking key, or a string to read a custom key (e.g.
705
706
  ``"rank_genes_groups_wilcoxon"``).
706
707
  n_genes : int, default=5
707
- Number of top genes to take per group when ``rank_genes_groups`` is set.
708
+ Number of top genes to take per group when ``markers`` is set.
708
709
  groups : Sequence[str] | None, default=None
709
- Subset of groups to include when ``rank_genes_groups`` is set;
710
+ Subset of groups to include when ``markers`` is set;
710
711
  ``None`` keeps all groups in their stored order.
711
712
  mapping : FeatureSpec | None, default=None
712
713
  Aesthetic mappings for the plot, the result of `aes()`.
@@ -817,13 +818,13 @@ def matrixplot(
817
818
  .. jupyter-execute::
818
819
 
819
820
  sc.tl.rank_genes_groups(data, groupby="cell_type_lvl1")
820
- cl.matrixplot(data, rank_genes_groups=True, n_genes=5)
821
+ cl.matrixplot(data, markers=True, n_genes=5)
821
822
  """
822
823
  return heatmap(
823
824
  data,
824
825
  keys=keys,
825
826
  group_by=group_by,
826
- rank_genes_groups=rank_genes_groups,
827
+ markers=markers,
827
828
  n_genes=n_genes,
828
829
  groups=groups,
829
830
  mapping=mapping,
@@ -179,7 +179,7 @@ def stacked_violin(
179
179
  keys: Sequence[str] | Mapping[str, Sequence[str]] | None = None,
180
180
  group_by: str | None = None,
181
181
  *,
182
- rank_genes_groups: bool | str = False,
182
+ markers: bool | str = False,
183
183
  n_genes: int = 5,
184
184
  groups: Sequence[str] | None = None,
185
185
  mapping: FeatureSpec | None = None,
@@ -227,22 +227,20 @@ def stacked_violin(
227
227
  data : AnnData
228
228
  The AnnData object of the single cell data.
229
229
  keys : Sequence[str] | Mapping[str, Sequence[str]] | None, default=None
230
- Variable keys laid out along the x-axis. One column of violins per
231
- key. When a mapping is provided, each entry maps a group label to the
232
- keys belonging to that group; the keys are placed on the x-axis in
233
- mapping order. The same key cannot appear in more than one group.
234
- Must be ``None`` when ``rank_genes_groups`` is set.
230
+ Variable keys laid out along the x-axis, one column of violins per
231
+ key. A mapping assigns keys to group labels (no key in more than one
232
+ group). Must be ``None`` when ``markers`` is set.
235
233
  group_by : str | None, default=None
236
234
  The key used to group observations along the y-axis. Inferred from a
237
- precomputed ranking when ``rank_genes_groups`` is set.
238
- rank_genes_groups : bool | str, default=False
235
+ precomputed ranking when ``markers`` is set.
236
+ markers : bool | str, default=False
239
237
  Derive ``keys`` from a precomputed ranking. Pass ``True`` to use the
240
238
  default ranking key, or a string to read a custom key (e.g.
241
239
  ``"rank_genes_groups_wilcoxon"``).
242
240
  n_genes : int, default=5
243
- Number of top genes to take per group when ``rank_genes_groups`` is set.
241
+ Number of top genes to take per group when ``markers`` is set.
244
242
  groups : Sequence[str] | None, default=None
245
- Subset of groups to include when ``rank_genes_groups`` is set;
243
+ Subset of groups to include when ``markers`` is set;
246
244
  ``None`` keeps all groups in their stored order.
247
245
  mapping : FeatureSpec | None, default=None
248
246
  Aesthetic mappings for the plot, the result of `aes()`.
@@ -349,12 +347,12 @@ def stacked_violin(
349
347
  UnsupportedDataTypeError
350
348
  If `data` is not a supported single-cell data object.
351
349
  KeyNotFoundError
352
- If `rank_genes_groups` is enabled and the requested ranking result or
350
+ If `markers` is enabled and the requested ranking result or
353
351
  group is missing.
354
352
  DuplicateKeysError
355
353
  If a mapping passed to `keys` assigns the same key to multiple groups.
356
354
  ValueError
357
- If `keys` and `group_by` are missing while `rank_genes_groups` is
355
+ If `keys` and `group_by` are missing while `markers` is
358
356
  disabled.
359
357
 
360
358
  Examples
@@ -407,17 +405,17 @@ def stacked_violin(
407
405
  .. jupyter-execute::
408
406
 
409
407
  sc.tl.rank_genes_groups(data, groupby="cell_type_lvl1")
410
- cl.stacked_violin(data, rank_genes_groups=True, n_genes=5)
408
+ cl.stacked_violin(data, markers=True, n_genes=5)
411
409
  """
412
410
  # HANDLE: Data types
413
411
  if not isinstance(data, AnnData):
414
412
  msg = f"Unsupported data type: `{type(data)}`"
415
413
  raise UnsupportedDataTypeError(msg)
416
414
 
417
- if rank_genes_groups:
415
+ if markers:
418
416
  keys, group_by = _resolve_rank_genes_groups_args(
419
417
  data,
420
- rank_genes_groups=rank_genes_groups,
418
+ rank_genes_groups=markers,
421
419
  n_genes=n_genes,
422
420
  groups=groups,
423
421
  keys=keys,
@@ -426,7 +424,7 @@ def stacked_violin(
426
424
  elif keys is None or group_by is None:
427
425
  msg = (
428
426
  "`keys` and `group_by` are required "
429
- "(or enable `rank_genes_groups` to derive them)."
427
+ "(or enable `markers` to derive them)."
430
428
  )
431
429
  raise ValueError(msg)
432
430
 
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import warnings
4
3
  from collections.abc import Sequence
5
4
  from typing import TYPE_CHECKING
6
5
 
@@ -30,6 +29,7 @@ from cellestial.util import (
30
29
  _is_variable_key,
31
30
  _resolve_tooltips,
32
31
  _validate_tooltips,
32
+ _warn,
33
33
  )
34
34
  from cellestial.util.errors import UnsupportedDataTypeError
35
35
 
@@ -113,7 +113,7 @@ def _spatial_components(
113
113
  image_array = images.get(image_key)
114
114
  if image_array is None:
115
115
  msg = f"image `{image_key}` not found for library `{library_id}`"
116
- warnings.warn(msg, stacklevel=2)
116
+ _warn(msg)
117
117
  return image_array, spot_coordinates, None, data
118
118
 
119
119
  msg = f"Unsupported data type: `{type(data)}`"
@@ -408,7 +408,7 @@ def spatial(
408
408
  frame = frame.filter(pl.col(key).is_in(list(groups)))
409
409
  else:
410
410
  msg = f"key `{key}` is not categorical, `groups` filter ignored"
411
- warnings.warn(msg, stacklevel=1)
411
+ _warn(msg)
412
412
 
413
413
  # HANDLE: standard scaling (numeric keys only)
414
414
  if scale_axis is not None and key is not None and frame[key].dtype.is_numeric():
@@ -18,6 +18,7 @@ from cellestial.util.utilities import (
18
18
  _share_ticks,
19
19
  _tooltip_fields,
20
20
  _validate_tooltips,
21
+ _warn,
21
22
  )
22
23
 
23
24
  __all__ = [
@@ -36,6 +37,7 @@ __all__ = [
36
37
  "_share_ticks",
37
38
  "_tooltip_fields",
38
39
  "_validate_tooltips",
40
+ "_warn",
39
41
  "get_mapping",
40
42
  "get_slice",
41
43
  "retrieve",
@@ -59,3 +59,7 @@ class SpatialLibraryError(Exception):
59
59
 
60
60
  def __init__(self, message: str):
61
61
  super().__init__(message)
62
+
63
+
64
+ class CellestialWarning(UserWarning):
65
+ """Base category for warnings raised by cellestial."""
@@ -1,8 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import inspect
3
4
  import re
5
+ import warnings
4
6
  from collections.abc import Sequence
5
7
  from math import ceil, log10
8
+ from pathlib import Path
6
9
  from typing import Literal
7
10
 
8
11
  import polars as pl
@@ -21,6 +24,44 @@ from lets_plot import (
21
24
  from lets_plot.plot.core import FeatureSpec
22
25
  from lets_plot.plot.subplots import SupPlotsSpec
23
26
 
27
+ from cellestial.util.errors import CellestialWarning
28
+
29
+ _PACKAGE_ROOT = str(Path(__file__).parents[1])
30
+
31
+
32
+ def _format_warning(
33
+ message: Warning | str, category: type[Warning], *_args: object
34
+ ) -> str:
35
+ """Render a cellestial warning as one line, dropping the source location."""
36
+ return f"{category.__name__}: {message}\n"
37
+
38
+
39
+ def _warn(message: str) -> None:
40
+ """
41
+ Emit a ``CellestialWarning`` rendered without the source location.
42
+
43
+ The warning is still attributed to the first caller outside cellestial so
44
+ ``warnings`` filters and per-location de-duplication behave sensibly, but
45
+ it is displayed as a single clean line.
46
+
47
+ Parameters
48
+ ----------
49
+ message : str
50
+ The warning message.
51
+ """
52
+ caller = inspect.currentframe()
53
+ caller = caller.f_back if caller is not None else None
54
+ stacklevel = 2
55
+ while caller is not None and caller.f_code.co_filename.startswith(_PACKAGE_ROOT):
56
+ stacklevel += 1
57
+ caller = caller.f_back
58
+ original_format = warnings.formatwarning
59
+ warnings.formatwarning = _format_warning
60
+ try:
61
+ warnings.warn(message, CellestialWarning, stacklevel=stacklevel)
62
+ finally:
63
+ warnings.formatwarning = original_format
64
+
24
65
 
25
66
  def _build_tooltips(
26
67
  *,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cellestial"
3
- version = "0.45.0"
3
+ version = "0.46.0"
4
4
  description = ""
5
5
  authors = [
6
6
  { name = "Zaf4", email = "zafermolbio@gmail.com" },
File without changes
File without changes