| Title: | Native R Reader and Streaming Interface for the Cytome Single-Cell Store |
|---|---|
| Description: | Reads .cytome files - a SQLite-backed single-cell store - natively in R with zero Python dependency. A .cytome is a plain SQLite database, so the structural data (cells / genes / peaks, embeddings, graphs, fragments) is read with DBI; the chunked, compressed CSR count matrices are decoded via a small Rcpp layer (lz4-block / zstd / zlib). Constructs a SingleCellExperiment or a Seurat object, and provides cytome-native chunk streaming for out-of-core analysis without loading the full matrix. Part of the PIASO toolkit for single-cell omics (<https://piaso.org>). |
| Authors: | Min Dai [aut, cre], PIASO Team [cph] |
| Maintainer: | Min Dai <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.3 |
| Built: | 2026-09-29 02:09:52 UTC |
| Source: | https://github.com/genecell/cytome-r |
A '.cytome' file is a plain SQLite database. 'cytome' opens it read-only with DBI, reads the relational tables (cells / genes / peaks, embeddings, graphs, fragments) directly, and decodes the chunked compressed CSR count matrices via a small Rcpp layer (lz4-block / zstd / zlib) — with zero Python dependency.
Close a cytome handle
cytome_close(x)cytome_close(x)
x |
A 'cytome' handle from [cytome_open()]. |
Returns a [DelayedArray::DelayedArray] backed by the file: nothing is read until something asks for values, and block-processing code ('DelayedMatrixStats', 'scuttle', 'scran', ...) then works on a matrix that never has to be held whole.
cytome_delayed(path, matrix_name)cytome_delayed(path, matrix_name)
path |
Path to a '.cytome' file. |
matrix_name |
Matrix to wrap, e.g. '"RNA_counts"'. |
Extraction is **chunk-aligned**: only the storage chunks overlapping the requested cells are read, and 'chunkdim()' reports the storage geometry so DelayedArray's block grid lands on chunk boundaries rather than straddling them. Peak memory is therefore set by the block size, not by the size of the matrix.
For data that fits comfortably in memory, 'delayed = FALSE' is faster – the reason to use this is data that does not fit, and code you did not write ('scran', 'scuttle', 'DelayedMatrixStats') that must run on it.
Requires the suggested 'DelayedArray', 'S4Arrays' and 'SparseArray' packages.
A 'DelayedArray', features x cells.
[read_cytome()] with 'delayed = TRUE', [cytome_stream()]
ref <- system.file("extdata", "reference.cytome", package = "cytome") if (nzchar(ref) && requireNamespace("DelayedArray", quietly = TRUE)) { m <- cytome_delayed(ref, "RNA_counts") dim(m) }ref <- system.file("extdata", "reference.cytome", package = "cytome") if (nzchar(ref) && requireNamespace("DelayedArray", quietly = TRUE)) { m <- cytome_delayed(ref, "RNA_counts") dim(m) }
Embeddings are stored as dense, row-major, compressed chunks ('dense_chunks').
cytome_embedding(x, name)cytome_embedding(x, name)
x |
A 'cytome' handle. |
name |
Embedding name, e.g. '"X_umap"' (see [cytome_embeddings()]). |
A numeric matrix (cells x n_cols) with cell barcodes as row names when available.
List embeddings stored in a cytome
cytome_embeddings(x)cytome_embeddings(x)
x |
A 'cytome' handle. |
Character vector of embedding/array names (from 'embedding_meta').
Fragments are stored per chromosome in 'fragments_<chrom>' tables (columns 'start, end_, cell_idx, dup_count') with an SQLite R*-tree index, so interval queries are fast and native — no Python.
cytome_fragments(x, chrom, start = NULL, end = NULL, with_barcode = TRUE)cytome_fragments(x, chrom, start = NULL, end = NULL, with_barcode = TRUE)
x |
A 'cytome' handle. |
chrom |
Chromosome, e.g. '"chr1"'. |
start, end
|
Optional 0-based half-open interval '[start, end)'. If both 'NULL', returns all fragments on 'chrom'. |
with_barcode |
If 'TRUE' (default), join 'cell_idx' to the cell 'barcode'. |
A data.frame: chrom, start, end, cell_idx, [barcode], dup_count.
Read one graph as a sparse matrix
cytome_graph(x, name, n = NULL)cytome_graph(x, name, n = NULL)
x |
A 'cytome' handle. |
name |
Graph name, from [cytome_graphs()]. |
n |
Square dimension; defaults to the stored shape, or the cell count for a graph stored one row per edge. |
A [Matrix::dgCMatrix-class], cells x cells.
Lists the cell-by-cell graphs of a store, in either form the Python package writes: compressed row chunks ('graph_meta' / 'graph_chunks', cytome 0.3.6 and later), and one row per edge ('graph_edges', earlier versions and this package's own writer).
cytome_graphs(x)cytome_graphs(x)
x |
A 'cytome' handle. |
A character vector of graph names.
High-level summary of a cytome
cytome_info(x)cytome_info(x)
x |
A 'cytome' handle. |
Matrix catalogue (from 'matrix_meta')
cytome_matrices(x)cytome_matrices(x)
x |
A 'cytome' handle. |
A data.frame: matrix_name, n_rows, n_cols, dtype, row_entity, col_entity.
Read an entity table (cells / genes / peaks / tiles / samples) as a data.frame
cytome_obs(x, entity = "cells")cytome_obs(x, entity = "cells")
x |
A 'cytome' handle. |
entity |
Entity table name. Default '"cells"' (obs). Use '"genes"'/'"peaks"' for var. |
A data.frame.
Open a .cytome file (read-only)
cytome_open(path)cytome_open(path)
path |
Path to a '.cytome' SQLite file. |
A 'cytome' handle (a list with the open DBI connection). Close with [cytome_close()].
Iterates the matrix's stored chunks, decoding **one chunk at a time** into a sparse sub-matrix and passing it to 'FUN' — so you can compute over a matrix far larger than RAM without ever materialising the whole thing, directly from the cytome format (no BPCells or other backend required). This is the foundation for R-side streaming single-cell analysis.
cytome_stream(x, name, FUN, features_x_cells = FALSE, ...)cytome_stream(x, name, FUN, features_x_cells = FALSE, ...)
x |
A 'cytome' handle. |
name |
Matrix name, e.g. '"RNA_counts"'. |
FUN |
A function called per chunk as 'FUN(mat, row_start, row_end, chunk_idx, ...)', where ‘mat' is the chunk’s sparse sub-matrix. |
features_x_cells |
If 'TRUE' each chunk is features x cells; else cells x features (default). |
... |
Extra arguments passed to 'FUN'. |
A list of the per-chunk return values of 'FUN' (reduce as you wish).
## Not run: x <- cytome_open("data.cytome") # per-cell total counts without loading the whole matrix: totals <- cytome_stream(x, "RNA_counts", function(m, s, e, i) Matrix::rowSums(m)) totals <- unlist(totals) ## End(Not run)## Not run: x <- cytome_open("data.cytome") # per-cell total counts without loading the whole matrix: totals <- cytome_stream(x, "RNA_counts", function(m, s, e, i) Matrix::rowSums(m)) totals <- unlist(totals) ## End(Not run)
Resolves the matrix's 'col_entity' (e.g. 'RNA_counts' -> 'genes', 'ATAC_counts' -> 'peaks').
cytome_var(x, matrix_name = NULL)cytome_var(x, matrix_name = NULL)
x |
A 'cytome' handle. |
matrix_name |
Matrix name, e.g. '"RNA_counts"'. If 'NULL', returns the 'genes' table. |
A data.frame of features.
One entry point. 'as' chooses what you get back, mirroring 'anndataR::read_h5ad(path, as = ...)':
read_cytome( path, as = c("SingleCellExperiment", "Seurat", "cytome"), main_modality = "RNA", alt_modalities = NULL, embeddings = TRUE, delayed = FALSE, ... )read_cytome( path, as = c("SingleCellExperiment", "Seurat", "cytome"), main_modality = "RNA", alt_modalities = NULL, embeddings = TRUE, delayed = FALSE, ... )
path |
Path to a '.cytome' file. |
as |
What to return. See above. |
main_modality |
Modality for the main assay (default '"RNA"'). |
alt_modalities |
Modalities to bring across as 'altExps' / extra assays. 'NULL' (default) = all other '_counts' matrices; 'character(0)' = none. |
embeddings |
If 'TRUE' (default) load embeddings. |
delayed |
If 'TRUE', back the main assay with a [DelayedArray::DelayedArray] that reads chunks from the file on demand, so the matrix is never held in memory. 'SingleCellExperiment' only, and experimental – see [cytome_delayed()]. |
... |
Passed to the underlying reader. |
* '"SingleCellExperiment"' (default) – main modality as the main assay, other modalities as 'altExps', embeddings as 'reducedDims'. * '"Seurat"' – main modality as the default assay, other modalities as extra assays, embeddings as 'DimReduc's. * '"cytome"' – the open handle itself, for chunk-wise work with [cytome_stream()]. Close it with [cytome_close()] when done.
A 'SingleCellExperiment', a 'Seurat' object, or a 'cytome' handle.
[write_cytome()], [cytome_stream()], [cytome_delayed()]
ref <- system.file("extdata", "reference.cytome", package = "cytome") if (nzchar(ref)) { x <- read_cytome(ref, as = "cytome") print(x) cytome_close(x) }ref <- system.file("extdata", "reference.cytome", package = "cytome") if (nzchar(ref)) { x <- read_cytome(ref, as = "cytome") print(x) cytome_close(x) }
Reconstructs the chunked, compressed CSR matrix (stored cells x features) and returns it, by default transposed to **features x cells** (the orientation of an assay in SingleCellExperiment / Seurat).
read_cytome_matrix(x, name, features_x_cells = TRUE)read_cytome_matrix(x, name, features_x_cells = TRUE)
x |
A 'cytome' handle. |
name |
Matrix name, e.g. '"RNA_counts"' (see [cytome_matrices()]). |
features_x_cells |
If 'TRUE' (default) return features x cells; else cells x features. |
A [Matrix::dgCMatrix-class].
Generic. The method is chosen from the class of 'x', so the same call works whether you are holding a Seurat object or a SingleCellExperiment – the thing you would otherwise have to look up is the thing R already knows. Third-party packages can add methods for their own classes.
write_cytome(x, path, ...)write_cytome(x, path, ...)
x |
A 'Seurat' or 'SingleCellExperiment' object. |
path |
Output '.cytome' path. |
... |
Passed to the method. |
'path', invisibly. The file is readable by Python 'cytome.open(path)'.
[read_cytome()]
## Not run: write_cytome(seurat_obj, "out.cytome") write_cytome(sce, "out.cytome") ## End(Not run)## Not run: write_cytome(seurat_obj, "out.cytome") write_cytome(sce, "out.cytome") ## End(Not run)
Write a Seurat object to a '.cytome' file
## S3 method for class 'Seurat' write_cytome( x, path, assay = NULL, layer = "counts", alt_assays = NULL, layers = FALSE, graphs = TRUE, dtype = "float32", chunk_size = 2000L, compression = "zstd", embeddings = TRUE, ... )## S3 method for class 'Seurat' write_cytome( x, path, assay = NULL, layer = "counts", alt_assays = NULL, layers = FALSE, graphs = TRUE, dtype = "float32", chunk_size = 2000L, compression = "zstd", embeddings = TRUE, ... )
x |
A 'Seurat' object. |
path |
Output '.cytome' path. |
assay |
Assay for the main modality (default the object's default assay). |
layer |
Layer/slot to store (default '"counts"'). |
alt_assays |
Other assays to write as extra modalities. 'NULL' (default) writes all of them; 'character(0)' writes none. |
layers |
Other layers of the main assay ('data', 'scale.data') to carry. 'FALSE' (default), 'TRUE', or name them. See the 'SingleCellExperiment' method for why this is off by default. |
graphs |
Write the 'graphs' slot to the shared 'graph_edges' table (default 'TRUE'). |
dtype, chunk_size, compression, embeddings
|
As for the 'SingleCellExperiment' method. |
... |
Unused. |
'path', invisibly.
Write a SingleCellExperiment to a '.cytome' file
## S3 method for class 'SingleCellExperiment' write_cytome( x, path, assay = "counts", main_modality = "RNA", alt_modalities = NULL, layers = FALSE, graphs = TRUE, dtype = "float32", chunk_size = 2000L, compression = "zstd", embeddings = TRUE, ... )## S3 method for class 'SingleCellExperiment' write_cytome( x, path, assay = "counts", main_modality = "RNA", alt_modalities = NULL, layers = FALSE, graphs = TRUE, dtype = "float32", chunk_size = 2000L, compression = "zstd", embeddings = TRUE, ... )
x |
A [SingleCellExperiment::SingleCellExperiment]. |
path |
Output '.cytome' path. |
assay |
Assay to store as the main counts matrix (default '"counts"'). |
main_modality |
Modality name for the main assay (default '"RNA"'). |
alt_modalities |
'altExp' names to write as extra modalities. 'NULL' (default) writes all of them; 'character(0)' writes none. |
layers |
Additional assays of the main experiment to carry. 'FALSE' (default) writes none, 'TRUE' writes all, or name them. Off by default because normalized values are recomputable from the counts and cost more space than the counts do; turn it on when the point is to hand somebody your object rather than to archive the measurements. |
graphs |
Write 'colPairs' to the shared 'graph_edges' table (default 'TRUE'). A neighbour graph is the expensive thing to recompute, and carrying it means the recipient reproduces the same clusters. |
dtype |
'"float32"' (default) or '"float64"'. |
chunk_size |
Rows (cells) per storage chunk. |
compression |
'"zstd"' (default), '"lz4"', or '"zlib"'. |
embeddings |
Store 'reducedDims' (default 'TRUE'). |
... |
Unused. |
'path', invisibly.