Source code for sceleto.annotator
"""Interactive cell annotation helper.
Usage
-----
>>> import sceleto as sl
>>> ann = sl.Annotator(adata, 'celltype')
>>> ann.annotate('leiden', '0', 'T cell')
>>> ann.annotate('leiden_R', '0,1', 'CD4 T')
>>> ann.annotate('leiden', '4', 'Monocyte', unknown_only=True)
"""
from __future__ import annotations
import numpy as np
[docs]
class Annotator:
"""Build cell-type annotations incrementally on an AnnData object.
Parameters
----------
adata
AnnData object.
label_key
Name of the new column in adata.obs.
copy_from
If given, initialize from an existing adata.obs column.
"""
def __init__(self, adata, label_key: str, copy_from: str | None = None):
if copy_from:
adata.obs[label_key] = adata.obs[copy_from].astype(str)
else:
adata.obs[label_key] = "unknown"
self._adata = adata
self._key = label_key
self._labels = np.array(adata.obs[label_key], dtype=object)
[docs]
def annotate(
self,
obs_key: str,
select: str,
label: str,
unknown_only: bool = False,
):
"""Assign *label* to cells whose ``obs_key`` value equals ``select``.
One call = one decision. ``select`` is a single string matched
exactly against ``adata.obs[obs_key]``; no list or comma splitting.
To label multiple groups with the same label, call repeatedly
(e.g. in a dict loop).
Parameters
----------
obs_key
Column in adata.obs to match against (e.g. 'leiden', 'leiden_R').
select
Exact value to match in ``adata.obs[obs_key]``.
label
The annotation label to assign.
unknown_only
If True, only update cells still labeled 'unknown'.
"""
mask = self._adata.obs[obs_key] == select
if unknown_only:
mask = mask & (self._adata.obs[self._key] == "unknown")
self._labels[mask] = label
self._adata.obs[self._key] = self._labels
[docs]
def annotate_mask(self, mask, label: str):
"""Assign *label* to cells matching a boolean mask directly."""
self._labels[mask] = label
self._adata.obs[self._key] = self._labels
[docs]
def summary(self):
"""Print value counts of current annotations."""
print(self._adata.obs[self._key].value_counts())