cellestial 0.58.2__tar.gz → 0.60.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 (68) hide show
  1. {cellestial-0.58.2 → cellestial-0.60.0}/PKG-INFO +1 -1
  2. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/complex/annotated_heatmap.py +15 -8
  3. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/datasets/__init__.py +2 -0
  4. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/datasets/datasets.py +100 -29
  5. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/frames/__init__.py +4 -3
  6. cellestial-0.60.0/cellestial/frames/_container.py +382 -0
  7. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/frames/build.py +58 -57
  8. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/__init__.py +1 -2
  9. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/arrow.py +3 -3
  10. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/bracket.py +1 -1
  11. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/ondata_legend.py +1 -1
  12. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/outline.py +3 -3
  13. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/stream.py +2 -2
  14. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/base/base.py +6 -5
  15. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/basic/bar.py +4 -3
  16. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/basic/scatter.py +5 -4
  17. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/common/xyplot.py +7 -6
  18. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/common/xyplots.py +4 -3
  19. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/dimensional.py +13 -12
  20. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/distribution.py +17 -10
  21. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/distributions.py +72 -19
  22. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/subdimensional.py +28 -27
  23. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/subdimensionals.py +44 -53
  24. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/utilities.py +31 -4
  25. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/differential/markers.py +12 -3
  26. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/differential/volcano.py +26 -9
  27. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/heatmap/dotplot.py +21 -10
  28. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/heatmap/heatmap.py +26 -15
  29. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/heatmap/stacked_violin.py +22 -11
  30. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/quick/elbow.py +13 -4
  31. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/quick/highest.py +14 -5
  32. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/quick/ridge.py +11 -10
  33. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/spatial/spatial.py +20 -7
  34. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/spatial/spatials.py +19 -5
  35. cellestial-0.60.0/cellestial/themes/__init__.py +11 -0
  36. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/__init__.py +3 -23
  37. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/dendrogram.py +11 -0
  38. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/errors.py +7 -0
  39. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/markers.py +20 -4
  40. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/operations.py +5 -5
  41. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/utilities.py +229 -155
  42. {cellestial-0.58.2 → cellestial-0.60.0}/pyproject.toml +1 -1
  43. cellestial-0.58.2/cellestial/themes/__init__.py +0 -20
  44. {cellestial-0.58.2 → cellestial-0.60.0}/LICENSE +0 -0
  45. {cellestial-0.58.2 → cellestial-0.60.0}/README.md +0 -0
  46. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/__init__.py +0 -0
  47. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/_version.py +0 -0
  48. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/complex/__init__.py +0 -0
  49. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/frames/operations.py +0 -0
  50. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/_deferred.py +0 -0
  51. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/layers/utilities.py +0 -0
  52. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/__init__.py +0 -0
  53. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/base/__init__.py +0 -0
  54. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/basic/__init__.py +0 -0
  55. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/common/__init__.py +0 -0
  56. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/core/__init__.py +0 -0
  57. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/differential/__init__.py +0 -0
  58. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/differential/utilities.py +0 -0
  59. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/heatmap/__init__.py +0 -0
  60. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/heatmap/utilities.py +0 -0
  61. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/single/quick/__init__.py +0 -0
  62. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/spatial/__init__.py +0 -0
  63. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/spatial/utilities.py +0 -0
  64. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/themes/_distributions.py +0 -0
  65. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/themes/_heatmaps.py +0 -0
  66. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/themes/_scatters.py +0 -0
  67. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/colors.py +0 -0
  68. {cellestial-0.58.2 → cellestial-0.60.0}/cellestial/util/save.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cellestial
3
- Version: 0.58.2
3
+ Version: 0.60.0
4
4
  Summary: Interactive single-cell and spatial omics visualization library
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -26,12 +26,14 @@ from lets_plot import (
26
26
  scale_y_continuous,
27
27
  theme,
28
28
  )
29
+ from mudata import MuData
29
30
 
30
31
  from cellestial.frames import build_frame
31
32
  from cellestial.single.heatmap.utilities import _scale_values
32
33
  from cellestial.themes import _THEME_HEATMAP
33
34
  from cellestial.util import _fill_gradient, _get_dendrogram, _warn
34
35
  from cellestial.util.errors import _unsupported_data_type
36
+ from cellestial.util.utilities import _modality_source
35
37
 
36
38
  if TYPE_CHECKING:
37
39
  from collections.abc import Sequence
