cytome 0.2.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.
- cytome-0.2.2/LICENSE +29 -0
- cytome-0.2.2/PKG-INFO +270 -0
- cytome-0.2.2/README.md +216 -0
- cytome-0.2.2/cytome/__init__.py +456 -0
- cytome-0.2.2/cytome/cli/__init__.py +1 -0
- cytome-0.2.2/cytome/cli/main.py +330 -0
- cytome-0.2.2/cytome/core/__init__.py +24 -0
- cytome-0.2.2/cytome/core/dataset.py +1756 -0
- cytome-0.2.2/cytome/core/embedding.py +60 -0
- cytome-0.2.2/cytome/core/entity.py +157 -0
- cytome-0.2.2/cytome/core/fragments.py +220 -0
- cytome-0.2.2/cytome/core/graph.py +104 -0
- cytome-0.2.2/cytome/core/lazy_layer.py +23 -0
- cytome-0.2.2/cytome/core/measurement.py +205 -0
- cytome-0.2.2/cytome/core/metadata.py +181 -0
- cytome-0.2.2/cytome/core/provenance.py +125 -0
- cytome-0.2.2/cytome/dataloader/__init__.py +5 -0
- cytome-0.2.2/cytome/dataloader/pytorch.py +53 -0
- cytome-0.2.2/cytome/index/__init__.py +23 -0
- cytome-0.2.2/cytome/index/builder.py +61 -0
- cytome-0.2.2/cytome/index/rtree.py +217 -0
- cytome-0.2.2/cytome/io/__init__.py +32 -0
- cytome-0.2.2/cytome/io/chunk_tuning.py +36 -0
- cytome-0.2.2/cytome/io/chunked_io.py +658 -0
- cytome-0.2.2/cytome/io/compression.py +143 -0
- cytome-0.2.2/cytome/io/convert_anndata.py +1174 -0
- cytome-0.2.2/cytome/io/convert_cellranger.py +500 -0
- cytome-0.2.2/cytome/io/convert_fragments.py +1000 -0
- cytome-0.2.2/cytome/io/convert_mudata.py +86 -0
- cytome-0.2.2/cytome/io/convert_soma.py +15 -0
- cytome-0.2.2/cytome/io/export_bigwig.py +330 -0
- cytome-0.2.2/cytome/io/gtf_import.py +373 -0
- cytome-0.2.2/cytome/io/merge.py +540 -0
- cytome-0.2.2/cytome/io/sqlite_engine.py +560 -0
- cytome-0.2.2/cytome/io/subset.py +560 -0
- cytome-0.2.2/cytome/py.typed +0 -0
- cytome-0.2.2/cytome/utils/__init__.py +39 -0
- cytome-0.2.2/cytome/utils/genome.py +99 -0
- cytome-0.2.2/cytome/utils/modality.py +275 -0
- cytome-0.2.2/cytome/utils/regions.py +73 -0
- cytome-0.2.2/cytome/utils/validation.py +311 -0
- cytome-0.2.2/cytome/utils/versioning.py +61 -0
- cytome-0.2.2/cytome.egg-info/PKG-INFO +270 -0
- cytome-0.2.2/cytome.egg-info/SOURCES.txt +59 -0
- cytome-0.2.2/cytome.egg-info/dependency_links.txt +1 -0
- cytome-0.2.2/cytome.egg-info/entry_points.txt +2 -0
- cytome-0.2.2/cytome.egg-info/requires.txt +26 -0
- cytome-0.2.2/cytome.egg-info/top_level.txt +1 -0
- cytome-0.2.2/pyproject.toml +91 -0
- cytome-0.2.2/setup.cfg +4 -0
- cytome-0.2.2/tests/test_compression_lz4_required.py +50 -0
- cytome-0.2.2/tests/test_compression_roundtrip.py +0 -0
- cytome-0.2.2/tests/test_create_force_guard.py +72 -0
- cytome-0.2.2/tests/test_export_fragment_chunks.py +70 -0
- cytome-0.2.2/tests/test_filter_cells_preserves_annotations.py +113 -0
- cytome-0.2.2/tests/test_filter_cells_wal_and_compact.py +84 -0
- cytome-0.2.2/tests/test_from_cellranger_modalities.py +133 -0
- cytome-0.2.2/tests/test_keep_chroms_filter.py +90 -0
- cytome-0.2.2/tests/test_merge_projection_and_fragments.py +125 -0
- cytome-0.2.2/tests/test_merge_tiles_and_layers.py +178 -0
- cytome-0.2.2/tests/test_to_anndata_modality_scoping.py +79 -0
cytome-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Min Dai
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
cytome-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cytome
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Single-file multi-omics data format for single-cell biology
|
|
5
|
+
Author-email: Min Dai <dai@broadinstitute.org>
|
|
6
|
+
Maintainer-email: Min Dai <dai@broadinstitute.org>
|
|
7
|
+
License: BSD-3-Clause
|
|
8
|
+
Project-URL: Homepage, https://github.com/genecell/cytome
|
|
9
|
+
Project-URL: Source, https://github.com/genecell/cytome
|
|
10
|
+
Project-URL: Documentation, https://github.com/genecell/cytome
|
|
11
|
+
Keywords: single-cell,genomics,bioinformatics,scRNA-seq,scATAC-seq,multiomics,data-format,sqlite,streaming
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Framework :: Jupyter
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
28
|
+
Requires-Python: >=3.9
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: numpy>=1.24
|
|
32
|
+
Requires-Dist: scipy>=1.11
|
|
33
|
+
Requires-Dist: pandas>=1.5
|
|
34
|
+
Requires-Dist: lz4>=4.0
|
|
35
|
+
Provides-Extra: anndata
|
|
36
|
+
Requires-Dist: anndata>=0.10; extra == "anndata"
|
|
37
|
+
Provides-Extra: mudata
|
|
38
|
+
Requires-Dist: mudata>=0.2; extra == "mudata"
|
|
39
|
+
Provides-Extra: full
|
|
40
|
+
Requires-Dist: anndata>=0.10; extra == "full"
|
|
41
|
+
Requires-Dist: mudata>=0.2; extra == "full"
|
|
42
|
+
Requires-Dist: zstandard>=0.20; extra == "full"
|
|
43
|
+
Requires-Dist: pysam>=0.22; extra == "full"
|
|
44
|
+
Requires-Dist: pyBigWig>=0.3; extra == "full"
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
47
|
+
Requires-Dist: anndata>=0.10; extra == "dev"
|
|
48
|
+
Requires-Dist: mudata>=0.2; extra == "dev"
|
|
49
|
+
Requires-Dist: zstandard>=0.20; extra == "dev"
|
|
50
|
+
Requires-Dist: pysam>=0.22; extra == "dev"
|
|
51
|
+
Requires-Dist: pyBigWig>=0.3; extra == "dev"
|
|
52
|
+
Requires-Dist: torch>=2.0; extra == "dev"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# cytome
|
|
56
|
+
|
|
57
|
+
**A single-file format for single-cell multi-omics data.**
|
|
58
|
+
|
|
59
|
+
`cytome` replaces ad-hoc file stacks with one SQLite-backed `.cytome` file that keeps matrices, metadata, embeddings, fragments, and provenance together.
|
|
60
|
+
|
|
61
|
+
`cytome` stores expression matrices, cell metadata, genomic fragments, embeddings, graphs, and computational provenance in a single SQLite file. It opens from manifest metadata, supports SQL-style metadata filtering, and provides a tested CLI for conversion, merge, subset, export, and validation.
|
|
62
|
+
|
|
63
|
+
`cytome` is part of the [PIASO](https://piaso.org) toolkit for single-cell analysis. PIASO natively supports cytome datasets for streaming single-cell ATAC-seq and RNA-seq workflows.
|
|
64
|
+
|
|
65
|
+
## Why cytome?
|
|
66
|
+
|
|
67
|
+
| Capability | AnnData (`.h5ad`) | BPCells | TileDB-SOMA | cytome (`.cytome`) |
|
|
68
|
+
|---|---:|---:|---:|---:|
|
|
69
|
+
| Single portable file | Yes | No (directory layout) | No (array store) | Yes |
|
|
70
|
+
| Python stdlib core storage dependency | No (`h5py`) | No | No | Yes (`sqlite3`) |
|
|
71
|
+
| SQL metadata queries | No | No | Limited via APIs | Yes |
|
|
72
|
+
| Fragment genomic range queries | No native index | Limited | Yes | Yes (SQLite R-tree) |
|
|
73
|
+
| Native provenance table | No | No | Partial workflow metadata | Yes |
|
|
74
|
+
| Streaming merge API | Partial | Strong compute streaming | Distributed workflows | Yes, chunk-aware |
|
|
75
|
+
| Full matrix load speed | Fast | Fast | Varies | Fast |
|
|
76
|
+
| Cloud-native multi-writer scale-out | No | No | Yes | No (single-writer SQLite) |
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
No optional dependencies — this runs with `pip install cytome` alone.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import cytome
|
|
84
|
+
import numpy as np
|
|
85
|
+
import pandas as pd
|
|
86
|
+
import scipy.sparse as sp
|
|
87
|
+
|
|
88
|
+
rng = np.random.default_rng(0)
|
|
89
|
+
counts = sp.random(1000, 500, density=0.05, format="csr", dtype=np.float32,
|
|
90
|
+
random_state=rng)
|
|
91
|
+
|
|
92
|
+
ds = cytome.create("example.cytome")
|
|
93
|
+
ds.set_entity("cells", pd.DataFrame({
|
|
94
|
+
"barcode": [f"cell_{i}" for i in range(1000)],
|
|
95
|
+
"cell_type": rng.choice(["A", "B"], 1000),
|
|
96
|
+
}))
|
|
97
|
+
ds.set_entity("genes", pd.DataFrame({"gene_id": [f"G{i}" for i in range(500)]}))
|
|
98
|
+
ds.add_matrix("RNA_counts", counts)
|
|
99
|
+
ds.flush()
|
|
100
|
+
|
|
101
|
+
print(ds) # metadata-first summary
|
|
102
|
+
b_cells = ds.cells.query("cell_type == 'B'") # SQL-style metadata query
|
|
103
|
+
block = ds.RNA.counts[:100, :50] # random access
|
|
104
|
+
for start, end, chunk in ds.RNA.counts.iter_rows():
|
|
105
|
+
... # bounded-memory streaming
|
|
106
|
+
ds.close()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Marker genes, straight off the file
|
|
110
|
+
|
|
111
|
+
[COSG](https://github.com/genecell/COSG) reads a `.cytome` in chunks, so peak
|
|
112
|
+
memory does not scale with the number of cells and nothing is converted to
|
|
113
|
+
AnnData first.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
# pip install cosg
|
|
117
|
+
import cosg
|
|
118
|
+
|
|
119
|
+
markers = cosg.cosg("example.cytome", groupby="cell_type",
|
|
120
|
+
modality="RNA", layer="log1p", n_genes_user=10)
|
|
121
|
+
markers["names"] # per-cell-type marker genes
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Coming from AnnData
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# pip install "cytome[anndata]"
|
|
128
|
+
ds = cytome.from_anndata(adata, modality="RNA", output="rna.cytome")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Key features
|
|
132
|
+
|
|
133
|
+
- Instant metadata-first open (`CytomeDataset` initialization reads manifest and table metadata)
|
|
134
|
+
- SQL-queryable entity tables (`cells`, `genes`, `peaks`, `samples`)
|
|
135
|
+
- Merge, subset, and downsample APIs with chunk-aware implementations
|
|
136
|
+
- Fragment storage (chunked, compressed) with genomic range queries and export
|
|
137
|
+
(bulk fragment **import** is provided by [PIASO](https://piaso.org) —
|
|
138
|
+
`piaso.pp.importFragments`)
|
|
139
|
+
- Analysis results live on the file: embeddings (`ds.embeddings`), neighbor
|
|
140
|
+
graphs (`ds.graphs`), per-cell / per-feature columns, and arbitrary analysis
|
|
141
|
+
artifacts (`ds.metadata`) — PIASO writes results back onto the cytome
|
|
142
|
+
- Provenance logging with parameters, dependency versions, and methods-text export
|
|
143
|
+
- ACID write transactions via SQLite
|
|
144
|
+
- Multi-modal naming convention (`RNA_counts`, `ATAC_counts`, etc.)
|
|
145
|
+
- Optional CSC feature index (`build_feature_index`) for faster column iteration
|
|
146
|
+
- JSON metadata store (`ds.metadata`) for arbitrary nested analysis metadata
|
|
147
|
+
- CLI (`cytome`) for convert, info, merge, subset, downsample, export, validate, provenance, and copy
|
|
148
|
+
|
|
149
|
+
## Installation
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
pip install cytome
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Optional extras:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pip install "cytome[full]"
|
|
159
|
+
pip install "cytome[dev]"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Usage examples
|
|
163
|
+
|
|
164
|
+
### Convert from AnnData
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
import cytome
|
|
168
|
+
ds = cytome.from_anndata(adata, modality="RNA", output="rna.cytome")
|
|
169
|
+
ds.close()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Open and query
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import cytome
|
|
176
|
+
ds = cytome.open("rna.cytome")
|
|
177
|
+
cd8 = ds.cells.query("cell_type == 'CD8 T'")
|
|
178
|
+
x = ds.RNA.counts[:200, :200]
|
|
179
|
+
ds.close()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Merge datasets
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
import cytome
|
|
186
|
+
merged = cytome.merge(["s1.cytome", "s2.cytome"], output="merged.cytome")
|
|
187
|
+
merged.close()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Command line
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
cytome info merged.cytome
|
|
194
|
+
cytome merge s1.cytome s2.cytome -o merged.cytome
|
|
195
|
+
cytome subset merged.cytome -o cd8.cytome --query "cell_type == 'CD8 T'"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### ATAC fragments
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
ds = cytome.open("multiome.cytome")
|
|
202
|
+
fr = ds.ATAC.fragments.query_region("chr1", 1_000_000, 2_000_000)
|
|
203
|
+
ds.ATAC.fragments.export("fragments.tsv.gz")
|
|
204
|
+
ds.close()
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### With PIASO
|
|
208
|
+
|
|
209
|
+
`cytome` integrates with [PIASO](https://piaso.org) (`pip install piaso-tools`) for
|
|
210
|
+
single-cell analysis. PIASO supports cytome datasets directly — streaming normalization,
|
|
211
|
+
dimensionality reduction, clustering, and visualization without loading full matrices
|
|
212
|
+
into memory.
|
|
213
|
+
|
|
214
|
+
PIASO functions are **self-contained on a cytome**: they stream from the file
|
|
215
|
+
and write their results back onto it (graphs, embeddings, cluster labels,
|
|
216
|
+
per-cell/per-feature metrics, markers) — they don't return large objects, so you
|
|
217
|
+
read results from the dataset afterwards.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
import cytome
|
|
221
|
+
import piaso
|
|
222
|
+
|
|
223
|
+
# Open a cytome dataset and run the PIASO ATAC pipeline (results persist on ds)
|
|
224
|
+
ds = cytome.open("atac.cytome")
|
|
225
|
+
|
|
226
|
+
piaso.pp.calculateCellMetrics(ds) # per-cell QC -> ds.cells
|
|
227
|
+
piaso.pp.selectPeaks(ds) # highly variable peaks -> ds.peaks
|
|
228
|
+
piaso.tl.runSVDLazy(ds) # X_svd embedding -> ds.embeddings
|
|
229
|
+
piaso.tl.neighbors(ds) # connectivities/distances -> ds.graphs
|
|
230
|
+
piaso.tl.leiden(ds, key_added="leiden") # labels -> ds.cells["leiden"]
|
|
231
|
+
piaso.tl.umap(ds) # X_umap -> ds.embeddings
|
|
232
|
+
piaso.pl.plotUMAP(ds, color="leiden")
|
|
233
|
+
|
|
234
|
+
# Markers + peak calling can persist to the cytome too
|
|
235
|
+
import cosg
|
|
236
|
+
cosg.run_cosg_cytome(ds, groupby="leiden", modality="ATAC",
|
|
237
|
+
write_to_cytome=True) # -> ds.metadata["cosg"]
|
|
238
|
+
piaso.tl.picco(ds, groupby="leiden", genome="mm10") # PICCO peak calling
|
|
239
|
+
|
|
240
|
+
ds.close()
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
See [piaso.org](https://piaso.org) for documentation and tutorials.
|
|
244
|
+
|
|
245
|
+
## File format
|
|
246
|
+
|
|
247
|
+
A `.cytome` file is a SQLite database with:
|
|
248
|
+
|
|
249
|
+
- Entity tables (`cells`, `genes`, `peaks`, ...)
|
|
250
|
+
- Chunked compressed sparse matrices (`matrix_chunks` + `matrix_meta`)
|
|
251
|
+
- Optional CSC chunks (`matrix_csc_chunks`)
|
|
252
|
+
- Dense chunked embeddings (`dense_chunks` + `embedding_meta`)
|
|
253
|
+
- Fragment storage (chunked compressed BLOBs) + genomic R-tree indices
|
|
254
|
+
- Provenance (`_provenance`) and metadata (`_metadata`)
|
|
255
|
+
|
|
256
|
+
## Comparison with existing tools
|
|
257
|
+
|
|
258
|
+
Trade-offs in the current implementation:
|
|
259
|
+
|
|
260
|
+
- Full matrix materialization can be slower than direct HDF5 reads for some workloads.
|
|
261
|
+
- Merge/subset APIs are chunk-aware, but current merge implementation may still materialize intermediate matrices for gene remapping.
|
|
262
|
+
- SQLite provides strong local reliability and portability but is not a distributed/cloud-native storage engine.
|
|
263
|
+
|
|
264
|
+
## Citation
|
|
265
|
+
|
|
266
|
+
If you use `cytome`, please cite the upcoming manuscript.
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
BSD 3-Clause License. See [LICENSE](LICENSE) for details.
|
cytome-0.2.2/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# cytome
|
|
2
|
+
|
|
3
|
+
**A single-file format for single-cell multi-omics data.**
|
|
4
|
+
|
|
5
|
+
`cytome` replaces ad-hoc file stacks with one SQLite-backed `.cytome` file that keeps matrices, metadata, embeddings, fragments, and provenance together.
|
|
6
|
+
|
|
7
|
+
`cytome` stores expression matrices, cell metadata, genomic fragments, embeddings, graphs, and computational provenance in a single SQLite file. It opens from manifest metadata, supports SQL-style metadata filtering, and provides a tested CLI for conversion, merge, subset, export, and validation.
|
|
8
|
+
|
|
9
|
+
`cytome` is part of the [PIASO](https://piaso.org) toolkit for single-cell analysis. PIASO natively supports cytome datasets for streaming single-cell ATAC-seq and RNA-seq workflows.
|
|
10
|
+
|
|
11
|
+
## Why cytome?
|
|
12
|
+
|
|
13
|
+
| Capability | AnnData (`.h5ad`) | BPCells | TileDB-SOMA | cytome (`.cytome`) |
|
|
14
|
+
|---|---:|---:|---:|---:|
|
|
15
|
+
| Single portable file | Yes | No (directory layout) | No (array store) | Yes |
|
|
16
|
+
| Python stdlib core storage dependency | No (`h5py`) | No | No | Yes (`sqlite3`) |
|
|
17
|
+
| SQL metadata queries | No | No | Limited via APIs | Yes |
|
|
18
|
+
| Fragment genomic range queries | No native index | Limited | Yes | Yes (SQLite R-tree) |
|
|
19
|
+
| Native provenance table | No | No | Partial workflow metadata | Yes |
|
|
20
|
+
| Streaming merge API | Partial | Strong compute streaming | Distributed workflows | Yes, chunk-aware |
|
|
21
|
+
| Full matrix load speed | Fast | Fast | Varies | Fast |
|
|
22
|
+
| Cloud-native multi-writer scale-out | No | No | Yes | No (single-writer SQLite) |
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
No optional dependencies — this runs with `pip install cytome` alone.
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import cytome
|
|
30
|
+
import numpy as np
|
|
31
|
+
import pandas as pd
|
|
32
|
+
import scipy.sparse as sp
|
|
33
|
+
|
|
34
|
+
rng = np.random.default_rng(0)
|
|
35
|
+
counts = sp.random(1000, 500, density=0.05, format="csr", dtype=np.float32,
|
|
36
|
+
random_state=rng)
|
|
37
|
+
|
|
38
|
+
ds = cytome.create("example.cytome")
|
|
39
|
+
ds.set_entity("cells", pd.DataFrame({
|
|
40
|
+
"barcode": [f"cell_{i}" for i in range(1000)],
|
|
41
|
+
"cell_type": rng.choice(["A", "B"], 1000),
|
|
42
|
+
}))
|
|
43
|
+
ds.set_entity("genes", pd.DataFrame({"gene_id": [f"G{i}" for i in range(500)]}))
|
|
44
|
+
ds.add_matrix("RNA_counts", counts)
|
|
45
|
+
ds.flush()
|
|
46
|
+
|
|
47
|
+
print(ds) # metadata-first summary
|
|
48
|
+
b_cells = ds.cells.query("cell_type == 'B'") # SQL-style metadata query
|
|
49
|
+
block = ds.RNA.counts[:100, :50] # random access
|
|
50
|
+
for start, end, chunk in ds.RNA.counts.iter_rows():
|
|
51
|
+
... # bounded-memory streaming
|
|
52
|
+
ds.close()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Marker genes, straight off the file
|
|
56
|
+
|
|
57
|
+
[COSG](https://github.com/genecell/COSG) reads a `.cytome` in chunks, so peak
|
|
58
|
+
memory does not scale with the number of cells and nothing is converted to
|
|
59
|
+
AnnData first.
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
# pip install cosg
|
|
63
|
+
import cosg
|
|
64
|
+
|
|
65
|
+
markers = cosg.cosg("example.cytome", groupby="cell_type",
|
|
66
|
+
modality="RNA", layer="log1p", n_genes_user=10)
|
|
67
|
+
markers["names"] # per-cell-type marker genes
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Coming from AnnData
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# pip install "cytome[anndata]"
|
|
74
|
+
ds = cytome.from_anndata(adata, modality="RNA", output="rna.cytome")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Key features
|
|
78
|
+
|
|
79
|
+
- Instant metadata-first open (`CytomeDataset` initialization reads manifest and table metadata)
|
|
80
|
+
- SQL-queryable entity tables (`cells`, `genes`, `peaks`, `samples`)
|
|
81
|
+
- Merge, subset, and downsample APIs with chunk-aware implementations
|
|
82
|
+
- Fragment storage (chunked, compressed) with genomic range queries and export
|
|
83
|
+
(bulk fragment **import** is provided by [PIASO](https://piaso.org) —
|
|
84
|
+
`piaso.pp.importFragments`)
|
|
85
|
+
- Analysis results live on the file: embeddings (`ds.embeddings`), neighbor
|
|
86
|
+
graphs (`ds.graphs`), per-cell / per-feature columns, and arbitrary analysis
|
|
87
|
+
artifacts (`ds.metadata`) — PIASO writes results back onto the cytome
|
|
88
|
+
- Provenance logging with parameters, dependency versions, and methods-text export
|
|
89
|
+
- ACID write transactions via SQLite
|
|
90
|
+
- Multi-modal naming convention (`RNA_counts`, `ATAC_counts`, etc.)
|
|
91
|
+
- Optional CSC feature index (`build_feature_index`) for faster column iteration
|
|
92
|
+
- JSON metadata store (`ds.metadata`) for arbitrary nested analysis metadata
|
|
93
|
+
- CLI (`cytome`) for convert, info, merge, subset, downsample, export, validate, provenance, and copy
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install cytome
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Optional extras:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pip install "cytome[full]"
|
|
105
|
+
pip install "cytome[dev]"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Usage examples
|
|
109
|
+
|
|
110
|
+
### Convert from AnnData
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
import cytome
|
|
114
|
+
ds = cytome.from_anndata(adata, modality="RNA", output="rna.cytome")
|
|
115
|
+
ds.close()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Open and query
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import cytome
|
|
122
|
+
ds = cytome.open("rna.cytome")
|
|
123
|
+
cd8 = ds.cells.query("cell_type == 'CD8 T'")
|
|
124
|
+
x = ds.RNA.counts[:200, :200]
|
|
125
|
+
ds.close()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Merge datasets
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import cytome
|
|
132
|
+
merged = cytome.merge(["s1.cytome", "s2.cytome"], output="merged.cytome")
|
|
133
|
+
merged.close()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Command line
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cytome info merged.cytome
|
|
140
|
+
cytome merge s1.cytome s2.cytome -o merged.cytome
|
|
141
|
+
cytome subset merged.cytome -o cd8.cytome --query "cell_type == 'CD8 T'"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### ATAC fragments
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
ds = cytome.open("multiome.cytome")
|
|
148
|
+
fr = ds.ATAC.fragments.query_region("chr1", 1_000_000, 2_000_000)
|
|
149
|
+
ds.ATAC.fragments.export("fragments.tsv.gz")
|
|
150
|
+
ds.close()
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### With PIASO
|
|
154
|
+
|
|
155
|
+
`cytome` integrates with [PIASO](https://piaso.org) (`pip install piaso-tools`) for
|
|
156
|
+
single-cell analysis. PIASO supports cytome datasets directly — streaming normalization,
|
|
157
|
+
dimensionality reduction, clustering, and visualization without loading full matrices
|
|
158
|
+
into memory.
|
|
159
|
+
|
|
160
|
+
PIASO functions are **self-contained on a cytome**: they stream from the file
|
|
161
|
+
and write their results back onto it (graphs, embeddings, cluster labels,
|
|
162
|
+
per-cell/per-feature metrics, markers) — they don't return large objects, so you
|
|
163
|
+
read results from the dataset afterwards.
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import cytome
|
|
167
|
+
import piaso
|
|
168
|
+
|
|
169
|
+
# Open a cytome dataset and run the PIASO ATAC pipeline (results persist on ds)
|
|
170
|
+
ds = cytome.open("atac.cytome")
|
|
171
|
+
|
|
172
|
+
piaso.pp.calculateCellMetrics(ds) # per-cell QC -> ds.cells
|
|
173
|
+
piaso.pp.selectPeaks(ds) # highly variable peaks -> ds.peaks
|
|
174
|
+
piaso.tl.runSVDLazy(ds) # X_svd embedding -> ds.embeddings
|
|
175
|
+
piaso.tl.neighbors(ds) # connectivities/distances -> ds.graphs
|
|
176
|
+
piaso.tl.leiden(ds, key_added="leiden") # labels -> ds.cells["leiden"]
|
|
177
|
+
piaso.tl.umap(ds) # X_umap -> ds.embeddings
|
|
178
|
+
piaso.pl.plotUMAP(ds, color="leiden")
|
|
179
|
+
|
|
180
|
+
# Markers + peak calling can persist to the cytome too
|
|
181
|
+
import cosg
|
|
182
|
+
cosg.run_cosg_cytome(ds, groupby="leiden", modality="ATAC",
|
|
183
|
+
write_to_cytome=True) # -> ds.metadata["cosg"]
|
|
184
|
+
piaso.tl.picco(ds, groupby="leiden", genome="mm10") # PICCO peak calling
|
|
185
|
+
|
|
186
|
+
ds.close()
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
See [piaso.org](https://piaso.org) for documentation and tutorials.
|
|
190
|
+
|
|
191
|
+
## File format
|
|
192
|
+
|
|
193
|
+
A `.cytome` file is a SQLite database with:
|
|
194
|
+
|
|
195
|
+
- Entity tables (`cells`, `genes`, `peaks`, ...)
|
|
196
|
+
- Chunked compressed sparse matrices (`matrix_chunks` + `matrix_meta`)
|
|
197
|
+
- Optional CSC chunks (`matrix_csc_chunks`)
|
|
198
|
+
- Dense chunked embeddings (`dense_chunks` + `embedding_meta`)
|
|
199
|
+
- Fragment storage (chunked compressed BLOBs) + genomic R-tree indices
|
|
200
|
+
- Provenance (`_provenance`) and metadata (`_metadata`)
|
|
201
|
+
|
|
202
|
+
## Comparison with existing tools
|
|
203
|
+
|
|
204
|
+
Trade-offs in the current implementation:
|
|
205
|
+
|
|
206
|
+
- Full matrix materialization can be slower than direct HDF5 reads for some workloads.
|
|
207
|
+
- Merge/subset APIs are chunk-aware, but current merge implementation may still materialize intermediate matrices for gene remapping.
|
|
208
|
+
- SQLite provides strong local reliability and portability but is not a distributed/cloud-native storage engine.
|
|
209
|
+
|
|
210
|
+
## Citation
|
|
211
|
+
|
|
212
|
+
If you use `cytome`, please cite the upcoming manuscript.
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
BSD 3-Clause License. See [LICENSE](LICENSE) for details.
|