Source code for spatialtis.spatial.neighborhood

from ast import literal_eval

import numpy as np
import pandas as pd
from anndata import AnnData
from scipy.stats import norm

from spatialtis.abc import AnalysisBase
from spatialtis.spatial.utils import NeighborsNotFoundError
from spatialtis.utils import doc
from spatialtis.utils.log import pbar_iter


[docs]@doc class neighborhood_analysis(AnalysisBase): """`Profiling cell-cell interaction <about/implementation.html#profiling-of-cell-cell-interaction>`_ using permutation test Neighborhood analysis tells you the relationship between different type of cells - Association (1) - Avoidance (-1) - No relationship (0) This method is implemented in Rust, it executes in parallel automatically. Args: data: {adata} method: "pval" and "zscore" (Default: "pval") resample: Number of times to perform resample pval: {pval} order: If False, (Cell_A, Cell_B) and (Cell_B, Cell_A) are the same interaction (Default: False) **kwargs: {analysis_kwargs} .. seealso:: `spatial_enrichment_analysis <#spatialtis.plotting.spatial_enrichment_analysis>`_ """ def __init__( self, data: AnnData, method: str = "pval", resample: int = 1000, pval: float = 0.01, order: bool = False, **kwargs, ): if method == "pval": self.method = "pseudo p-value" else: self.method = "z-score" super().__init__(data, task_name="neighborhood_analysis", **kwargs) self.params = {"order": order} try: import neighborhood_analysis as na except ImportError: raise ImportError( "Package not found, try `pip install neighborhood_analysis`." ) if not self.neighbors_exists: raise NeighborsNotFoundError("Run `find_neighbors` first before continue.") need_eval = self.is_col_str(self.neighbors_key) cc = na.CellCombs(self.cell_types, order) results_data = [] for name, g in pbar_iter( data.obs.groupby(self.exp_obs), desc="Neighborhood analysis" ): if isinstance(name, str): name = [name] if need_eval: neighbors = [literal_eval(n) for n in g[self.neighbors_key]] else: neighbors = [n for n in g[self.neighbors_key]] # here we need to move the neighbors from its real ix to starting point 0 neighbors_min = np.asarray( [i for n in neighbors for i in n], dtype=int ).min() neighbors = [(np.asarray(n) - neighbors_min).tolist() for n in neighbors] cell_types = g[self.cell_type_key] result = cc.bootstrap( cell_types, neighbors, resample, pval, method, ignore_self=True ) for k, v in result: results_data.append([*name, *k, v]) df = pd.DataFrame( data=results_data, columns=self.exp_obs + ["type1", "type2", "value"] ) if method == "pval": df.loc[:, ["value"]] = df["value"].astype(int) else: def sign(x): p = norm.sf(abs(x)) * 2 if p < pval: return np.sign(x) else: return 0 df.loc[:, ["value"]] = df["value"].apply(sign).astype(int) self.result = df