File size: 1,553 Bytes
4e2940e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | """Per-layer library-size normalization."""
from __future__ import annotations
import numpy as np
from anndata import AnnData
from scipy.sparse import issparse
from .._constants import UNSPLICED, SPLICED
from .._utils import log_params
def normalize_layers(
adata: AnnData,
target_sum: float | None = None,
layers: tuple[str, ...] = (SPLICED, UNSPLICED),
) -> None:
"""Library-size normalize spliced and unspliced layers independently.
Each cell's counts in each layer are divided by the cell's total
counts in that layer and multiplied by *target_sum* (defaults to
the median library size across cells for that layer).
Modifies *adata* in place — layers are converted to dense float32.
Parameters
----------
adata
Annotated data matrix.
target_sum
Target total counts per cell. If ``None``, use the median.
layers
Which layers to normalize.
"""
for layer in layers:
mat = adata.layers[layer]
if issparse(mat):
mat = np.asarray(mat.todense(), dtype=np.float32)
else:
mat = np.asarray(mat, dtype=np.float32)
lib_sizes = mat.sum(axis=1, keepdims=True)
lib_sizes = np.clip(lib_sizes, 1e-10, None)
if target_sum is None:
ts = np.median(lib_sizes)
else:
ts = target_sum
mat = mat / lib_sizes * ts
adata.layers[layer] = mat
log_params(adata, "normalize_layers", {
"target_sum": target_sum,
"layers": list(layers),
})
|