File size: 2,731 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Post-transcriptional state discovery via Leiden clustering on gamma profiles."""

from __future__ import annotations

import numpy as np
from anndata import AnnData

from .._constants import GAMMA, PT_STATE, DEFAULT_LEIDEN_RESOLUTION
from .._utils import get_layer, require_layers, log_params


def pt_states(
    adata: AnnData,
    resolution: float = DEFAULT_LEIDEN_RESOLUTION,
    n_pcs: int = 30,
    n_neighbors: int = 30,
    random_state: int = 0,
) -> None:
    """Discover post-transcriptional states by clustering gamma profiles.

    Steps:
    1. PCA on the gamma matrix.
    2. kNN graph in gamma-PCA space.
    3. Leiden clustering.
    4. UMAP embedding in gamma space.

    Results are stored in ``adata.obs['pt_state']`` and
    ``adata.obsm['X_gamma_pca']``, ``adata.obsm['X_gamma_umap']``.

    Parameters
    ----------
    adata
        Annotated data matrix with ``gamma`` layer.
    resolution
        Leiden clustering resolution.
    n_pcs
        Number of principal components for gamma PCA.
    n_neighbors
        Number of neighbors for the gamma-space kNN graph.
    random_state
        Random seed for reproducibility.
    """
    import scanpy as sc

    require_layers(adata, GAMMA)

    gamma = get_layer(adata, GAMMA)

    # Create a temporary AnnData for gamma-space analysis
    gamma_adata = AnnData(X=gamma.copy())
    gamma_adata.obs_names = adata.obs_names.copy()
    gamma_adata.var_names = adata.var_names.copy()

    # PCA on gamma matrix
    n_pcs_use = min(n_pcs, min(gamma.shape) - 1)
    sc.tl.pca(gamma_adata, n_comps=n_pcs_use, random_state=random_state)

    # kNN graph in gamma-PCA space
    sc.pp.neighbors(
        gamma_adata,
        n_neighbors=n_neighbors,
        use_rep="X_pca",
        random_state=random_state,
    )

    # Leiden clustering
    sc.tl.leiden(
        gamma_adata,
        resolution=resolution,
        random_state=random_state,
        flavor="igraph",
        n_iterations=2,
        directed=False,
    )

    # UMAP
    sc.tl.umap(gamma_adata, random_state=random_state)

    # Store results back in original adata
    adata.obs[PT_STATE] = gamma_adata.obs["leiden"].values
    adata.obs[PT_STATE] = adata.obs[PT_STATE].astype("category")
    adata.obsm["X_gamma_pca"] = gamma_adata.obsm["X_pca"]
    adata.obsm["X_gamma_umap"] = gamma_adata.obsm["X_umap"]

    # Store gamma-space neighbor graph
    adata.obsp["gamma_distances"] = gamma_adata.obsp["distances"]
    adata.obsp["gamma_connectivities"] = gamma_adata.obsp["connectivities"]

    log_params(adata, "pt_states", {
        "resolution": resolution,
        "n_pcs": n_pcs_use,
        "n_neighbors": n_neighbors,
        "n_states": int(adata.obs[PT_STATE].nunique()),
    })