Objects¶
The container, before any analysis touches it. Truecell holds one or more assays,
the reductions computed off them, the neighbour graphs, the per-cell metadata and
the command log — the same slots R's Seurat S4 class holds, as ordinary Python
classes with __slots__.
The one structural difference worth knowing up front: R's Assay5 inherits from
dgCMatrix; here Assay5 wraps a SciPy CSC matrix rather than subclassing it,
because subclassing scipy.sparse is a well-known trap. Everything you reach
through the generics behaves the same either way.
The object model is checked against Seurat anchor by anchor in The Object Model Itself — 91 of 91 exact, no tolerance.
The top-level object¶
Truecell
¶
Truecell(assays: dict[str, AnyAssay], meta_data: DataFrame, active_assay: str, active_ident: Optional[Categorical] = None, graphs: Optional[dict[str, Graph]] = None, neighbors: Optional[dict[str, Neighbor]] = None, reductions: Optional[dict[str, DimReduc]] = None, images: Optional[dict[str, FOV]] = None, project_name: str = 'SeuratProject', misc: Optional[dict] = None, version: Optional[Version] = None, commands: Optional[list[TruecellCommand]] = None, tools: Optional[dict] = None)
Top-level Truecell single-cell data object.
Mirrors R's Seurat class from seurat.R.
Slots
assays(dict[str, AnyAssay])meta_data(pd.DataFrame) — cells × metadata columnsactive_assay(str)active_ident(pd.Categorical)graphs(dict[str, Graph])neighbors(dict[str, Neighbor])reductions(dict[str, DimReduc])images(dict[str, FOV])project_name(str)misc(dict)version(packaging.version.Version)commands(list[TruecellCommand])tools(dict)
Source code in truecell/truecell.py
image_names
¶
get_tissue_coordinates
¶
Centroid coordinates across images (mirrors GetTissueCoordinates).
Returns a DataFrame with columns x, y, cell, image.
Source code in truecell/truecell.py
reorder_ident
¶
Reorder the identity levels by a per-ident summary of var.
Mirrors R's ReorderIdent(object, var, reverse = FALSE, afxn = mean):
fetch var for every cell (a gene or a metadata column — anything
fetch_data accepts), summarise it within each identity with
afxn, and sort the levels by that summary, ascending.
Divergence, deliberate: R's reverse does nothing. It applies
max(x) + 1 - x to the values of an already-sorted named vector and
then reads names() off the result — which leaves the element order
untouched, so the levels come back identical. Verified on Seurat 5.5.1:
the same D,B,A,C with and without it. Here reverse=True
genuinely reverses, because the alternative is shipping another argument
that silently does nothing.
R's reorder.numeric is not ported. It renames every identity to a
rank, and on 5.5.1 it warns Cannot find cells provided and leaves the
levels unchanged, so there is no working behaviour to match.
Source code in truecell/truecell.py
subset
¶
subset(cells: Optional[list[str]] = None, features: Optional[list[str]] = None, idents: Optional[Union[str, list[str]]] = None) -> 'Truecell'
Restrict the object to cells and/or features.
Mirrors R's subset(x, cells = , features = , idents = ).
The result keeps the object's cell order whatever order cells
arrives in, as Seurat's intersect(colnames(x), cells) does. Every slot
is read by position against cell_names(), so the order is settled once,
here, before any slot is subset. Taking the caller's order used to reach
only some of them — the metadata, the assay's cell axis, the reductions and
the graphs followed the request, while every layer, the identities and the
image coordinates stayed in object order — so a reordered request paired
nCount with another cell's counts and Moran's I with another cell's
coordinates.
Identities are carried by cell name, keep their level order, and drop the
levels no retained cell carries (Idents(x, drop = TRUE)).
A name in cells that the object does not have raises KeyError.
Seurat drops it silently; a misspelt barcode is better reported.
Source code in truecell/truecell.py
create_truecell_object
¶
create_truecell_object(counts, assay: str = 'RNA', min_cells: int = 0, min_features: int = 0, project: str = 'SeuratProject', feature_names: Optional[list[str]] = None, cell_names: Optional[list[str]] = None, meta_data: Optional[DataFrame] = None, use_v5: bool = True) -> Truecell
Create a Truecell object from a counts matrix.
Mirrors R's CreateSeuratObject().
Parameters:
-
counts–sparse or dense matrix (features × cells)
-
assay(str, default:'RNA') –assay name (default "RNA")
-
min_cells(int, default:0) –min cells a feature must be detected in to be kept
-
min_features(int, default:0) –min features a cell must have to be kept
-
project(str, default:'SeuratProject') –project name
-
feature_names(Optional[list[str]], default:None) –optional list of feature (gene) names
-
cell_names(Optional[list[str]], default:None) –optional list of cell barcodes
-
meta_data(Optional[DataFrame], default:None) –optional per-cell metadata DataFrame
-
use_v5(bool, default:True) –if True, create Assay5 (v5); else Assay (v3)
Source code in truecell/truecell.py
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 | |
diet_truecell strips an object down before saving or sharing it. Note that
dimreducs and graphs are keep-lists: calling it with no arguments removes
every reduction and graph, which is Seurat's behaviour too.
diet_truecell
¶
diet_truecell(seurat, layers: Optional[Union[str, list[str], dict[str, Union[str, list[str]]]]] = None, features: Optional[list[str]] = None, assays: Optional[Union[str, list[str]]] = None, dimreducs: Optional[Union[str, list[str]]] = None, graphs: Optional[Union[str, list[str]]] = None, misc: bool = True)
Slim an object down to the pieces you name.
Mirrors R's DietSeurat(object). Returns a new object; the one passed
in is left alone, and the layers that survive are shared rather than copied,
so this frees memory rather than doubling it.
Parameters:
-
layers(Optional[Union[str, list[str], dict[str, Union[str, list[str]]]]], default:None) –layers to keep. A name or list applies to every assay; a dict (
{"RNA": "counts"}) names them per assay.Nonekeeps all. -
features(Optional[list[str]], default:None) –keep only these features. An assay left with none of them is dropped, with a warning.
-
assays(Optional[Union[str, list[str]]], default:None) –assays to keep.
Nonekeeps all. -
dimreducs(Optional[Union[str, list[str]]], default:None) –reductions to keep.
Nonekeeps none — see below. -
graphs(Optional[Union[str, list[str]]], default:None) –graphs to keep.
Nonekeeps none — see below. -
misc(bool, default:True) –Falseempties the object-levelmisc.
Returns:
-
A new ``Truecell``.–
Warning
diet_truecell(obj) with no arguments deletes every reduction and every
graph. That is R's behaviour, not a translation slip — dimreducs and
graphs are keep-lists, and an unset keep-list keeps nothing. Verified
against Seurat 5.5.1: a pbmc3k object with a pca and two graphs comes back
with zero of each, and all three layers untouched. Name what you want kept::
slim = diet_truecell(obj, layers="counts", dimreducs="pca")
Notes
- Neighbor objects are left alone, as in R:
DietSeuratfilters onlyDimReducandGraph. - A v3
Assaycannot give up bothcountsanddata— Seurat raises rather than leave the assay with no expression matrix, and so does this. - Cells are re-intersected against the surviving assays at the end, which
only bites when
featuresempties an assay and removes it.
Source code in truecell/diet.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | |
Assays¶
Assay5
¶
Assay5(layers: dict[str, Union[ndarray, spmatrix]], feature_names: list[str], cell_names: list[str], assay_orig: Optional[str] = None, meta_data: Optional[DataFrame] = None, misc: Optional[dict] = None, key: str = 'rna_', default: int = 0, layer_features: Optional[dict[str, list[str]]] = None, layer_cells: Optional[dict[str, list[str]]] = None)
Bases: StdAssay
Modern layered assay (v5).
Mirrors R's Assay5 class from assay5.R. Extends StdAssay with no additional slots.
Source code in truecell/assay5.py
create_assay5_object
¶
create_assay5_object(counts=None, data=None, min_cells: int = 0, min_features: int = 0, feature_names: Optional[list[str]] = None, cell_names: Optional[list[str]] = None, key: str = 'rna_') -> Assay5
Source code in truecell/assay5.py
StdAssay
¶
StdAssay(layers: dict[str, Union[ndarray, spmatrix]], feature_names: list[str], cell_names: list[str], assay_orig: Optional[str] = None, meta_data: Optional[DataFrame] = None, misc: Optional[dict] = None, key: str = 'rna_', default: int = 0, layer_features: Optional[dict[str, list[str]]] = None, layer_cells: Optional[dict[str, list[str]]] = None)
Bases: KeyMixin, ABC
Abstract base for layered assays (v5 architecture).
Mirrors R's StdAssay virtual class from assay5.R. Unlike the legacy Assay (v3), StdAssay stores arbitrary named layers and uses LogMap to track which cells/features belong to each layer.
Slots
layers(dict[str, AnyMatrix]) — named expression matrices (features × cells)cells(LogMap) — per-layer boolean cell membershipfeatures(LogMap) — per-layer boolean feature membershipdefault(int) — index of the default layerassay_orig(Optional[str])meta_data(pd.DataFrame) — per-feature metadatamisc(dict)_key(str) — inherited from KeyMixin
Source code in truecell/assay5.py
set_layer_data
¶
set_layer_data(layer: str, value: Union[ndarray, spmatrix], cell_names: Optional[list[str]] = None, feature_names: Optional[list[str]] = None) -> None
Store (or replace) a layer.
feature_names / cell_names declare which features / cells the
matrix spans, so a layer may legitimately cover only a subset (e.g.
scale.data over the variable features). When replacing an existing
layer without supplying names, the previous span is reused.
Source code in truecell/assay5.py
join_layers
¶
Rejoin split layers, restoring the name, order and contents.
Mirrors R's JoinLayers. Each split stem is rejoined separately —
counts.batch1 and counts.batch2 become counts again — and
layers that were never split are left alone, which is what makes the
no-argument call safe on a prepared assay that also holds data and a
variable-features-only scale.data.
The rejoined columns come back in the assay's cell order, not in the order the split happened to produce. The assay's own cell vector never moved during the split, so anything else would leave the matrix silently transposed against the metadata that indexes it.
Source code in truecell/assay5.py
split_layers
¶
Split one layer into per-group layers, as R's split() does.
The parts are named <layer>.<group> — Seurat's spelling, which users
match on with Layers(obj, pattern = "counts") — and each records the
layer it came from so join_layers can put it back.
Source code in truecell/assay5.py
Assay
¶
Assay(counts: Optional[Union[ndarray, spmatrix]] = None, data: Optional[Union[ndarray, spmatrix]] = None, scale_data: Optional[ndarray] = None, scaled_features: Optional[list[str]] = None, feature_names: Optional[list[str]] = None, cell_names: Optional[list[str]] = None, assay_orig: Optional[str] = None, var_features: Optional[list[str]] = None, meta_features: Optional[DataFrame] = None, misc: Optional[dict] = None, key: str = 'rna_')
Bases: KeyMixin
Legacy (v3) Assay object.
Mirrors R's Assay class from assay.R.
Slots
counts— raw counts / TPMs (features × cells)data— normalised expression (features × cells)scale_data— scaled expression (features × cells, dense) — a subset of the features, since ScaleData defaults to the variable ones. R's slot is a matrix and carries its own rownames; a bare ndarray does not, so the labels live alongside it in_scaled_featuresand every read of the layer goes throughfeatures("scale_data").assay_orig— name of original assay this was derived fromvar_features— list of highly variable feature namesmeta_features— per-feature metadata DataFrame (features × cols)misc(dict) — for miscellaneous storage_key(str) — ing key prefix (inherited from KeyMixin)
Source code in truecell/assay.py
subset
¶
Restrict the assay to cells and/or features, in the order given.
Every slot follows that order together, so the result is consistent
whichever order it is. Seurat's subset.Assay keeps the assay's own cell
order (and the requested feature order); Truecell.subset hands the
cells over in object order already, so the two agree through the object.
Source code in truecell/assay.py
create_assay_object
¶
create_assay_object(counts=None, data=None, min_cells: int = 0, min_features: int = 0, feature_names: Optional[list[str]] = None, cell_names: Optional[list[str]] = None, key: str = 'rna_') -> Assay
Create an Assay, optionally filtering by min_cells / min_features.
Source code in truecell/assay.py
Reductions, graphs and neighbours¶
DimReduc
¶
DimReduc(cell_embeddings: ndarray, cell_names: list[str], feature_loadings: Optional[ndarray] = None, feature_names: Optional[list[str]] = None, feature_loadings_projected: Optional[ndarray] = None, feature_names_projected: Optional[list[str]] = None, assay_used: str = '', global_: bool = False, stdev: Optional[ndarray] = None, jackstraw: Optional[JackStrawData] = None, misc: Optional[dict] = None, key: str = 'PC_')
Bases: KeyMixin
Stores a dimensionality reduction (PCA, UMAP, tSNE, …).
Mirrors R's DimReduc class from dimreduc.R.
Slots
cell_embeddings(np.ndarray) — (n_cells × n_dims), requiredfeature_loadings(np.ndarray) — (n_features × n_dims), optionalfeature_loadings_projected(np.ndarray) — projected loadings, optionalassay_used(str) — source assay nameglobal_(bool) — if True, persists when assay is removedstdev(np.ndarray) — per-dimension std devsjackstraw(JackStrawData)misc(dict)_key(str) — prefix, e.g. "PC_"
Source code in truecell/dimreduc.py
set_loadings
¶
set_loadings(value: ndarray, projected: bool = False, feature_names: Optional[list[str]] = None) -> None
Set one loadings matrix, and optionally the features it is indexed by.
feature_names matters most on the projected side, which starts empty:
without it, setting projected loadings would leave features(projected=True)
with nothing to report them against.
Source code in truecell/dimreduc.py
features
¶
Feature names for the requested loadings matrix.
Mirrors Features.DimReduc, which returns
rownames(Loadings(object, projected = projected)) and NULL when
that matrix is empty. So this reports the features of the matrix you
asked for, and [] when there is none — previously it returned the
unprojected names either way, which on a reduction with no projected
loadings claimed N features for a 0-row matrix.
Source code in truecell/dimreduc.py
subset
¶
Restrict the embedding to cells (in the order given) and dims.
Rows follow cells exactly, which integrate_layers relies on to put
a corrected embedding back into object order. Seurat's subset.DimReduc
keeps the reduction's own order instead; Truecell.subset passes
cells in object order already, so the two agree through the object.
Source code in truecell/dimreduc.py
Graph
¶
Sparse graph object for cell-cell relationships (e.g. SNN graph).
Mirrors R's Graph class from graph.R, which extends dgCMatrix. In Python we wrap (not inherit) a scipy CSC matrix to avoid scipy subclassing pitfalls.
Slots
_matrix(scipy.sparse.csc_matrix) — underlying adjacency matrixassay_used(Optional[str]) — assay that generated this graph_cell_names(list[str]) — row/col names (cells)
Source code in truecell/graph.py
subset
¶
Return a new Graph restricted to cells (cell×cell submatrix).
Rows and columns follow cells in the order given, skipping names the
graph does not have. Truecell.subset passes them in object order.
Source code in truecell/graph.py
as_graph
¶
as_graph(x: Union[ndarray, spmatrix, 'Neighbor'], cell_names: Optional[list[str]] = None, assay_used: Optional[str] = None, weighted: bool = True) -> Graph
Convert a matrix or Neighbor to a Graph. Mirrors R as.Graph().
Source code in truecell/graph.py
Neighbor
¶
Neighbor(nn_idx: ndarray, nn_dist: ndarray, cell_names: list[str], alg_idx: Any = None, alg_info: Optional[dict] = None)
Nearest-neighbor results for a set of cells.
Mirrors R's Neighbor class from neighbor.R.
Slots
nn_idx(int matrix) — (n_cells × k), neighbor indices (1-based in R; 0-based here)nn_dist(float matrix) — (n_cells × k), corresponding distancesalg_idx(Any) — algorithm index object (e.g. annoy index)alg_info(dict) — metadata about the algorithm usedcell_names(list[str]) — cell barcodes, length n_cells
Source code in truecell/neighbor.py
Supporting structures¶
JackStrawData
¶
JackStrawData(empirical_p_values: Optional[ndarray] = None, fake_reduction_scores: Optional[ndarray] = None, overall_p_values: Optional[ndarray] = None, score: Optional[ndarray] = None, method: Optional[str] = None)
Stores JackStraw permutation test results for a DimReduc.
Mirrors R's JackStraw / JackStrawData from jackstraw.R.
Source code in truecell/jackstraw.py
LogMap
¶
Logical mapping: named boolean arrays indicating membership.
Mirrors R's LogMap class from logmap.R. Keys are cell or feature names; values are boolean numpy arrays.
Source code in truecell/logmap.py
KeyMixin
¶
Mixin providing a validated 'key' slot, mirroring R's KeyMixin from keymixin.R.
TruecellCommand
¶
TruecellCommand(name: str, time_stamp: Optional[datetime] = None, assay_used: Optional[str] = None, call_string: str = '', params: Optional[dict] = None, key: Optional[str] = None)
Logs commands executed on a Truecell object.
Mirrors R's TruecellCommand class from command.R.
Slots
name(str) — function/method nametime_stamp(datetime) — when the command ranassay_used(Optional[str])call_string(str) — human-readable call representationparams(dict) — non-function parameters passed to the command
Source code in truecell/command.py
log_truecell_command
¶
log_truecell_command(object_, func_name: str, params: Optional[dict] = None, assay: Optional[str] = None, reduction: Optional[str] = None) -> 'TruecellCommand'
Capture a command log entry, typically called at the end of a function.
Mirrors R's LogSeuratCommand, including how it names the entry: Seurat's
function name, the assay, and the reduction where one was consumed. The
names are R's (RunPCA, not run_pca) because the log is a lookup
table users query — the same reasoning that keeps layer names scale.data
and reduction keys PC_.