@@ -330,10 +332,11 @@ def _dendrogram_panel(
330
332
 
331
333
 
332
334
  def annotated_heatmap(
333
- data: AnnData,
335
+ data: AnnData | MuData,
334
336
  keys: Sequence[str],
335
337
  group_by: str | None = None,
336
338
  *,
339
+ modality: str | None = None,
337
340
  column_annotations: str | Sequence[str] | None = None,
338
341
  row_annotations: str | Sequence[str] | None = None,
339
342
  annotation_colors: Mapping[str, AnnotationColors] | None = None,
@@ -359,7 +362,7 @@ def annotated_heatmap(
359
362
  color_low: str = "#0000ff",
360
363
  color_mid: str = "#ffffff",
361
364
  color_high: str = "#ff0000",
362
- mid_point: Literal["mean", "median", "mid"] | float = "mid",
365
+ midpoint: Literal["mean", "median", "mid"] | float = "mid",
363
366
  max_rows: int | None = 1000,
364
367
  value_column: str = "value",
365
368
  variable_column: str = "variable",
@@ -377,6 +380,10 @@ def annotated_heatmap(
377
380
  The AnnData object of the single cell data.
378
381
  keys : Sequence[str]
379
382
  Variable keys to include, placed on the x-axis.
383
+ modality : str | None, default=None
384
+ Which modality's stored analysis results to use when `markers` or
385
+ `dendrogram` is enabled. Required for a multimodal object holding more
386
+ than one modality, and not accepted otherwise.
380
387
  group_by : str | None, default=None
381
388
  The observation key to group the rows by. When `None`, rows keep their
382
389
  original order and no group separators are drawn.
@@ -446,7 +453,7 @@ def annotated_heatmap(
446
453
  Color for mid values in the heatmap gradient.
447
454
  color_high : str, default='#ff0000'
448
455
  Color for high values in the heatmap gradient.
449
- mid_point : {'mean', 'median', 'mid'} | float, default='mid'
456
+ midpoint : {'mean', 'median', 'mid'} | float, default='mid'
450
457
  Midpoint for the heatmap color gradient.
451
458
  max_rows : int | None, default=1000
452
459
  Cap the number of plotted rows by averaging contiguous observations
@@ -495,7 +502,7 @@ def annotated_heatmap(
495
502
 
496
503
  import cellestial as cl
497
504
 
498
- data = cl.datasets.pbmc3k(cache_directory="data")
505
+ data = cl.datasets.pbmc3k()
499
506
  markers = ["C1QA", "PSAP", "CD79A", "CD79B", "CST3", "LYZ"]
500
507
 
501
508
  cl.annotated_heatmap(
@@ -507,8 +514,8 @@ def annotated_heatmap(
507
514
  scale_axis=0,
508
515
  )
509
516
  """
510
- if not isinstance(data, AnnData):
511
- raise _unsupported_data_type(data, AnnData)
517
+ if not isinstance(data, (AnnData, MuData)):
518
+ raise _unsupported_data_type(data, AnnData, MuData)
512
519
 
513
520
  keys = list(keys)
514
521
  column_annotations = _as_list(column_annotations)
@@ -524,7 +531,7 @@ def annotated_heatmap(
524
531
  if dendrogram:
525
532
  assert group_by is not None # guaranteed by the guard above
526
533
  dendrogram_order, dendrogram_paths = _get_dendrogram(
527
- data, group_by, use_key=dendrogram_key
534
+ *_modality_source(data, modality, group_by), use_key=dendrogram_key
528
535
  )
529
536
  else:
530
537
  dendrogram_order, dendrogram_paths = None, None
@@ -608,7 +615,7 @@ def annotated_heatmap(
608
615
  color_low=color_low,
609
616
  color_mid=color_mid,
610
617
  color_high=color_high,
611
- mid_point=mid_point,
618
+ midpoint=midpoint,
612
619
  )
613
620
  + key_scale
614
621
  + observation_scale
@@ -5,6 +5,7 @@ from cellestial.datasets.datasets import (
5
5
  human_lymph_node,
6
6
  pancreas,
7
7
  pbmc3k,
8
+ pbmc_cite,
8
9
  )
9
10
 
10
11
  __all__ = [
@@ -14,4 +15,5 @@ __all__ = [
14
15
  "human_lymph_node",
15
16
  "pancreas",
16
17
  "pbmc3k",
18
+ "pbmc_cite",
17
19
  ]
@@ -2,8 +2,10 @@ import re
2
2
  import shutil
3
3
  from os import PathLike
4
4
  from pathlib import Path
5
+ from typing import cast
5
6
 
6
7
  from anndata import AnnData, read_h5ad
8
+ from mudata import MuData
7
9
 
8
10
  _GLOBAL_CACHE = Path.home() / ".cache" / "cellestial" / "datasets"
9
11
 
@@ -81,11 +83,14 @@ def pbmc3k(
81
83
  OSError
82
84
  If the downloaded file size does not match the expected size.
83
85
  """
84
- return from_url(
85
- "https://huggingface.co/datasets/datavil/pbmc3k/resolve/main/pbmc3k_pped.h5ad",
86
- cache_directory=cache_directory,
87
- use_cache=use_cache,
88
- bring=bring,
86
+ return cast(
87
+ "AnnData",
88
+ from_url(
89
+ "https://huggingface.co/datasets/datavil/pbmc3k/resolve/main/pbmc3k_pped.h5ad",
90
+ cache_directory=cache_directory,
91
+ use_cache=use_cache,
92
+ bring=bring,
93
+ ),
89
94
  )
90
95
 
91
96
 
@@ -120,14 +125,70 @@ def pancreas(
120
125
  OSError
121
126
  If the downloaded file size does not match the expected size.
122
127
  """
123
- return from_url(
124
- "https://huggingface.co/datasets/datavil/pancreas/resolve/main/endocrinogenesis_day15_pped.h5ad",
125
- cache_directory=cache_directory,
126
- use_cache=use_cache,
127
- bring=bring,
128
+ return cast(
129
+ "AnnData",
130
+ from_url(
131
+ "https://huggingface.co/datasets/datavil/pancreas/resolve/main/endocrinogenesis_day15_pped.h5ad",
132
+ cache_directory=cache_directory,
133
+ use_cache=use_cache,
134
+ bring=bring,
135
+ ),
128
136
  )
129
137
 
130
138
 
139
+ def pbmc_cite(
140
+ cache_directory: str | Path | PathLike = _GLOBAL_CACHE,
141
+ *,
142
+ use_cache: bool = True,
143
+ bring: bool = True,
144
+ ) -> MuData:
145
+ """
146
+ Download and load a small multimodal CITE-seq PBMC dataset.
147
+
148
+ Parameters
149
+ ----------
150
+ cache_directory : str | Path | PathLike
151
+ Directory where the `.h5mu` file is cached.
152
+ use_cache : bool, default=True
153
+ If True, load from the cached file when present. If False, remove any
154
+ existing cached file and re-download.
155
+ bring : bool, default=True
156
+ If True and `cache_directory` is not the default global cache, copy the
157
+ file from the global cache when it already exists there. Set to False
158
+ to disable this behavior.
159
+
160
+ Returns
161
+ -------
162
+ MuData
163
+ 411 cells with paired gene expression (`rna`) and surface protein
164
+ (`prot`) modalities, carrying joint WNN and MOFA embeddings.
165
+
166
+ Raises
167
+ ------
168
+ OSError
169
+ If the downloaded file size does not match the expected size.
170
+ """
171
+ return cast(
172
+ "MuData",
173
+ from_url(
174
+ "https://github.com/gtca/h5xx-datasets/raw/main/datasets/minipbcite.h5mu",
175
+ cache_directory=cache_directory,
176
+ use_cache=use_cache,
177
+ bring=bring,
178
+ extension=".h5mu",
179
+ ),
180
+ )
181
+
182
+
183
+ def _read_dataset(path: Path) -> AnnData | MuData:
184
+ """Read a cached dataset, dispatching on the file extension."""
185
+ if path.suffix == ".h5mu":
186
+ from mudata import read_h5mu
187
+
188
+ return read_h5mu(path)
189
+ return read_h5ad(path)
190
+
191
+
131
192
  def from_url(
132
193
  url: str,
133
194
  *,
@@ -135,14 +196,15 @@ def from_url(
135
196
  cache_directory: str | Path | PathLike = _GLOBAL_CACHE,
136
197
  use_cache: bool = True,
137
198
  bring: bool = True,
138
- ) -> AnnData:
199
+ extension: str = ".h5ad",
200
+ ) -> AnnData | MuData:
139
201
  """
140
- Download and load an `.h5ad` dataset from a direct HTTP(S) URL.
202
+ Download and load a dataset from a direct HTTP(S) URL.
141
203
 
142
204
  Parameters
143
205
  ----------
144
206
  url : str
145
- Direct URL to a downloadable `.h5ad` file.
207
+ Direct URL to a downloadable `.h5ad` or `.h5mu` file.
146
208
  name : str, optional
147
209
  Name for the cached file (without extension). If omitted, the cache
148
210
  filename is derived from the URL's last path segment.
@@ -155,10 +217,13 @@ def from_url(
155
217
  If True and `cache_directory` is not the default global cache, copy the
156
218
  file from the global cache when it already exists there. Set to False
157
219
  to disable this behavior.
220
+ extension : str, default='.h5ad'
221
+ File extension used when `name` is given, and the format the downloaded
222
+ file is read as. Pass '.h5mu' for a multimodal dataset.
158
223
 
159
224
  Returns
160
225
  -------
161
- AnnData
226
+ AnnData | MuData
162
227
  The downloaded dataset.
163
228
 
164
229
  Raises
@@ -170,7 +235,7 @@ def from_url(
170
235
 
171
236
  Notes
172
237
  -----
173
- Generic loader for any host that serves an AnnData `.h5ad` file at a
238
+ Generic loader for any host that serves an `.h5ad` or `.h5mu` file at a
174
239
  stable URL (CELLxGENE, Zenodo, Figshare, S3 buckets, etc.).
175
240
  """
176
241
  from urllib.parse import urlparse
@@ -179,7 +244,7 @@ def from_url(
179
244
  from tqdm import tqdm
180
245
 
181
246
  if name is not None:
182
- filename = f"{name}.h5ad"
247
+ filename = f"{name}{extension}"
183
248
  else:
184
249
  filename = Path(urlparse(url).path).name
185
250
  if not filename:
@@ -189,7 +254,7 @@ def from_url(
189
254
  cache_file = _resolve_cache_file(cache_directory, filename, use_cache=use_cache, bring=bring)
190
255
 
191
256
  if cache_file.exists():
192
- return read_h5ad(cache_file)
257
+ return _read_dataset(cache_file)
193
258
 
194
259
  print(f"No cache at {cache_file} !")
195
260
  print(f"Downloading from {url} ...")
@@ -227,7 +292,7 @@ def from_url(
227
292
 
228
293
  print(f"Saved to {cache_file}")
229
294
 
230
- return read_h5ad(cache_file)
295
+ return _read_dataset(cache_file)
231
296
 
232
297
 
233
298
  def from_cellxgene(
@@ -291,12 +356,15 @@ def from_cellxgene(
291
356
  else f"https://datasets.cellxgene.cziscience.com/{uuid}.h5ad"
292
357
  )
293
358
 
294
- return from_url(
295
- url,
296
- name=name or uuid,
297
- cache_directory=cache_directory,
298
- use_cache=use_cache,
299
- bring=bring,
359
+ return cast(
360
+ "AnnData",
361
+ from_url(
362
+ url,
363
+ name=name or uuid,
364
+ cache_directory=cache_directory,
365
+ use_cache=use_cache,
366
+ bring=bring,
367
+ ),
300
368
  )
301
369
 
302
370
 
@@ -375,9 +443,12 @@ def human_lymph_node(
375
443
  OSError
376
444
  If the downloaded file size does not match the expected size.
377
445
  """
378
- return from_url(
379
- "https://huggingface.co/datasets/datavil/human_lymph_node/resolve/main/V1_Human_Lymph_Node_pped.h5ad",
380
- cache_directory=cache_directory,
381
- use_cache=use_cache,
382
- bring=bring,
446
+ return cast(
447
+ "AnnData",
448
+ from_url(
449
+ "https://huggingface.co/datasets/datavil/human_lymph_node/resolve/main/V1_Human_Lymph_Node_pped.h5ad",
450
+ cache_directory=cache_directory,
451
+ use_cache=use_cache,
452
+ bring=bring,
453
+ ),
383
454
  )
@@ -4,11 +4,12 @@ from cellestial.frames.build import (
4
4
  anndata_variables_frame,
5
5
  build_frame,
6
6
  )
7
- from cellestial.frames.operations import _highest_expressed_genes_frame, _pca_variance_frame
7
+ from cellestial.frames.operations import ( # noqa: F401
8
+ _highest_expressed_genes_frame,
9
+ _pca_variance_frame,
10
+ )
8
11
 
9
12
  __all__ = [
10
- "_highest_expressed_genes_frame",
11
- "_pca_variance_frame",
12
13
  "anndata_observations_frame",
13
14
  "anndata_variable_columns",
14
15
  "anndata_variables_frame",