From 25e352f60c2d16d76bea4d5b218fd5930965eb3e Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Wed, 4 Jun 2025 12:19:20 +0200 Subject: [PATCH 01/10] First group_nhoods update Added group_nhoods to _milo.py as FUNCTION, not included in the class, which will be changed when I finalize everything. Added tests in pertpy.tests.tools.test_milo.py, where the tests focus on the processing of the neighborhood adjacency matrix and show, that the processing in miloR and Python are equivalent. Added pertpy.utils... for lazy rpy2 convenience utils. This is NOT to stay there, but I want to ask if I can include this somewhere maybe others can use it, too, or should I hardcode with localconverter, etc.? --- pertpy/tools/__init__.py | 3 + pertpy/tools/_milo.py | 254 ++++++++++++++++++++++++++++++ pertpy/utils/__init__.py | 0 pertpy/utils/_lazy_r_namespace.py | 22 +++ pertpy/utils/rpy2_utils.py | 245 ++++++++++++++++++++++++++++ tests/tools/test_milo.py | 252 +++++++++++++++++++++++++++++ 6 files changed, 776 insertions(+) create mode 100644 pertpy/utils/__init__.py create mode 100644 pertpy/utils/_lazy_r_namespace.py create mode 100644 pertpy/utils/rpy2_utils.py diff --git a/pertpy/tools/__init__.py b/pertpy/tools/__init__.py index 45969728..791f5b86 100644 --- a/pertpy/tools/__init__.py +++ b/pertpy/tools/__init__.py @@ -52,6 +52,8 @@ def __init__(self, *args, **kwargs): TTest = lazy_import("pertpy.tools._differential_gene_expression", "TTest", DE_EXTRAS) WilcoxonTest = lazy_import("pertpy.tools._differential_gene_expression", "WilcoxonTest", DE_EXTRAS) +from ._milo import group_nhoods + __all__ = [ "Augur", "Cinemaot", @@ -77,4 +79,5 @@ def __init__(self, *args, **kwargs): "KMeansSpace", "PseudobulkSpace", "Scgen", + "group_nhoods", ] diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 10874ac5..e5932ce4 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -1138,3 +1138,257 @@ def plot_nhood_counts_by_cond( # pragma: no cover # noqa: D417 plt.show() return None + + + +### Neighborhood clustering as in miloR + +import numpy as np +import pandas as pd +import scipy.sparse as sp +import scanpy as sc +from igraph import Graph +from anndata import AnnData + +def _group_nhoods_from_adjacency( + adjacency: sp.spmatrix, + da_res: pd.DataFrame, + is_da: np.ndarray, + merge_discord: bool = False, + overlap: int = 1, + max_lfc_delta: float | None = None, + subset_nhoods=None, +) -> np.ndarray: + """ + Core neighborhood‐grouping logic (vectorized, no Python loops). + Inputs: + - adjacency: scipy.sparse square matrix of shape (N, N), + storing neighborhood adjacency (overlap counts). + - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. + - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. + - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. + - overlap: integer threshold; zero edges with weight < overlap. + - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. + - subset_nhoods: None or one of: + • boolean mask (length N), + • list/array of integer indices, + • list/array of string names (matching da_res.index). + Returns: + - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), + giving a Louvain cluster label for each neighborhood (in the same order as da_res). + """ + + # 1) Optional subsetting of neighborhoods --------------------------------------------------- + # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. + if subset_nhoods is not None: + if isinstance(subset_nhoods, (list, np.ndarray)): + # could be integer indices or names + if all(isinstance(x, (int, np.integer)) for x in subset_nhoods): + # direct integer indices + mask = np.zeros(adjacency.shape[0], dtype=bool) + mask[np.array(subset_nhoods, dtype=int)] = True + else: + # assume list of names + names = np.array(da_res.index, dtype=str) + mask = np.isin(names, subset_nhoods) + elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: + # boolean mask + if len(subset_nhoods) != adjacency.shape[0]: + raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") + mask = np.asarray(subset_nhoods, dtype=bool) + else: + raise ValueError("subset_nhoods must be a boolean mask, a list of indices, or a list of names.") + + # Apply subsetting to adjacency, da_res, and is_da + adjacency = adjacency[mask, :][:, mask] + da_res = da_res.loc[mask].copy() + is_da = is_da[mask] + else: + mask = np.ones(adjacency.shape[0], dtype=bool) + + M = adjacency.shape[0] + if da_res.shape[0] != M or is_da.shape[0] != M: + raise ValueError("Length of da_res and is_da must match adjacency dimension after subsetting.") + + # 2) Convert adjacency to CSR (if not already) and then to COO for a flat edge list ---------------- + if not sp.issparse(adjacency): + adjacency = sp.csr_matrix(adjacency) + else: + adjacency = adjacency.tocsr() + + Acoo = adjacency.tocoo() + rows = Acoo.row # array of length E = number of nonzero edges + cols = Acoo.col + data = Acoo.data # the actual overlap counts + + # 3) Precompute logFC and sign arrays ------------------------------------------------------------------- + lfc_vals = da_res["logFC"].values # shape = (M,) + signs = np.sign(lfc_vals) # sign(lfc_i), shape = (M,) + + # 4) Build Boolean masks (length E) for each filter ------------------------------------------------------ + + # 4.1) “Discord” filter: if merge_discord=False, drop any edge (i,j) where both i,j are DA + # AND sign(lfc_i) * sign(lfc_j) < 0 (opposite signs). + if merge_discord: + keep_discord = np.ones_like(data, dtype=bool) + else: + # For each edge k at (i=rows[k], j=cols[k]), check if both are DA AND signs differ + is_da_rows = is_da[rows] # True if endpoint‐i is DA + is_da_cols = is_da[cols] # True if endpoint‐j is DA + sign_rows = signs[rows] + sign_cols = signs[cols] + + # discord_pair[k] = True if both DA and (signs multiply < 0) + discord_pair = (is_da_rows & is_da_cols) & ((sign_rows * sign_cols) < 0) + keep_discord = ~discord_pair + + # 4.2) “Overlap” filter: drop any edge whose current weight < overlap + if overlap <= 1: + keep_overlap = np.ones_like(data, dtype=bool) + else: + keep_overlap = (data >= overlap) + + # 4.3) “Δ logFC” filter: drop any edge where |lfc_i - lfc_j| > max_lfc_delta + if max_lfc_delta is None: + keep_lfc = np.ones_like(data, dtype=bool) + else: + # Compute |lfc_vals[rows] - lfc_vals[cols]| vectorized + lfc_edge_diffs = np.abs(lfc_vals[rows] - lfc_vals[cols]) + keep_lfc = (lfc_edge_diffs <= max_lfc_delta) + + # 5) Combine all masks into a single “keep” mask ---------------------------------------------------------------- + keep_mask = keep_discord & keep_overlap & keep_lfc + + # 6) Rebuild a new, pruned adjacency in COO form (only edges where keep_mask=True) -------------------------- + new_rows = rows[keep_mask] + new_cols = cols[keep_mask] + new_data = data[keep_mask] + + # If you want an unweighted graph (just connectivity), you could do `new_data = np.ones_like(new_rows)`. + # But to mirror MiloR exactly, we preserve the original overlap counts until the final binarization. + pruned_adj = sp.coo_matrix((new_data, (new_rows, new_cols)), shape=(M, M)).tocsr() + + # 7) Binarize: every surviving edge → 1, then convert to CSR ---------------------------------------------------------------- + pruned_adj = (pruned_adj > 0).astype(int).tocsr() + + # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- + # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. + g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) + + # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- + # By not providing a “weights” argument, igraph treats every edge as weight=1. + clustering = g.community_multilevel(weights=None) + labels = np.array(clustering.membership, dtype=str) # length = M, dtype = 'str' + + # 10) Return the cluster labels array (strings), in the same order as da_res.index --------------------------------------- + # If subset_nhoods was not None, these labels correspond to rows where mask=True. + return labels + +def group_nhoods( + adata: AnnData, + da_res: pd.DataFrame | None = None, + da_fdr: float = 0.1, + overlap: int = 1, + max_lfc_delta: float | None = None, + merge_discord: bool = False, + subset_nhoods=None, +) -> pd.DataFrame: + """ + Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. + + Parameters + ---------- + adata : AnnData + Must contain: + - `adata.var` with columns "SpatialFDR" (float) and "logFC" (float) + - `adata.varp["nhood_connectivities"]` as an (N×N) sparse adjacency matrix + da_res : pd.DataFrame, optional + If provided, must match `adata.var`. Otherwise, `adata.var` is used directly. + da_fdr : float, default=0.1 + Neighborhoods with `SpatialFDR < da_fdr` are called “DA.” + overlap : int, default=1 + Drop any adjacency entry (edge) with weight < overlap. + max_lfc_delta : float or None, default=None + If not None, drop edges where |lfc_i - lfc_j| > max_lfc_delta. + merge_discord : bool, default=False + If False, drop edges between DA neighborhoods whose logFC signs disagree. + subset_nhoods : None or boolean mask / list of indices / list of names + If provided, only cluster that subset of neighborhoods. + + Returns + ------- + pd.DataFrame + A copy of `adata.var`, with a new column "NhoodGroup" of dtype string giving each + neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). + """ + + # 1) Validate input --------------------------------------------------------------------------------------------- + if not isinstance(adata, AnnData): + raise ValueError("`adata` must be an AnnData object.") + + # 2) Get or check `da_res` -------------------------------------------------------------------------------------- + if da_res is None: + da_res = adata.var + else: + # If user passed their own da_res, ensure indexes match + if not da_res.index.equals(adata.var.index): + raise ValueError("`da_res` index must match `adata.var.index`.") + + # Ensure required columns exist + if "SpatialFDR" not in da_res.columns or "logFC" not in da_res.columns: + raise ValueError("`da_res` (adata.var) must contain columns 'SpatialFDR' and 'logFC'.") + + # 3) Identify “DA” neighborhoods by FDR cutoff ------------------------------------------------------------------- + fdr_values = da_res["SpatialFDR"].values + if np.all(pd.isna(fdr_values)): + raise ValueError("All `SpatialFDR` values are NA; cannot determine DA neighborhoods.") + is_da = (fdr_values < da_fdr) + + n_da = int(is_da.sum()) + if n_da == 0: + raise ValueError(f"No DA neighborhoods found at FDR < {da_fdr}.") + + # 4) Extract adjacency ------------------------------------------------------------------------------------------ + if "nhood_connectivities" not in adata.varp: + raise KeyError("`adata.varp` does not contain 'nhood_connectivities'. Did you run buildNhoodGraph?") + adjacency = adata.varp["nhood_connectivities"] + + # 5) Call core worker to get string labels ---------------------------------------------------------------------- + labels = _group_nhoods_from_adjacency( + adjacency = adjacency, + da_res = da_res, + is_da = is_da, + merge_discord = merge_discord, + overlap = overlap, + max_lfc_delta = max_lfc_delta, + subset_nhoods = subset_nhoods, + ) + + # 6) Write results back into `adata.var["NhoodGroup"]` ----------------------------------------------------------- + N_full = adata.var.shape[0] + out = np.array([""] * N_full, dtype=object) + out[:] = pd.NA + + if subset_nhoods is None: + # Every neighborhood was labeled + out[:] = labels + else: + # Reconstruct the same mask logic to place `labels` in the correct positions + if isinstance(subset_nhoods, (list, np.ndarray)): + arr = np.asarray(subset_nhoods) + if np.issubdtype(arr.dtype, np.integer): + mask_idx = np.zeros(N_full, dtype=bool) + mask_idx[arr.astype(int)] = True + else: + names = np.array(adata.var.index, dtype=str) + mask_idx = np.isin(names, arr.astype(str)) + elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: + if len(subset_nhoods) != N_full: + raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") + mask_idx = np.asarray(subset_nhoods, dtype=bool) + else: + raise ValueError("`subset_nhoods` must be a boolean mask, a list of indices, or a list of names.") + + out[mask_idx] = labels + + adata.var["nhood_groups"] = out \ No newline at end of file diff --git a/pertpy/utils/__init__.py b/pertpy/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pertpy/utils/_lazy_r_namespace.py b/pertpy/utils/_lazy_r_namespace.py new file mode 100644 index 00000000..58fc346e --- /dev/null +++ b/pertpy/utils/_lazy_r_namespace.py @@ -0,0 +1,22 @@ +from types import SimpleNamespace + +def lazy_import_r_env(): + import rpy2.robjects as ro + from rpy2.robjects.packages import importr, STAP + from rpy2.robjects.conversion import localconverter + from rpy2.robjects import default_converter, pandas2ri, numpy2ri + + from pertpy.utils.rpy2_utils import _py_to_r, _r_to_py, lazy_import_r_packages # moved inside function + + r = SimpleNamespace( + ro=ro, + importr=importr, + STAP=STAP, + localconverter=localconverter, + default_converter=default_converter, + pandas2ri=pandas2ri, + numpy2ri=numpy2ri, + lazy_import_r_packages=lazy_import_r_packages + ) + + return r, _py_to_r, _r_to_py \ No newline at end of file diff --git a/pertpy/utils/rpy2_utils.py b/pertpy/utils/rpy2_utils.py new file mode 100644 index 00000000..35763ff5 --- /dev/null +++ b/pertpy/utils/rpy2_utils.py @@ -0,0 +1,245 @@ +from functools import singledispatch +from typing import Sequence, Union, Any +from rpy2 import robjects as ro +from rpy2.robjects import vectors, methods +from rpy2.robjects.vectors import ListVector +from rpy2.robjects.methods import RS4 +from rpy2.robjects.conversion import localconverter +from rpy2.robjects import default_converter, numpy2ri, pandas2ri +from anndata2ri import scipy2ri +import numpy as np +import pandas as pd +from scipy.sparse import csr_matrix, csc_matrix +from typing import Sequence, Union, Tuple +import types + +def get_rpy2_objects(): + """ + Return commonly used rpy2 classes, functions, and modules for local use. + + Returns + ------- + tuple : (ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri) + """ + try: + import rpy2.robjects as ro + from rpy2.robjects.packages import importr, STAP + from rpy2.robjects.conversion import localconverter + from rpy2.robjects import pandas2ri, numpy2ri + from rpy2.robjects import default_converter + + except ImportError as e: + raise ImportError("rpy2 must be installed to use this function.") from e + + return ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri + +ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri = get_rpy2_objects() + +def lazy_import_r_packages(packages: Sequence[str] | str) -> tuple[Union[types.ModuleType, str], ...]: + """ + Lazily import R packages using rpy2.robjects.packages.importr. + + For each package name: + - Try to import it. + - If successful, return the imported package object, prefixed with "r_" in variable naming convention. + - If failed, return the package name string (as a marker of failure). + + Parameters + ---------- + packages : list of str + R package names to import. + + Returns + ------- + tuple + A tuple of imported modules or failed package names (as strings), in order. + """ + ro, importr, _, *_ = get_rpy2_objects() + + if isinstance(packages, str): + try: + r_pkg = importr(packages) + except Exception as e: + raise ImportError(f"Failed to import required R package: {packages}") + return r_pkg + + imported = [] + failures = [] + for pkg in packages: + try: + r_pkg = importr(pkg) + imported.append(r_pkg) + except Exception as e: + imported.append(pkg) + failures.append(pkg) + + if failures: + raise ImportError(f"Failed to import required R packages: {', '.join(failures)}") + + return tuple(imported) + + +### + +# ---------------------- +# Python -> R converters +# ---------------------- +@singledispatch +def _py_to_r(obj) -> ro.RObject: + """ + Fallback: convert with rpy2's generic converter. + Lists/tuples of atomic types -> R vector; mixed lists -> R list. + """ + with localconverter(default_converter): + return ro.conversion.py2rpy(obj) + +@_py_to_r.register(type(None)) +def _(obj) -> ro.NULL: + return ro.NULL + +@_py_to_r.register(bool) +def _(obj: bool) -> vectors.BoolVector: + return vectors.BoolVector([obj]) + +@_py_to_r.register(int) +def _(obj: int) -> vectors.IntVector: + return vectors.IntVector([obj]) + +@_py_to_r.register(float) +def _(obj: float) -> vectors.FloatVector: + return vectors.FloatVector([obj]) + +@_py_to_r.register(str) +def _(obj: str) -> vectors.StrVector: + return vectors.StrVector([obj]) + +@_py_to_r.register(dict) +def _(obj: dict) -> ListVector: + # Convert a Python dict to an R named list + rdict = {str(k): _py_to_r(v) for k, v in obj.items()} + return ListVector(rdict) + +@_py_to_r.register(np.ndarray) +def _(obj: np.ndarray) -> ro.Matrix: + with localconverter(default_converter + numpy2ri.converter): + return numpy2ri.py2rpy(obj) + +@_py_to_r.register(pd.DataFrame) +def _(obj: pd.DataFrame) -> ro.DataFrame: + with localconverter(default_converter + pandas2ri.converter): + return ro.conversion.py2rpy(obj) + +@_py_to_r.register(pd.Series) +def _(obj: pd.Series) -> vectors.Vector: + with localconverter(default_converter + pandas2ri.converter): + return ro.conversion.py2rpy(obj) + +@_py_to_r.register(csr_matrix) +def _(obj: csr_matrix) -> ro.Matrix: + with localconverter(default_converter + scipy2ri.converter): + return ro.conversion.py2rpy(obj) + +@_py_to_r.register(csc_matrix) +def _(obj: csc_matrix) -> ro.Matrix: + with localconverter(default_converter + scipy2ri.converter): + return ro.conversion.py2rpy(obj) + +# ---------------------- +# R -> Python converters +# ---------------------- +@singledispatch +def _r_to_py(obj: ro.RObject): + """Fallback: generic R->Python via rpy2""" + with localconverter(default_converter): + return ro.conversion.rpy2py(obj) + +@_r_to_py.register(type(ro.NULL)) +def _(obj) -> None: + return None + +@_r_to_py.register(vectors.BoolVector) +def _(obj: vectors.BoolVector): + py = [bool(x) for x in list(obj)] + return py[0] if len(py) == 1 else py + +@_r_to_py.register(vectors.IntVector) +def _(obj: vectors.IntVector): + py = list(obj) + return int(py[0]) if len(py) == 1 else py + +@_r_to_py.register(vectors.FloatVector) +def _(obj: vectors.FloatVector): + py = list(obj) + return float(py[0]) if len(py) == 1 else py + +@_r_to_py.register(vectors.StrVector) +def _(obj: vectors.StrVector): + py = list(obj) + return str(py[0]) if len(py) == 1 else py + +@_r_to_py.register(ListVector) +def _(obj: ListVector): + # Convert each element first + items = [_r_to_py(obj[i]) for i in range(len(obj))] + # Handle names (NULL means no names) + names_r = obj.names + if names_r == ro.NULL: + return items + names = list(names_r) + return {names[i]: items[i] for i in range(len(items))} + +@_r_to_py.register(vectors.Matrix) +def _(obj: vectors.Matrix): + with localconverter(default_converter + numpy2ri.converter): + return ro.conversion.rpy2py(obj) + +@_r_to_py.register(ro.DataFrame) +def _(obj: ro.DataFrame) -> pd.DataFrame: + with localconverter(default_converter + pandas2ri.converter): + return ro.conversion.rpy2py(obj) + +@_r_to_py.register(vectors.Vector) +def _(obj: vectors.Vector): + return list(obj) + +@_r_to_py.register(RS4) +def _(obj: RS4): + # Sparse S4 matrix types go through scipy2ri + if obj.rclass[0] in ("dgCMatrix", "dgRMatrix"): + with localconverter(default_converter + scipy2ri.converter): + return ro.conversion.rpy2py(obj) + # Other S4 -> dict of slots + return {name: _r_to_py(obj.slots[name]) for name in obj.slotnames()} + + +def _ad_to_rmat(adata, layer="X"): + from rpy2 import robjects as ro + from rpy2.robjects import baseenv + from rpy2.robjects.packages import importr + import numpy as np + + # 1) grab & transpose + mat = adata.X if layer == "X" else adata.layers[layer] + mat = mat.T + + # 2) convert to R + rmat = _py_to_r(mat) + + # 3) build an *unnamed* R list(r_rownames, r_colnames) + r_colnames = _py_to_r(np.asarray(adata.obs_names)) + r_rownames = _py_to_r(np.asarray(adata.var_names)) + dim_list = ro.r.list(r_rownames, r_colnames) + + # 4) set dimnames via baseenv() + assign_dim = baseenv["dimnames<-"] + rmat = assign_dim(rmat, dim_list) + + return rmat + +def _ad_to_dge(adata, layer="X") -> Any: + edgeR = importr("edgeR") + counts = _ad_to_rmat(adata, layer) + samples = _py_to_r(adata.obs) + return edgeR.DGEList(counts=counts, samples=samples) + + diff --git a/tests/tools/test_milo.py b/tests/tools/test_milo.py index 8264ab4a..c95e9f72 100644 --- a/tests/tools/test_milo.py +++ b/tests/tools/test_milo.py @@ -7,6 +7,10 @@ import scanpy as sc from mudata import MuData +### NEW IMPORTS +from pertpy.utils._lazy_r_namespace import lazy_import_r_env +### + @pytest.fixture(params=["edger", "pydeseq2"]) def solver(request): @@ -307,3 +311,251 @@ def test_add_nhood_expression_nhood_mean_range(add_nhood_expression_mdata, milo) nhood_cells = mdata["rna"].obs_names[mdata["rna"].obsm["nhoods"][:, nhood_ix].toarray().ravel() == 1] mean_gex = np.array(mdata["rna"][nhood_cells].X.mean(axis=0)).ravel() assert nhood_gex == pytest.approx(mean_gex, 0.0001) + + +### NEW TESTS + + +import numpy as np +import pandas as pd +import scipy.sparse as sp + +import pytest + +from anndata import AnnData + +r, _py_to_r, _r_to_py = lazy_import_r_env() + +r_string = """ +.group_nhoods_from_adjacency_pycomp <- function(nhs, nhood.adj, da.res, is.da, + merge.discord=FALSE, + max.lfc.delta=NULL, + overlap=1, + subset.nhoods=NULL + ){ + # Force everything into a plain base‐R matrix + nhood.adj <- as.matrix(nhood.adj) + + if(is.null(colnames(nhs))){ + warning("No names attributed to nhoods. Converting indices to names") + colnames(nhs) <- as.character(seq_len(ncol(nhs))) + } + + # Subsetting logic (exactly as in miloR) + if(!is.null(subset.nhoods)){ + if(mode(subset.nhoods) %in% c("character", "logical", "numeric")){ + if(mode(subset.nhoods) %in% c("character")){ + sub.log <- colnames(nhs) %in% subset.nhoods + } else if (mode(subset.nhoods) %in% c("numeric")) { + sub.log <- colnames(nhs) %in% colnames(nhs)[subset.nhoods] + } else{ + sub.log <- subset.nhoods + } + nhood.adj <- nhood.adj[sub.log, sub.log] + if(length(is.da) == ncol(nhs)){ + nhs <- nhs[sub.log] + is.da <- is.da[sub.log] + da.res <- da.res[sub.log, ] + } else{ + stop("Subsetting `is.da` vector length does not equal nhoods length") + } + } else{ + stop("Incorrect subsetting vector provided:", class(subset.nhoods)) + } + } else{ + if(length(is.da) != ncol(nhood.adj)){ + stop("Subsetting `is.da` vector length is not the same dimension as adjacency") + } + } + + # Discord‐filter + if(isFALSE(merge.discord)){ + discord.sign <- sign(da.res[is.da, 'logFC'] %*% t(da.res[is.da, 'logFC'])) < 0 + nhood.adj[is.da, is.da][discord.sign] <- 0 + } + + # Overlap‐filter + if(overlap > 1){ + nhood.adj[nhood.adj < overlap] <- 0 + } + + # max.lfc.delta‐filter + if(!is.null(max.lfc.delta)){ + lfc.diff <- sapply(da.res[,"logFC"], "-", da.res[,"logFC"]) + nhood.adj[abs(lfc.diff) > max.lfc.delta] <- 0 + } + + # Binarize + nhood.adj <- as.matrix((nhood.adj > 0) + 0) + + # Sanity checks + if(!isSymmetric(nhood.adj)){ + stop("Overlap matrix is not symmetric") + } + if(nrow(nhood.adj) != ncol(nhood.adj)){ + stop("Non-square distance matrix - check nhood subsetting") + } + + return(nhood.adj) +} +""" + +r_pkg = r.STAP(r_string, "r_pkg") + + +def _group_nhoods_from_adjacency_rcomp( + adjacency: sp.spmatrix, + da_res: pd.DataFrame, + is_da: np.ndarray, + merge_discord: bool = False, + overlap: int = 1, + max_lfc_delta: float | None = None, + subset_nhoods=None, +) -> np.ndarray: + """ + Mirror of the R code above, returning the final binary adjacency + (dense array) after applying Discord, Overlap, and ΔlogFC filters. + """ + + # 1) Subset if needed + if subset_nhoods is not None: + if isinstance(subset_nhoods, (list, np.ndarray)): + arr = np.asarray(subset_nhoods) + if np.issubdtype(arr.dtype, np.integer): + mask = np.zeros(adjacency.shape[0], dtype=bool) + mask[arr.astype(int)] = True + else: + names = np.array(da_res.index, dtype=str) + mask = np.isin(names, arr.astype(str)) + elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: + if len(subset_nhoods) != adjacency.shape[0]: + raise ValueError("Boolean subset_nhoods length must match nhood count") + mask = np.asarray(subset_nhoods, dtype=bool) + else: + raise ValueError("subset_nhoods must be bool mask, index list, or name list") + + adjacency = adjacency[mask, :][:, mask] + da_res = da_res.loc[mask].copy() + is_da = is_da[mask] + else: + mask = np.ones(adjacency.shape[0], dtype=bool) + + M = adjacency.shape[0] + if da_res.shape[0] != M or is_da.shape[0] != M: + raise ValueError("da_res and is_da must match adjacency dimension after subsetting") + + # 2) Ensure CSR → COO + if not sp.issparse(adjacency): + adjacency = sp.csr_matrix(adjacency) + adjacency = adjacency.tocsr() + Acoo = adjacency.tocoo() + rows, cols, data = (np.asarray(Acoo.row, int), + np.asarray(Acoo.col, int), + np.asarray(Acoo.data, float)) + + # 3) Precompute logFC and signs + lfc_vals = da_res["logFC"].values + signs = np.sign(lfc_vals) + + # 4.1) Discord filter + if merge_discord: + keep_discord = np.ones_like(data, dtype=bool) + else: + is_da_rows = is_da[rows] + is_da_cols = is_da[cols] + sign_rows = signs[rows] + sign_cols = signs[cols] + discord_pair = (is_da_rows & is_da_cols) & (sign_rows * sign_cols < 0) + keep_discord = ~discord_pair + + # 4.2) Overlap filter + if overlap <= 1: + keep_overlap = np.ones_like(data, dtype=bool) + else: + keep_overlap = (data >= overlap) + + # 4.3) ΔlogFC filter + if max_lfc_delta is None: + keep_lfc = np.ones_like(data, dtype=bool) + else: + diffs = np.abs(lfc_vals[rows] - lfc_vals[cols]) + keep_lfc = (diffs <= max_lfc_delta) + + # 5) Combine masks + keep_mask = keep_discord & keep_overlap & keep_lfc + + # 6) Reconstruct pruned adjacency, then binarize + new_rows = rows[keep_mask] + new_cols = cols[keep_mask] + new_data = data[keep_mask] + pruned = sp.coo_matrix((new_data, (new_rows, new_cols)), shape=(M, M)).tocsr() + pruned_bin = (pruned > 0).astype(int).toarray() + + return pruned_bin + + + +@pytest.mark.parametrize("merge_discord_flag, overlap_val, max_lfc_val", [ + (False, 1, None), + (True, 1, None), + (False, 2, None), + (False, 3, None), + (False, 5, None), + (False, 15, None), + (False, 100, None), + (False, 1, 0.5), + (False, 1, 1.0), + (False, 1, 2.0), + (False, 1, 3.0), + (False, 1, 4.0), + (False, 1, 5.0), +]) +@pytest.fixture +def test_sparse_adjacency_filters_match_R(annotate_nhoods_mdata, merge_discord_flag, overlap_val, max_lfc_val): + """ + Compare the output of the R version (via r_pkg) versus the Python version + for various combinations of merge_discord, overlap, and max_lfc_delta. + """ + # 4.1) Extract inputs from mdata + + mdata = annotate_nhoods_mdata.copy() + + nhs = mdata["rna"].obsm["nhoods"].copy() + nhood_adj = mdata["milo"].varp["nhood_connectivities"].copy() # sparse + da_res = mdata["milo"].var.copy() + is_da = (da_res["SpatialFDR"].values < 0.1) & (da_res["logFC"].values > 0) + + # 4.2) Run R version (returns a dense matrix) + r_out = r_pkg._group_nhoods_from_adjacency_pycomp( + _py_to_r(nhs), + _py_to_r(nhood_adj), + _py_to_r(da_res), + _py_to_r(is_da), + _py_to_r(merge_discord_flag), + _py_to_r(max_lfc_val), + _py_to_r(overlap_val), + subset_nhoods = r.ro.NULL + ) + adj_R = _r_to_py(r_out) + # adj_R is a dense NumPy matrix of shape (N, N) + + # 4.3) Run Python version + adj_py = _group_nhoods_from_adjacency_rcomp( + nhood_adj, + da_res, + is_da, + merge_discord = merge_discord_flag, + overlap = overlap_val, + max_lfc_delta = max_lfc_val, + subset_nhoods = None + ) + # adj_py is also a dense NumPy matrix of shape (N, N) + + # 4.4) Compare element‐by‐element + # We convert adj_R (which may be a pandas object) explicitly to NumPy + if not isinstance(adj_R, np.ndarray): + adj_R = np.asarray(adj_R) + assert adj_R.shape == adj_py.shape + # Use a strict equality test (all entries must match) + assert np.array_equal(adj_R, adj_py), \ + f"Difference detected (merge_discord={merge_discord_flag}, overlap={overlap_val}, max_lfc={max_lfc_val})" \ No newline at end of file From f08088dea5f80a4aecde48122aff7750c2aa5e2f Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Sun, 8 Jun 2025 11:44:26 +0200 Subject: [PATCH 02/10] Added nhood grouping functionality group_nhoods, annotate_cells_from_nhoods with two modes, find_nhood_group_markers with default pydeseq2 and optionally edgeR. Statsmodels and limma for logcounts doesnt make sense if counts were normalized with a scale factor. --- pertpy/tools/__init__.py | 2 - pertpy/tools/_milo.py | 2126 +++++++++++++++++++++++++---- pertpy/utils/__init__.py | 0 pertpy/utils/_lazy_r_namespace.py | 22 - pertpy/utils/rpy2_utils.py | 245 ---- 5 files changed, 1895 insertions(+), 500 deletions(-) delete mode 100644 pertpy/utils/__init__.py delete mode 100644 pertpy/utils/_lazy_r_namespace.py delete mode 100644 pertpy/utils/rpy2_utils.py diff --git a/pertpy/tools/__init__.py b/pertpy/tools/__init__.py index 791f5b86..69ba58ff 100644 --- a/pertpy/tools/__init__.py +++ b/pertpy/tools/__init__.py @@ -52,7 +52,6 @@ def __init__(self, *args, **kwargs): TTest = lazy_import("pertpy.tools._differential_gene_expression", "TTest", DE_EXTRAS) WilcoxonTest = lazy_import("pertpy.tools._differential_gene_expression", "WilcoxonTest", DE_EXTRAS) -from ._milo import group_nhoods __all__ = [ "Augur", @@ -79,5 +78,4 @@ def __init__(self, *args, **kwargs): "KMeansSpace", "PseudobulkSpace", "Scgen", - "group_nhoods", ] diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index e5932ce4..61766a33 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -3,7 +3,7 @@ import random import re from importlib.util import find_spec -from typing import TYPE_CHECKING, Literal +from typing import TYPE_CHECKING, Any, Literal, Optional import matplotlib.pyplot as plt import numpy as np @@ -12,21 +12,32 @@ import seaborn as sns from anndata import AnnData from lamin_utils import logger +from matplotlib.axes import Axes +from matplotlib.cm import ScalarMappable +from matplotlib.colors import Colormap, Normalize from mudata import MuData from pertpy._doc import _doc_params, doc_common_plot_args if TYPE_CHECKING: - from collections.abc import Sequence + from collections.abc import Collection, Sequence from matplotlib.axes import Axes from matplotlib.colors import Colormap from matplotlib.figure import Figure -from scipy.sparse import csr_matrix +from scipy.sparse import coo_matrix, csr_matrix, issparse, spmatrix from sklearn.metrics.pairwise import euclidean_distances +def _is_counts(array: np.ndarray | spmatrix) -> bool: + """Check if the array is a count matrix.""" + if issparse(array): + return bool(np.all(np.mod(array.data, 1) == 0)) + else: + return bool(np.all(np.mod(array, 1) == 0)) + + class Milo: """Python implementation of Milo.""" @@ -878,6 +889,173 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 plt.show() return None + from collections.abc import Sequence + from typing import Union + + def plot_nhood_annotation( # pragma: no cover + self, + mdata: MuData, + *, + # ------------------------------------------------------------------- + # Styling / filtering parameters for logFC‐based coloring: + alpha: float = 0.1, + min_logFC: float = 0.0, + min_size: int = 10, + plot_edges: bool = False, + title: str = "DA log‐Fold Change", + color_map: Colormap | str | None = None, + palette: str | Sequence[str] | None = None, + ax: Axes | None = None, + return_fig: bool = False, + # ------------------------------------------------------------------- + # New arguments: + adata_key: str = "milo", + annotation_key: str | None = "nhood_annotation", + # ------------------------------------------------------------------- + **kwargs, + ) -> Figure | None: + """Visualize Milo differential‐abundance results on the abstracted neighborhood graph. + + By default (annotation_key=None), nodes are colored by filtered logFC (SpatialFDR ≤ alpha, + |logFC| ≥ min_logFC). If annotation_key is provided, instead draw node colors from + mdata[adata_key].obs[annotation_key]. + + Args: + mdata: MuData object containing at least: + • mdata["milo"] (the Milo‐neighborhood AnnData, transposed) + • mdata[adata_key] (the AnnData where your annotation lives) + alpha: Significance threshold for SpatialFDR (only used if annotation_key is None). + min_logFC: Minimum absolute logFC to display (only used if annotation_key is None). + min_size: Scaling factor: actual marker size = Nhood_size × min_size. + plot_edges: If True, draw edges of the neighborhood overlap graph. + title: Plot title (ignored if annotation_key is not None; you can override if you like). + color_map: Passed through to sc.pl.embedding for discrete palettes (optional). + palette: Passed through to sc.pl.embedding (optional). + ax: Matplotlib Axes to plot on (optional). + return_fig: If True, return the Figure object instead of calling plt.show(). + + adata_key: Key in mdata corresponding to the AnnData whose `.obs` has the annotation. + Default = "rna". + + annotation_key: If not None, the name of a column in mdata[adata_key].obs whose values + should be used to color the Milo neighborhood graph. If provided, + we ignore all logFC / FDR logic and simply color by that annotation. + Example: "nhood_annotation". If None, revert to the original logFC‐based coloring. + + **kwargs: Additional keyword arguments passed to sc.pl.embedding. + + Returns: + If return_fig == True → returns the matplotlib Figure. Otherwise, shows the plot and returns None. + """ + # ------------------------------------------------------------------- + # 1) Extract and copy the Milo neighborhood AnnData: + if "milo" not in mdata.mod: + raise KeyError('Cannot find "milo" modality in mdata. Did you run milo.build_nhood_graph()?') + nhood_adata: AnnData = mdata["milo"].T.copy() # transpose to get nhoods as “cells” + + # ------------------------------------------------------------------- + # 2) If annotation_key is provided, we skip the logFC logic and simply pull + # the annotation from mdata[adata_key].obs. We assume that the neighborhood + # IDs in nhood_adata.obs.index correspond to the same index in mdata[adata_key].obs. + if annotation_key is not None: + if adata_key not in mdata.mod: + raise KeyError(f'Cannot find "{adata_key}" modality in mdata.') + if annotation_key not in nhood_adata.obs.columns: + raise KeyError(f'Cannot find "{annotation_key}" column in mdata["{adata_key}"].obs.') + # Copy the annotation over to the neighborhood AnnData’s obs: + # We assume that nhood_adata.obs.index (e.g. neighborhood IDs) also appear + # as an index in mdata[adata_key].obs so we can simply reindex. + annots = mdata[adata_key].T.obs[annotation_key] + # Subset / align: + if not all(idx in annots.index for idx in nhood_adata.obs.index): + missing = set(nhood_adata.obs.index) - set(annots.index) + raise KeyError(f"The following neighborhood IDs are not found in mdata['{adata_key}'].obs: {missing}") + nhood_adata.obs["graph_color"] = annots.reindex(nhood_adata.obs.index).values + + # We do not filter by logFC or FDR in this mode; we just plot all neighborhoods. + # Sorting: if you want to put ‘NaN’ or a particular annotation at the bottom, + # you could sort by graph_color, but for simplicity we’ll plot in dataset order. + ordered = list(nhood_adata.obs.index) + nhood_adata = nhood_adata[ordered] + + # We no longer need “abs_logFC” or SpatialFDR logic, so skip to plotting. + vmax = None + vmin = None + + # Call scanpy’s embedding plot: + fig = sc.pl.embedding( + nhood_adata, + basis="X_milo_graph", + color="graph_color", + cmap=color_map or "tab20", # default to a discrete palette if none provided + size=nhood_adata.obs["Nhood_size"] * min_size, + edges=plot_edges, + neighbors_key="nhood", + sort_order=False, + frameon=False, + title=f"{annotation_key}", + palette=palette, + ax=ax, + show=False, + **kwargs, + ) + + if return_fig: + return fig + plt.show() + return None + + # ------------------------------------------------------------------- + # 3) Otherwise, annotation_key is None → we do the original logFC‐based coloring: + if "Nhood_size" not in nhood_adata.obs.columns: + raise KeyError( + 'Cannot find "Nhood_size" column in nhood_adata.obs; please run milo.build_nhood_graph() first.' + ) + if "logFC" not in nhood_adata.obs.columns or "SpatialFDR" not in nhood_adata.obs.columns: + raise KeyError( + 'Cannot find "logFC" / "SpatialFDR" columns in nhood_adata.obs; please run milo.da_nhoods() first.' + ) + + # Copy logFC into graph_color, then mask out nonsignificant / small‐effect neighborhoods: + nhood_adata.obs["graph_color"] = nhood_adata.obs["logFC"] + nhood_adata.obs.loc[nhood_adata.obs["SpatialFDR"] > alpha, "graph_color"] = np.nan + nhood_adata.obs["abs_logFC"] = np.abs(nhood_adata.obs["logFC"]) + nhood_adata.obs.loc[nhood_adata.obs["abs_logFC"] < min_logFC, "graph_color"] = np.nan + + # Plot order: neighborhoods with large |logFC| on top + nhood_adata.obs.loc[nhood_adata.obs["graph_color"].isna(), "abs_logFC"] = np.nan + ordered = nhood_adata.obs.sort_values("abs_logFC", na_position="first").index + nhood_adata = nhood_adata[ordered] + + # Determine symmetric color limits: + vmax = np.nanmax([nhood_adata.obs["graph_color"].max(), -nhood_adata.obs["graph_color"].min()]) + vmin = -vmax + + # Finally, call scanpy to draw the embedding: + fig = sc.pl.embedding( + nhood_adata, + basis="X_milo_graph", + color="graph_color", + cmap=color_map or "RdBu_r", + size=nhood_adata.obs["Nhood_size"] * min_size, + edges=plot_edges, + neighbors_key="nhood", + sort_order=False, + frameon=False, + title=title, + vmax=vmax, + vmin=vmin, + palette=palette, + ax=ax, + show=False, + **kwargs, + ) + + if return_fig: + return fig + plt.show() + return None + @_doc_params(common_plot_args=doc_common_plot_args) def plot_nhood( # pragma: no cover # noqa: D417 self, @@ -1139,256 +1317,1742 @@ def plot_nhood_counts_by_cond( # pragma: no cover # noqa: D417 return None + def _group_nhoods_from_adjacency( + self, + adjacency: spmatrix, + da_res: pd.DataFrame, + is_da: np.ndarray, + merge_discord: bool = False, + overlap: int = 1, + max_lfc_delta: float | None = None, + subset_nhoods=None, + ) -> np.ndarray: + """Core neighborhood‐grouping logic (vectorized, no Python loops). + + Inputs: + - adjacency: scipy.sparse square matrix of shape (N, N), + storing neighborhood adjacency (overlap counts). + - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. + - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. + - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. + - overlap: integer threshold; zero edges with weight < overlap. + - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. + - subset_nhoods: None or one of: + • boolean mask (length N), + • list/array of integer indices, + • list/array of string names (matching da_res.index). + Returns: + - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), + giving a Louvain cluster label for each neighborhood (in the same order as da_res). + """ + # 1) Optional subsetting of neighborhoods --------------------------------------------------- + # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. + if subset_nhoods is not None: + if isinstance(subset_nhoods, list | np.ndarray): + # could be integer indices or names + if all(isinstance(x, int | np.integer) for x in subset_nhoods): + # direct integer indices + mask = np.zeros(adjacency.shape[0], dtype=bool) + mask[np.array(subset_nhoods, dtype=int)] = True + else: + # assume list of names + names = np.array(da_res.index, dtype=str) + mask = np.isin(names, subset_nhoods) + elif isinstance(subset_nhoods, pd.Series | np.ndarray) and subset_nhoods.dtype == bool: + # boolean mask + if len(subset_nhoods) != adjacency.shape[0]: + raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") + mask = np.asarray(subset_nhoods, dtype=bool) + else: + raise ValueError("subset_nhoods must be a boolean mask, a list of indices, or a list of names.") -### Neighborhood clustering as in miloR + # Apply subsetting to adjacency, da_res, and is_da + adjacency = adjacency[mask, :][:, mask] + da_res = da_res.loc[mask].copy() + is_da = is_da[mask] + else: + mask = np.ones(adjacency.shape[0], dtype=bool) -import numpy as np -import pandas as pd -import scipy.sparse as sp -import scanpy as sc -from igraph import Graph -from anndata import AnnData + M = adjacency.shape[0] + if da_res.shape[0] != M or is_da.shape[0] != M: + raise ValueError("Length of da_res and is_da must match adjacency dimension after subsetting.") -def _group_nhoods_from_adjacency( - adjacency: sp.spmatrix, - da_res: pd.DataFrame, - is_da: np.ndarray, - merge_discord: bool = False, - overlap: int = 1, - max_lfc_delta: float | None = None, - subset_nhoods=None, -) -> np.ndarray: - """ - Core neighborhood‐grouping logic (vectorized, no Python loops). - Inputs: - - adjacency: scipy.sparse square matrix of shape (N, N), - storing neighborhood adjacency (overlap counts). - - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. - - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. - - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. - - overlap: integer threshold; zero edges with weight < overlap. - - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. - - subset_nhoods: None or one of: - • boolean mask (length N), - • list/array of integer indices, - • list/array of string names (matching da_res.index). - Returns: - - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), - giving a Louvain cluster label for each neighborhood (in the same order as da_res). - """ + # 2) Convert adjacency to CSR (if not already) and then to COO for a flat edge list ---------------- + adjacency = csr_matrix(adjacency) if not issparse(adjacency) else adjacency.tocsr() - # 1) Optional subsetting of neighborhoods --------------------------------------------------- - # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. - if subset_nhoods is not None: - if isinstance(subset_nhoods, (list, np.ndarray)): - # could be integer indices or names - if all(isinstance(x, (int, np.integer)) for x in subset_nhoods): - # direct integer indices - mask = np.zeros(adjacency.shape[0], dtype=bool) - mask[np.array(subset_nhoods, dtype=int)] = True - else: - # assume list of names - names = np.array(da_res.index, dtype=str) - mask = np.isin(names, subset_nhoods) - elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: - # boolean mask - if len(subset_nhoods) != adjacency.shape[0]: - raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") - mask = np.asarray(subset_nhoods, dtype=bool) + Acoo = adjacency.tocoo() + rows = Acoo.row # array of length E = number of nonzero edges + cols = Acoo.col + data = Acoo.data # the actual overlap counts + + # 3) Precompute logFC and sign arrays ------------------------------------------------------------------- + lfc_vals = da_res["logFC"].values # shape = (M,) + signs = np.sign(lfc_vals) # sign(lfc_i), shape = (M,) + + # 4) Build Boolean masks (length E) for each filter ------------------------------------------------------ + + # 4.1) “Discord” filter: if merge_discord=False, drop any edge (i,j) where both i,j are DA + # AND sign(lfc_i) * sign(lfc_j) < 0 (opposite signs). + if merge_discord: + keep_discord = np.ones_like(data, dtype=bool) else: - raise ValueError("subset_nhoods must be a boolean mask, a list of indices, or a list of names.") + # For each edge k at (i=rows[k], j=cols[k]), check if both are DA AND signs differ + is_da_rows = is_da[rows] # True if endpoint‐i is DA + is_da_cols = is_da[cols] # True if endpoint‐j is DA + sign_rows = signs[rows] + sign_cols = signs[cols] + + # discord_pair[k] = True if both DA and (signs multiply < 0) + discord_pair = (is_da_rows & is_da_cols) & ((sign_rows * sign_cols) < 0) + keep_discord = ~discord_pair + + # 4.2) “Overlap” filter: drop any edge whose current weight < overlap + keep_overlap = np.ones_like(data, dtype=bool) if overlap <= 1 else data >= overlap + + # 4.3) “Δ logFC” filter: drop any edge where |lfc_i - lfc_j| > max_lfc_delta + if max_lfc_delta is None: + keep_lfc = np.ones_like(data, dtype=bool) + else: + # Compute |lfc_vals[rows] - lfc_vals[cols]| vectorized + lfc_edge_diffs = np.abs(lfc_vals[rows] - lfc_vals[cols]) + keep_lfc = lfc_edge_diffs <= max_lfc_delta - # Apply subsetting to adjacency, da_res, and is_da - adjacency = adjacency[mask, :][:, mask] - da_res = da_res.loc[mask].copy() - is_da = is_da[mask] - else: - mask = np.ones(adjacency.shape[0], dtype=bool) + # 5) Combine all masks into a single “keep” mask ---------------------------------------------------------------- + keep_mask = keep_discord & keep_overlap & keep_lfc - M = adjacency.shape[0] - if da_res.shape[0] != M or is_da.shape[0] != M: - raise ValueError("Length of da_res and is_da must match adjacency dimension after subsetting.") + # 6) Rebuild a new, pruned adjacency in COO form (only edges where keep_mask=True) -------------------------- + new_rows = rows[keep_mask] + new_cols = cols[keep_mask] + new_data = data[keep_mask] - # 2) Convert adjacency to CSR (if not already) and then to COO for a flat edge list ---------------- - if not sp.issparse(adjacency): - adjacency = sp.csr_matrix(adjacency) - else: - adjacency = adjacency.tocsr() + # If you want an unweighted graph (just connectivity), you could do `new_data = np.ones_like(new_rows)`. + # But to mirror MiloR exactly, we preserve the original overlap counts until the final binarization. + pruned_adj = coo_matrix((new_data, (new_rows, new_cols)), shape=(M, M)).tocsr() - Acoo = adjacency.tocoo() - rows = Acoo.row # array of length E = number of nonzero edges - cols = Acoo.col - data = Acoo.data # the actual overlap counts + # 7) Binarize: every surviving edge → 1, then convert to CSR ---------------------------------------------------------------- + pruned_adj = (pruned_adj > 0).astype(int).tocsr() - # 3) Precompute logFC and sign arrays ------------------------------------------------------------------- - lfc_vals = da_res["logFC"].values # shape = (M,) - signs = np.sign(lfc_vals) # sign(lfc_i), shape = (M,) + # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- + # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. + g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) - # 4) Build Boolean masks (length E) for each filter ------------------------------------------------------ + # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- + # By not providing a “weights” argument, igraph treats every edge as weight=1. + clustering = g.community_multilevel(weights=None) + labels = np.array(clustering.membership, dtype=str) # length = M, dtype = 'str' - # 4.1) “Discord” filter: if merge_discord=False, drop any edge (i,j) where both i,j are DA - # AND sign(lfc_i) * sign(lfc_j) < 0 (opposite signs). - if merge_discord: - keep_discord = np.ones_like(data, dtype=bool) - else: - # For each edge k at (i=rows[k], j=cols[k]), check if both are DA AND signs differ - is_da_rows = is_da[rows] # True if endpoint‐i is DA - is_da_cols = is_da[cols] # True if endpoint‐j is DA - sign_rows = signs[rows] - sign_cols = signs[cols] - - # discord_pair[k] = True if both DA and (signs multiply < 0) - discord_pair = (is_da_rows & is_da_cols) & ((sign_rows * sign_cols) < 0) - keep_discord = ~discord_pair - - # 4.2) “Overlap” filter: drop any edge whose current weight < overlap - if overlap <= 1: - keep_overlap = np.ones_like(data, dtype=bool) - else: - keep_overlap = (data >= overlap) + # 10) Return the cluster labels array (strings), in the same order as da_res.index --------------------------------------- + # If subset_nhoods was not None, these labels correspond to rows where mask=True. + return labels - # 4.3) “Δ logFC” filter: drop any edge where |lfc_i - lfc_j| > max_lfc_delta - if max_lfc_delta is None: - keep_lfc = np.ones_like(data, dtype=bool) - else: - # Compute |lfc_vals[rows] - lfc_vals[cols]| vectorized - lfc_edge_diffs = np.abs(lfc_vals[rows] - lfc_vals[cols]) - keep_lfc = (lfc_edge_diffs <= max_lfc_delta) - - # 5) Combine all masks into a single “keep” mask ---------------------------------------------------------------- - keep_mask = keep_discord & keep_overlap & keep_lfc - - # 6) Rebuild a new, pruned adjacency in COO form (only edges where keep_mask=True) -------------------------- - new_rows = rows[keep_mask] - new_cols = cols[keep_mask] - new_data = data[keep_mask] - - # If you want an unweighted graph (just connectivity), you could do `new_data = np.ones_like(new_rows)`. - # But to mirror MiloR exactly, we preserve the original overlap counts until the final binarization. - pruned_adj = sp.coo_matrix((new_data, (new_rows, new_cols)), shape=(M, M)).tocsr() - - # 7) Binarize: every surviving edge → 1, then convert to CSR ---------------------------------------------------------------- - pruned_adj = (pruned_adj > 0).astype(int).tocsr() - - # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- - # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. - g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) - - # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- - # By not providing a “weights” argument, igraph treats every edge as weight=1. - clustering = g.community_multilevel(weights=None) - labels = np.array(clustering.membership, dtype=str) # length = M, dtype = 'str' - - # 10) Return the cluster labels array (strings), in the same order as da_res.index --------------------------------------- - # If subset_nhoods was not None, these labels correspond to rows where mask=True. - return labels - -def group_nhoods( - adata: AnnData, - da_res: pd.DataFrame | None = None, - da_fdr: float = 0.1, - overlap: int = 1, - max_lfc_delta: float | None = None, - merge_discord: bool = False, - subset_nhoods=None, -) -> pd.DataFrame: - """ - Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. - - Parameters - ---------- - adata : AnnData - Must contain: - - `adata.var` with columns "SpatialFDR" (float) and "logFC" (float) - - `adata.varp["nhood_connectivities"]` as an (N×N) sparse adjacency matrix - da_res : pd.DataFrame, optional - If provided, must match `adata.var`. Otherwise, `adata.var` is used directly. - da_fdr : float, default=0.1 - Neighborhoods with `SpatialFDR < da_fdr` are called “DA.” - overlap : int, default=1 - Drop any adjacency entry (edge) with weight < overlap. - max_lfc_delta : float or None, default=None - If not None, drop edges where |lfc_i - lfc_j| > max_lfc_delta. - merge_discord : bool, default=False - If False, drop edges between DA neighborhoods whose logFC signs disagree. - subset_nhoods : None or boolean mask / list of indices / list of names - If provided, only cluster that subset of neighborhoods. - - Returns - ------- - pd.DataFrame - A copy of `adata.var`, with a new column "NhoodGroup" of dtype string giving each - neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). - """ + def group_nhoods( + self, + data: Any, + key: str | None = "rna", + da_res: pd.DataFrame | None = None, + da_fdr: float = 0.1, + overlap: int = 1, + max_lfc_delta: float | None = None, + merge_discord: bool = False, + subset_nhoods=None, + ) -> pd.DataFrame: + """Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. + + Parameters + ---------- + adata : AnnData + Must contain: + - `adata.var` with columns "SpatialFDR" (float) and "logFC" (float) + - `adata.varp["nhood_connectivities"]` as an (N×N) sparse adjacency matrix + da_res : pd.DataFrame, optional + If provided, must match `adata.var`. Otherwise, `adata.var` is used directly. + da_fdr : float, default=0.1 + Neighborhoods with `SpatialFDR < da_fdr` are called “DA.” + overlap : int, default=1 + Drop any adjacency entry (edge) with weight < overlap. + max_lfc_delta : float or None, default=None + If not None, drop edges where |lfc_i - lfc_j| > max_lfc_delta. + merge_discord : bool, default=False + If False, drop edges between DA neighborhoods whose logFC signs disagree. + subset_nhoods : None or boolean mask / list of indices / list of names + If provided, only cluster that subset of neighborhoods. - # 1) Validate input --------------------------------------------------------------------------------------------- - if not isinstance(adata, AnnData): - raise ValueError("`adata` must be an AnnData object.") + Returns: + ------- + pd.DataFrame + A copy of `adata.var`, with a new column "nhood_groups" of dtype string giving each + neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). - # 2) Get or check `da_res` -------------------------------------------------------------------------------------- - if da_res is None: - da_res = adata.var - else: + + Examples: + >>> import pertpy as pt + >>> adata = pt.dt.bhattacherjee() + >>> milo = pt.tl.Milo() + >>> mdata = milo.load(adata) + >>> sc.pp.neighbors(mdata["rna"]) + >>> milo.make_nhoods(mdata["rna"]) + >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") + >>> milo.da_nhoods(mdata, design="~label") + >>> milo.group_nhoods(mdata) + """ + if isinstance(data, AnnData): + adata = data + elif isinstance(data, MuData): + if key is None: + raise ValueError("If `data` is a MuData object, `key` must be specified.") + adata = data[key] + else: + raise ValueError("`data` must be an AnnData or MuData object.") + + # 1) Validate input --------------------------------------------------------------------------------------------- + if not isinstance(adata, AnnData): + raise ValueError("`adata` must be an AnnData object.") + + # 2) Get or check `da_res` -------------------------------------------------------------------------------------- + if da_res is None: + da_res = adata.var # If user passed their own da_res, ensure indexes match - if not da_res.index.equals(adata.var.index): + elif not da_res.index.equals(adata.var.index): raise ValueError("`da_res` index must match `adata.var.index`.") - # Ensure required columns exist - if "SpatialFDR" not in da_res.columns or "logFC" not in da_res.columns: - raise ValueError("`da_res` (adata.var) must contain columns 'SpatialFDR' and 'logFC'.") - - # 3) Identify “DA” neighborhoods by FDR cutoff ------------------------------------------------------------------- - fdr_values = da_res["SpatialFDR"].values - if np.all(pd.isna(fdr_values)): - raise ValueError("All `SpatialFDR` values are NA; cannot determine DA neighborhoods.") - is_da = (fdr_values < da_fdr) - - n_da = int(is_da.sum()) - if n_da == 0: - raise ValueError(f"No DA neighborhoods found at FDR < {da_fdr}.") - - # 4) Extract adjacency ------------------------------------------------------------------------------------------ - if "nhood_connectivities" not in adata.varp: - raise KeyError("`adata.varp` does not contain 'nhood_connectivities'. Did you run buildNhoodGraph?") - adjacency = adata.varp["nhood_connectivities"] - - # 5) Call core worker to get string labels ---------------------------------------------------------------------- - labels = _group_nhoods_from_adjacency( - adjacency = adjacency, - da_res = da_res, - is_da = is_da, - merge_discord = merge_discord, - overlap = overlap, - max_lfc_delta = max_lfc_delta, - subset_nhoods = subset_nhoods, - ) + # Ensure required columns exist + if "SpatialFDR" not in da_res.columns or "logFC" not in da_res.columns: + raise ValueError("`da_res` (adata.var) must contain columns 'SpatialFDR' and 'logFC'.") + + # 3) Identify “DA” neighborhoods by FDR cutoff ------------------------------------------------------------------- + fdr_values = da_res["SpatialFDR"].values + if np.all(pd.isna(fdr_values)): + raise ValueError("All `SpatialFDR` values are NA; cannot determine DA neighborhoods.") + is_da = fdr_values < da_fdr + + n_da = int(is_da.sum()) + if n_da == 0: + raise ValueError(f"No DA neighborhoods found at FDR < {da_fdr}.") + + # 4) Extract adjacency ------------------------------------------------------------------------------------------ + if "nhood_connectivities" not in adata.varp: + raise KeyError("`adata.varp` does not contain 'nhood_connectivities'. Did you run buildNhoodGraph?") + adjacency = adata.varp["nhood_connectivities"] + + # 5) Call core worker to get string labels ---------------------------------------------------------------------- + labels = self._group_nhoods_from_adjacency( + adjacency=adjacency, + da_res=da_res, + is_da=is_da, + merge_discord=merge_discord, + overlap=overlap, + max_lfc_delta=max_lfc_delta, + subset_nhoods=subset_nhoods, + ) - # 6) Write results back into `adata.var["NhoodGroup"]` ----------------------------------------------------------- - N_full = adata.var.shape[0] - out = np.array([""] * N_full, dtype=object) - out[:] = pd.NA + # 6) Write results back into `adata.var["NhoodGroup"]` ----------------------------------------------------------- + N_full = adata.var.shape[0] + out = np.array([""] * N_full, dtype=object) + out[:] = pd.NA - if subset_nhoods is None: - # Every neighborhood was labeled - out[:] = labels - else: - # Reconstruct the same mask logic to place `labels` in the correct positions - if isinstance(subset_nhoods, (list, np.ndarray)): - arr = np.asarray(subset_nhoods) - if np.issubdtype(arr.dtype, np.integer): - mask_idx = np.zeros(N_full, dtype=bool) - mask_idx[arr.astype(int)] = True + if subset_nhoods is None: + # Every neighborhood was labeled + out[:] = labels + else: + # Reconstruct the same mask logic to place `labels` in the correct positions + if isinstance(subset_nhoods, list | np.ndarray): + arr = np.asarray(subset_nhoods) + if np.issubdtype(arr.dtype, np.integer): + mask_idx = np.zeros(N_full, dtype=bool) + mask_idx[arr.astype(int)] = True + else: + names = np.array(adata.var.index, dtype=str) + mask_idx = np.isin(names, arr.astype(str)) + elif isinstance(subset_nhoods, pd.Series | np.ndarray) and subset_nhoods.dtype == bool: + if len(subset_nhoods) != N_full: + raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") + mask_idx = np.asarray(subset_nhoods, dtype=bool) + else: + raise ValueError("`subset_nhoods` must be a boolean mask, a list of indices, or a list of names.") + + out[mask_idx] = labels + + adata.var["nhood_groups"] = out + + def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_groups", subset_nhoods=None): + nhood_mat = mdata["rna"].obsm["nhoods"] + + da_res = mdata["milo"].var.copy() + + nhood_mat = AnnData(X=nhood_mat) + nhood_mat.obs_names = mdata["rna"].obs_names + nhood_mat.var_names = [str(i) for i in range(nhood_mat.shape[1])] + + nhs_da_gr = da_res[nhood_group_obs].copy() + nhs_da_gr.index = da_res.index.to_numpy() + + nhood_gr = da_res.dropna()[nhood_group_obs].unique() + + nhs = nhood_mat.copy() + + # if(!is.null(subset.nhoods)){ + # nhs <- nhs[,subset.nhoods] + ## # ## Remove cells out of neighbourhoods of interest + # # nhs <- nhs[rowSums(nhs) > 0,] + # } + + if subset_nhoods is not None: + nhs = nhs[:, subset_nhoods] + nhs = nhs[np.asarray(nhs.X.sum(1)).ravel() > 0, :].copy() + + fake_meta = pd.DataFrame( + { + "CellID": nhs.obs_names[(np.asarray(nhs.X.sum(1).flatten()).ravel() != 0)], + "Nhood_Group": [np.nan for _ in range((np.asarray(nhs.X.sum(1).flatten()).ravel() != 0).sum())], + } + ) + fake_meta.index = fake_meta["CellID"].copy() + + for i in range(len(nhood_gr)): + cur_nh_group = nhood_gr[i] + + nhood_x = nhs_da_gr == cur_nh_group + nhood_x = nhood_x[nhood_x] + nhood_x = nhood_x.index + nhood_x = np.asarray(nhood_x) + + nhs = nhs[nhs.X.sum(1) > 0, :].copy() + + mask = np.asarray(nhs[:, nhood_x].X.sum(1)).ravel() > 0 + nhood_gr_cells = nhs.obs_names[mask] + + # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = cur_nh_group#fake_meta.loc[nhood_gr_cells, "Nhood_Group"].apply(lambda x: cur_nh_group if np.isnan(x) else np.nan) + # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = [cur_nh_group if np.isnan(x) else np.nan for x in fake_meta.loc[nhood_gr_cells, "Nhood_Group"]] + # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = fake_meta.loc[nhood_gr_cells, "Nhood_Group"].apply(lambda x: cur_nh_group if np.isnan(x) else np.nan) + # for i in range(len(nhood_gr)): # Assuming you want to iterate over nhood.gr + + fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = np.where( + (fake_meta.loc[nhood_gr_cells, "Nhood_Group"]).isna(), + nhood_gr[i], + pd.NA, + # np.nan + ) + # fake_meta.loc[fake_meta.Nhood_Group.] + mdata["rna"].obs["nhood_groups"] = np.nan + mdata["rna"].obs.loc[fake_meta.CellID.to_list(), "nhood_groups"] = fake_meta.Nhood_Group.to_numpy() + + def _get_cells_in_nhoods(self, adata, nhood_ids): + """Get cells in neighbourhoods of interest, store the number of neighbourhoods for each cell in adata.obs['in_nhoods'].""" + in_nhoods = np.array(adata.obsm["nhoods"][:, nhood_ids.astype("int")].sum(1)) + adata.obs["in_nhoods"] = in_nhoods + + def _nhood_labels_to_cells_exclude_overlaps( + self, + mdata, + nhood_group_obs: str = "nhood_groups", + min_n_nhoods: int = 3, + ): + groups = mdata["milo"].var[nhood_group_obs].dropna().unique() + for g in groups: + nhoods_oi = mdata["milo"].var_names[mdata["milo"].var[nhood_group_obs] == g] + self._get_cells_in_nhoods(mdata["rna"], nhoods_oi) + mdata["rna"].obs[f"in_nhoods_{g}"] = mdata["rna"].obs["in_nhoods"].copy() + + ## Find most representative group (cell belongs to mostly to neighbourhoods of that group) + mdata["rna"].obs["nhood_groups"] = np.nan + mdata["rna"].obs["nhood_groups"] = mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]].idxmax(1) + ## Keep only if cell is in at least min_n_nhoods nhoods of the same group + mdata["rna"].obs.loc[ + ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), "nhood_groups" + ] = np.nan + + def annotate_cells_from_nhoods( + self, + mdata: MuData, + nhood_group_obs: str = "nhood_groups", + subset_nhoods: list[str] | None = None, + min_n_nhoods: int = 3, + mode: Literal["last_wins", "exclude_overlaps"] = "last_wins", + ) -> None: + """Annotate cells with neighborhood group labels. + + Parameters: + ----------- + mdata: MuData object with 'milo' modality. + nhood_group_obs: Column in `mdata["milo"].var` to use for neighborhood group labels. + subset_nhoods: List of neighborhood IDs to consider. If None, all neighborhoods are used. + min_n_nhoods: Minimum number of neighborhoods a cell must belong to in order to be annotated. Used for mode "exclude_overlaps". + mode: Mode for annotation. Options are: + - "last_wins": Last neighborhood label wins, adapted from miloR. + - "exclude_overlaps": Exclude overlaps, keeping only the most representative cells within groups. + + Returns: + -------- + None: Modifies `mdata["rna"].obs` in place, adding a column `nhood_groups` with the assigned labels. + + Examples: + >>> import pertpy as pt + >>> adata = pt.dt.bhattacherjee() + >>> milo = pt.tl.Milo() + >>> mdata = milo.load(adata) + >>> sc.pp.neighbors(mdata["rna"]) + >>> milo.make_nhoods(mdata["rna"]) + >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") + >>> milo.da_nhoods(mdata, design="~label") + >>> milo.group_nhoods(mdata) + >>> milo.annotate_cells_from_nhoods(mdata, mode="last_wins") + >>> milo.annotate_cells_from_nhoods(mdata, mode="exclude_overlaps", min_n_nhoods=3) + """ + if mode == "last_wins": + self._nhood_labels_to_cells_last_wins(mdata, nhood_group_obs, subset_nhoods) + elif mode == "exclude_overlaps": + self._nhood_labels_to_cells_exclude_overlaps(mdata, nhood_group_obs, min_n_nhoods) + else: + raise ValueError(f"Unknown mode '{mode}'. Use 'last_wins' or 'exclude_overlaps'.") + + def get_mean_expression(self, adata, groupby: str, var_names: list[str]) -> pd.DataFrame: + """Compute the *mean* expression (counts) of each gene in `var_names`, stratified by a categorical column `groupby` in adata.obs. + + Parameters + ---------- + adata : AnnData + AnnData object containing the expression matrix in `.X` and categorical metadata in `.obs`. + groupby : str + Column name in `adata.obs` that contains the categorical variable to group by. + var_names : list of str + List of gene names (or variable names) for which to compute the mean expression. + + Returns: + ------- + mean_df : pandas.DataFrame (n_genes × n_groups) + Rows are `var_names`, columns are the unique categories of `adata.obs[groupby]`. + Each entry mean_df.loc[g, grp] = (sum of adata[:, g].X over all cells in `grp`) + / (number of cells in that `grp`). + """ + # 1) Subset the matrix to just the columns (genes) in var_names: + subX = adata[:, var_names].X.copy() # shape: (n_cells, n_genes) + + # 2) Build a one‐hot (dummy) matrix of shape (n_cells, n_groups): + groups = pd.get_dummies(adata.obs[groupby], drop_first=False) + # groups.values is (n_cells, n_groups). groups.sum() is a Series: number of cells per group. + n_per_group = groups.sum().astype(float) # length = n_groups + + # 3) Compute Σ_counts_{gene i, group j} by matrix‐multiplication: + # - If subX is sparse, convert to a CSR; otherwise treat as dense. + if issparse(subX): + subX = csr_matrix(subX) + sum_counts = subX.T.dot(csr_matrix(groups.values)) # shape (n_genes, n_groups), sparse + sum_counts = sum_counts.toarray() # convert to dense (n_genes, n_groups) + else: + # dense case: subX is (n_cells, n_genes), so subX.T is (n_genes, n_cells), + # dot with (n_cells, n_groups) → (n_genes, n_groups) + sum_counts = subX.T.dot(groups.values) + + # 4) Divide each column (group) by its total cell count to get means: + # We want mean_counts[i, j] = sum_counts[i, j] / n_per_group[j]. + # n_per_group.values is shape (n_groups,), so broadcasting works. + mean_mat = sum_counts / n_per_group.values[np.newaxis, :] + + # 5) Build a DataFrame, indexed by var_names, columns = groups.columns + mean_df = pd.DataFrame(mean_mat, index=var_names, columns=groups.columns) + return mean_df + + def _run_limma_trend_contrasts( + self, + pdata: AnnData, + nhood_group_obs: str, + *, + formula: str, + group_to_compare: str | None = None, + baseline: str | None = None, + subset_samples: list[str] | None = None, + ) -> pd.DataFrame: + """Run limma (with trend) on a pseudobulk AnnData whose .X is continuous (e.g. log‐CPM). + + If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. + Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. + + Returns a pandas DataFrame with columns: + ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). + """ + if _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") + + # ──────────────────────────────────────────────────────────────────────────────── + # 0) Imports and R‐setup + # ──────────────────────────────────────────────────────────────────────────────── + edger, limma, rstats, rbase = self._setup_rpy2() + import rpy2.robjects as ro + from formulaic_contrasts import FormulaicContrasts + from rpy2.robjects import IntVector, StrVector, baseenv, numpy2ri, pandas2ri + from rpy2.robjects.conversion import localconverter + + # ──────────────────────────────────────────────────────────────────────────────── + # 1) Pull out (n_cells × n_genes) continuous expression matrix and transpose + # so we get (n_genes × n_cells), as required by limma. + # ──────────────────────────────────────────────────────────────────────────────── + expr_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T + + # ──────────────────────────────────────────────────────────────────────────────── + # 2) Build sample_obs (optionally subset to a given list of sample‐IDs) + # ──────────────────────────────────────────────────────────────────────────────── + sample_obs = pdata.obs.copy() + if subset_samples is not None: + sample_obs = sample_obs.loc[subset_samples] + expr_mat = expr_mat[:, np.isin(pdata.obs_names, subset_samples)] + + # ──────────────────────────────────────────────────────────────────────────────── + # 3) Build FormulaicContrasts on the full sample_obs to get “baseline” design + # ──────────────────────────────────────────────────────────────────────────────── + fc_full = FormulaicContrasts(sample_obs, formula) + design_df = pd.DataFrame(fc_full.design_matrix) # ○ shape = (n_samples × K) + with localconverter(ro.default_converter + pandas2ri.converter): + design_r = pandas2ri.py2rpy(design_df) + design_r = rbase.as_matrix(design_r) # R matrix (n_samples × K) + + # ──────────────────────────────────────────────────────────────────────────────── + # 4) Convert expr_mat → an R matrix with rownames & colnames + # ──────────────────────────────────────────────────────────────────────────────── + r_mat = numpy2ri.py2rpy(expr_mat) # now an R “matrix” of shape (n_genes × n_cells) + r_colnames = StrVector(np.asarray(sample_obs.index)) + r_rownames = StrVector(np.asarray(pdata.var_names)) + dim_list = ro.r.list(r_rownames, r_colnames) + assign_dim = baseenv["dimnames<-"] + r_mat = assign_dim(r_mat, dim_list) + + # ──────────────────────────────────────────────────────────────────────────────── + # 5) Fit the linear model (lmFit) once on the “baseline” design + # We skip voom because pdata.X is already log‐normalized. Then call eBayes(..., trend=TRUE). + # ──────────────────────────────────────────────────────────────────────────────── + fit = limma.lmFit(r_mat, design_r) + # fit = limma.eBayes(fit, trend=True,) + + # ──────────────────────────────────────────────────────────────────────────────── + # 6) SINGLE‐CONTRAST branch + # ──────────────────────────────────────────────────────────────────────────────── + if group_to_compare is not None and baseline is not None: + # (a) Build contrast vector from fc_full: + cont = fc_full.contrast(nhood_group_obs, baseline, group_to_compare) + r_contrast = IntVector(np.asarray(cont)) + + # (b) Fit contrasts & re‐run eBayes (with trend) on that single contrast: + fit2 = limma.contrasts_fit(fit, contrasts=r_contrast) + fit2 = limma.eBayes(fit2, trend=True, robust=True) + + # (c) Extract topTable for coefficient 1 (the single contrast) + top = limma.topTable(fit2, coef=1, sort_by="none", number=np.inf) + with localconverter(ro.default_converter + pandas2ri.converter): + top_df = pandas2ri.rpy2py(top) + + # (d) Rename columns: “adj.P.Val”→“adj_PValue”, “P.Value”→“PValue” + top_df = top_df.rename(columns={"adj.P.Val": "adj_PValue", "P.Value": "PValue"}) + top_df = top_df.reset_index().rename(columns={"index": "variable"}) + return top_df[["variable", "logFC", "t", "B", "PValue", "adj_PValue"]] + + # ──────────────────────────────────────────────────────────────────────────────── + # 7) ONE‐VS‐REST branch (group_to_compare == baseline == None) + # ──────────────────────────────────────────────────────────────────────────────── + col = sample_obs[nhood_group_obs] + unique_groups = col.cat.categories.tolist() if pd.api.types.is_categorical_dtype(col) else col.unique().tolist() + + results_list: list[Any] = [] + + for grp in unique_groups: + # (a) Recode sample_obs so that non‐grp → "rest" + tmp_obs = sample_obs.copy() + tmp_obs[nhood_group_obs] = tmp_obs[nhood_group_obs].cat.add_categories("rest") + tmp_obs[nhood_group_obs] = tmp_obs[nhood_group_obs].apply(lambda x, grp=grp: x if x == grp else "rest") + + # (b) Build FormulaicContrasts on tmp_obs with same formula + fc_sub = FormulaicContrasts(tmp_obs, formula) + design_df = pd.DataFrame(fc_sub.design_matrix) + + with localconverter(ro.default_converter + pandas2ri.converter): + design_r_sub = pandas2ri.py2rpy(design_df) + design_r_sub = rbase.as_matrix(design_r_sub) + + # (c) Re‐fit lmFit + eBayes(trend=True) on exactly the same r_mat but new design + fit_sub = limma.lmFit(r_mat, design_r_sub) + fit_sub = limma.eBayes(fit_sub, trend=True, robust=True) + + # (d) Contrast “rest vs grp” + cont_sub = fc_sub.contrast(nhood_group_obs, "rest", grp) + r_cont_sub = IntVector(np.asarray(cont_sub)) + + fit_sub2 = limma.contrasts_fit(fit_sub, contrasts=r_cont_sub) + fit_sub2 = limma.eBayes(fit_sub2, trend=True, robust=True) + + # (e) topTable on that contrast + top_sub = limma.topTable(fit_sub2, coef=1, sort_by="none", number=np.inf) + with localconverter(ro.default_converter + pandas2ri.converter): + top_df_sub = pandas2ri.rpy2py(top_sub) + + top_df_sub = top_df_sub.rename(columns={"adj.P.Val": "adj_PValue", "P.Value": "PValue"}) + top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) + top_df_sub["group"] = grp + + results_list.append(top_df_sub[["variable", "logFC", "t", "B", "PValue", "adj_PValue", "group"]]) + + # (f) Concatenate results and return + final_df = pd.concat(results_list, ignore_index=True) + return final_df + + def _run_edger_contrasts( + self, + pdata: AnnData, + nhood_group_obs: str, + *, + formula: str, + group_to_compare: str | None = None, + baseline: str | None = None, + subset_samples: list[str] | None = None, + ) -> pd.DataFrame: + """Run edgeR QLF tests on a pseudobulk AnnData. + + If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. + Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. + + Returns a pandas DataFrame with columns: + ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). + """ + if not _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") + + edger, limma, rstats, rbase = self._setup_rpy2() + import rpy2.robjects as ro + from formulaic_contrasts import FormulaicContrasts + from rpy2.robjects import IntVector, StrVector, baseenv, numpy2ri, pandas2ri + from rpy2.robjects.conversion import localconverter + + count_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T + + # 2) Build a pandas DataFrame for sample‐level covariates + sample_obs = pdata.obs.copy() + + fc = FormulaicContrasts(sample_obs, formula) + design_df = pd.DataFrame(fc.design_matrix) + with localconverter(ro.default_converter + pandas2ri.converter): + design_r = pandas2ri.py2rpy(design_df) + design_r = rbase.as_matrix(design_r) + + # Wrap the numpy count_mat into an R integer matrix + # with localconverter(ro.default_converter + numpy2ri.converter): + # rmat = numpy2ri + rmat = numpy2ri.py2rpy(count_mat) + + r_colnames = StrVector(np.asarray(pdata.obs_names)) + r_rownames = StrVector(np.asarray(pdata.var_names)) + dim_list = ro.r.list(r_rownames, r_colnames) + + assign_dim = baseenv["dimnames<-"] + rmat = assign_dim(rmat, dim_list) + + # Build the DGEList + dge = edger.DGEList(counts=rmat) + + # Calculate TMM normalization factors + dge = edger.calcNormFactors(dge, method="TMM") + + # Estimate dispersion + # not needed in edgeR 4.x, automatically calculated in the Cpp implementation + # dge = edger.estimateDisp(dge, r_model_mat) + + # Fit the quasi‐likelihood model + fit = edger.glmQLFit(dge, design_r, robust=True) + + # 6) Single‐contrast vs one‐vs‐rest + results_list: list[Any] = [] + + # If a specific two‐level contrast was given: + if group_to_compare is not None and baseline is not None: + contrast_vec = fc.contrast(nhood_group_obs, baseline, group_to_compare) + + r_contrast = IntVector(np.asarray(contrast_vec)) + + # Now run QLF test with that contrast + qlf = edger.glmQLFTest(fit, contrast=r_contrast) + top = edger.topTags(qlf, sort_by="none", n=np.inf)[0] + # Convert top (an R data.frame) to pandas + with localconverter(ro.default_converter + pandas2ri.converter): + top_df = pandas2ri.rpy2py(top) + + # Clean up column names (they come as “logFC”, “PValue”, “FDR”) + top_df = top_df.rename(columns={"FDR": "adj_PValue"}) + top_df = top_df.reset_index().rename(columns={"index": "variable"}) + return top_df + # results_list.append(top_df[["variable", "logFC", "PValue", "adj_PValue"]]) + + else: + col = sample_obs[nhood_group_obs] + if pd.api.types.is_categorical_dtype(col): + unique_groups = col.cat.categories.tolist() else: - names = np.array(adata.var.index, dtype=str) - mask_idx = np.isin(names, arr.astype(str)) - elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: - if len(subset_nhoods) != N_full: - raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") - mask_idx = np.asarray(subset_nhoods, dtype=bool) + unique_groups = col.unique().tolist() + + results_list = [] + + for grp in unique_groups: + tmp_obs = pdata.obs.copy() + + tmp_obs[nhood_group_obs] = [x if x == grp else "rest" for x in tmp_obs[nhood_group_obs]] + tmp_obs[nhood_group_obs] = pd.Categorical(tmp_obs[nhood_group_obs].values, categories=["rest", grp]) + + # 2) Build a new FormulaicContrasts on tmp_obs + fc = FormulaicContrasts(tmp_obs, formula) + design_df = pd.DataFrame(fc.design_matrix) + + with localconverter(ro.default_converter + pandas2ri.converter): + design_r = pandas2ri.py2rpy(design_df) + design_r = rbase.as_matrix(design_r) + + # # 3) Convert design_df_sub to an R matrix + # rmat = numpy2ri.py2rpy(count_mat) + + # r_colnames = StrVector(np.asarray(pdata.obs_names)) + # r_rownames = StrVector(np.asarray(pdata.var_names)) + # dim_list = ro.r.list(r_rownames, r_colnames) + + # assign_dim = baseenv["dimnames<-"] + # rmat = assign_dim(rmat, dim_list) + + # 6) Build a DGEList for this subset (or reuse dge_full but safer to make a fresh one) + dge = edger.calcNormFactors(dge, method="TMM") + fit_sub = edger.glmQLFit(dge, design_r, robust=True) + + # 7) Build contrast vector: “rest” vs “grp” + contrast_vec = fc.contrast(nhood_group_obs, "rest", grp) + contrast_r = IntVector(np.asarray(contrast_vec)) + + # 8) QLF test on that contrast + qlf_sub = edger.glmQLFTest(fit_sub, contrast=contrast_r) + top_sub = edger.topTags(qlf_sub, sort_by="none", n=np.inf)[0] + + with localconverter(ro.default_converter + pandas2ri.converter): + top_df_sub = pandas2ri.rpy2py(top_sub) + + top_df_sub = top_df_sub.rename(columns={"FDR": "adj_PValue"}) + top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) + top_df_sub["group"] = grp + + results_list.append(top_df_sub[["variable", "logFC", "PValue", "adj_PValue", "group"]]) + + # 9) Concatenate and return + final_df = pd.concat(results_list, ignore_index=True) + return final_df + + def _run_pydeseq2_contrasts( + self, + pdata: AnnData, + nhood_group_obs: str, + *, + formula: str, + group_to_compare: str | None = None, + baseline: str | None = None, + alpha: float = 0.05, + quiet: bool = True, + ) -> pd.DataFrame: + """Run PyDESeq2 on a pseudobulk AnnData (`pdata`) with a given neighborhood grouping, using exactly the design `formula` you supply. + + Parameters + ---------- + pdata : AnnData + Pseudobulk AnnData, where .obs[nhood_group_obs] is a categorical allowing + you to compare levels. + + nhood_group_obs : str + The column name in pdata.obs that holds the neighborhood groups. + + formula : str + An R‐style design formula, e.g. "~ batch + Nhood_Group". Must include + `nhood_group_obs` as one of the terms. This is used verbatim for both the + single‐contrast and one‐vs‐rest calls. + + group_to_compare : Optional[str] + If non‐None (and `baseline` is also non‐None), run only the single contrast + [nhood_group_obs, group_to_compare, baseline] with design = `formula`. + + baseline : Optional[str] + If non‐None (and `group_to_compare` is non‐None), run only that one contrast. + If either is None, the function does a one‐vs‐rest loop over all levels of + pdata.obs[nhood_group_obs]. + + alpha : float, default=0.05 + Significance threshold passed to PyrDESeq2’s `DeseqStats`. + + quiet : bool, default=True + Whether to suppress PyDESeq2’s “DESeq2()” progress messages. + + Returns: + ------- + pd.DataFrame + If `group_to_compare` and `baseline` are provided: a DataFrame with columns + ["variable","log_fc","p_value","adj_p_value"], sorted by p_value. + + Otherwise (one‐vs‐rest): a concatenated DataFrame with those columns plus + a “group” column indicating which level was tested vs “rest.” + """ + if find_spec("pydeseq2") is None: + raise ImportError("pydeseq2 is required but not installed. Install with: pip install pydeseq2") + from pydeseq2.dds import DeseqDataSet + from pydeseq2.ds import DeseqStats + + # Basic check: if both group_to_compare & baseline are provided, do just that contrast + if (group_to_compare is not None) ^ (baseline is not None): + raise ValueError("You must supply either both `group_to_compare` and `baseline`, or neither.") + + # 1) Single contrast branch + if group_to_compare is not None and baseline is not None: + # 1a) Build the DESeqDataSet using exactly the provided `formula` + dds = DeseqDataSet(adata=pdata, design=formula, quiet=quiet) + dds.deseq2() + + # 1b) Run PyrDESeq2 with the single contrast + stat_res = DeseqStats( + dds, + contrast=[nhood_group_obs, group_to_compare, baseline], + alpha=alpha, + quiet=quiet, + ) + stat_res.summary() + + # 1c) Collect results into a pandas DataFrame + df = ( + pd.DataFrame(stat_res.results_df) + .rename( + columns={ + "log2FoldChange": "log_fc", + "pvalue": "p_value", + "padj": "adj_p_value", + } + ) + .sort_values("p_value") + .reset_index(drop=True) + ) + return df + + # 2) One‐vs‐rest: get all levels of nhood_group_obs + col = pdata.obs[nhood_group_obs] + unique_groups = col.cat.categories.tolist() if pd.api.types.is_categorical_dtype(col) else col.unique().tolist() + + all_results = [] + for grp in unique_groups: + # 2a) Copy pdata so we can relabel group vs “rest” + tmp = pdata.copy() + + # 2b) Ensure “rest” is a valid category, then recode everything not == grp → "rest" + tmp.obs[nhood_group_obs] = tmp.obs[nhood_group_obs].cat.add_categories("rest") + tmp.obs[nhood_group_obs] = tmp.obs[nhood_group_obs].apply(lambda x, grp=grp: x if x == grp else "rest") + # Now tmp.obs[nhood_group_obs] has exactly two levels: grp and "rest" + + # 2c) Build DESeqDataSet on `tmp` using **the same** `formula` + # (The formula must reference nhood_group_obs so that “grp” vs “rest” is meaningful.) + dds = DeseqDataSet(adata=tmp, design=formula, quiet=quiet) + dds.deseq2() + + # 2d) Run PyrDESeq2 with contrast = [nhood_group_obs, grp, "rest"] + stat_res = DeseqStats( + dds, + contrast=[nhood_group_obs, grp, "rest"], + alpha=alpha, + quiet=quiet, + ) + stat_res.summary() + + # 2e) Extract results, rename, attach “group = grp” + df = ( + pd.DataFrame(stat_res.results_df) + .rename( + columns={ + "log2FoldChange": "log_fc", + "pvalue": "p_value", + "padj": "adj_p_value", + } + ) + .reset_index(names=["variable"]) + .assign(group=grp) + .sort_values("p_value") + .reset_index(drop=True) + ) + + all_results.append(df) + + # 3) Concatenate and return + final_df = pd.concat(all_results, ignore_index=True) + return final_df + + def _filter_by_expr_edger(self, pdata, formula, **kwargs): + """Filter genes in `pdata` based on expression criteria using edgeR.""" + edger, _, rstats, rbase = self._setup_rpy2() + import rpy2.robjects as ro + from rpy2.robjects import numpy2ri, pandas2ri + from rpy2.robjects.conversion import localconverter + + counts = pdata.X + counts = counts.toarray().T if hasattr(counts, "toarray") else np.asarray(counts).T + rcounts = numpy2ri.py2rpy(counts) + obs = pdata.obs + with localconverter(ro.default_converter + pandas2ri.converter): + robs = pandas2ri.py2rpy(obs) + rdesign = rstats.model_matrix(rstats.as_formula(formula), robs) + rkeep = edger.filterByExpr(rcounts, design=rdesign, **kwargs) + keep = list(rkeep) + + pdata._inplace_subset_var(keep) + + def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6, **kwargs): + if _is_counts(pdata.X): + pdata.layers["normalized"] = pdata.X.copy() + sc.pp.normalize_total( + pdata, + target_sum=target_sum, + layer="normalized", + ) + sc.pp.log1p(pdata, layer="normalized") + else: + pdata.layers["normalized"] = pdata.X.copy() + + sc.pp.highly_variable_genes(pdata, layer="normalized", n_top_genes=n_top_genes, subset=True, **kwargs) + + def _filter_highly_variable_scran(self, pdata, n_top_genes): + scran = self._try_import_bioc_library("scran") + scuttle = self._try_import_bioc_library("scuttle") + singlecellexperiment = self._try_import_bioc_library("SingleCellExperiment") + + import rpy2.robjects as ro + from rpy2.robjects import ListVector, numpy2ri, pandas2ri + from rpy2.robjects.conversion import localconverter + + counts = pdata.X + rcounts = numpy2ri.py2rpy(counts.T) + obs = pdata.obs + var = pdata.var + + with localconverter(ro.default_converter + pandas2ri.converter): + robs = pandas2ri.py2rpy(obs) + rvar = pandas2ri.py2rpy(var) + + if _is_counts(counts): + sce = singlecellexperiment.SingleCellExperiment(ListVector({"counts": rcounts}), colData=robs, rowData=rvar) + sce = scuttle.logNormCounts(sce) + else: + sce = singlecellexperiment.SingleCellExperiment( + ListVector({"logcounts": rcounts}), colData=robs, rowData=rvar + ) + + dec = scran.modelGeneVar(sce) + hvgs = scran.getTopHVGs(dec, n=n_top_genes) + hvgs = list(hvgs) + + pdata._inplace_subset_var(hvgs) + + def find_nhood_group_markers( + self, + mdata: MuData, + group_to_compare: str | None = None, + baseline: str | None = None, + nhood_group_obs: str = "nhood_groups", + sample_col: str = "sample", + covariates: Collection[str] | None = None, + key: str = "rna", + pseudobulk_function: str = "sum", + layer: str | None = None, + target_sum: float = 1e6, + n_top_genes: int = 7500, + filter_method: str | None = "scanpy", + var_names: Collection[str] | None = None, + de_method: Literal["pydeseq2", "statsmodels", "edgeR", "limma"] = "pydeseq2", + quiet: bool = True, + alpha: float = 0.05, + use_eb: bool = False, + **kwargs, + ): + """Perform differential expression analysis on neighborhood groups in a MuData object. + + The MuData object must contain a modality with the name `key`, which is used for pseudobulk aggregation. + The column `nhood_group_obs` in `mdata[key]` must contain the neighborhood group labels, and `sample_col` must contain the sample labels. + Neighborhood group labels can be assigned to the single-cell data using ´milo.group_nhoods(...)`, or manually set in `mdata[key].obs[nhood_group_obs]`. + Neighborhood group labels must be strings or categorical values and are used for pseudobulk aggregation. + If both `group_to_compare` and `baseline` are given, runs exactly that contrast. Otherwise, runs one‐vs‐rest for every level of `nhood_group_obs`. + All NAs in mdata[key].obs[nhood_group_obs] are filtered out before running the analysis. + Therefore, if annotating nhood_group_obs manually, introducing NAs before Milo().group_nhoods(...) is can exclude unwanted neighborhoods from the analysis. + + Parameters + ---------- + mdata : MuData + A MuData object containing the data. Must have a modality with the name `key`. + group_to_compare : Optional[str] + If provided, runs a single contrast comparing this group to `baseline`. + baseline : Optional[str] + The reference group for the contrast. Must be provided if `group_to_compare` is provided. + nhood_group_obs : str, default="nhood_groups" + The name of the column in `adata.obs` that contains the neighborhood group labels. + sample_col : str, default="sample" + The name of the column in `adata.obs` that contains the sample labels. + covariates : Collection[str] | None, default=None + A collection of additional covariates to include in the design formula. + If None, no additional covariates are used. + key : str, default="rna" + The key in `mdata` that corresponds to the modality to be used for pseudobulk aggregation. + pseudobulk_function : str, default="sum" + The function to use for pseudobulk aggregation. Can be "sum" or "mean". + layer : str | None, default=None + If provided, the layer to use for pseudobulk aggregation. If None, uses the default layer. + target_sum : float, default=1e6 + The target sum for normalization when using the "scanpy" filter method. + n_top_genes : int, default=7500 + The number of top variable genes to retain after filtering. Only used if `filter_method` is `scanpy` `scran`. + filter_method : str | None, default="scanpy" + The method to use for filtering highly variable genes. Can be "scanpy", "scran", or "filterByExpr". + If None, no filtering is applied. + var_names : Collection[str] | None, default=None + A collection of variable names to restrict the analysis to. If None, all variables are used. + de_method : Literal["pydeseq2", "statsmodels", "edgeR", "limma"], default="pydeseq2" + The method to use for differential expression analysis. Can be "pydeseq2", "statsmodels", "edgeR", or "limma". + quiet : bool, default=True + If True, suppresses output messages from pydeseq2. + alpha : float, default=0.05 + The significance threshold for differential expression analysis in pydeseq2. + use_eb : bool, default=False + If True, applies empirical Bayes moderation to the results in statsmodels. Not for serious use, but a starting point for limma-like differential testing in pure Python. + **kwargs : dict + Additional keyword arguments passed to the filtering methods or differential expression methods. + + Examples: + >>> import pertpy as pt + >>> adata = pt.dt.bhattacherjee() + >>> milo = pt.tl.Milo() + >>> mdata = milo.load(adata) + >>> sc.pp.neighbors(mdata["rna"]) + >>> milo.make_nhoods(mdata["rna"]) + >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") + >>> milo.da_nhoods(mdata, design="~label") + >>> milo.group_nhoods(mdata) + >>> milo.annotate_cells_from_nhoods(mdata) + >>> milo.find_nhood_group_markers(mdata, group_to_compare="3", baseline="1", nhood_group_obs="nhood_groups") + >>> milo.find_nhood_group_markers(mdata, nhood_group_obs="nhood_groups") + """ + func = pseudobulk_function + + # 1) Subset to cells that have a non‐NA group label + if key not in mdata.mod_names: + raise KeyError(f"Modality '{key}' not found in mdata; available keys: {list(mdata.keys())}") + adata = mdata[key] + + if nhood_group_obs not in adata.obs.columns: + raise KeyError(f"Column '{nhood_group_obs}' not found in adata.obs") + if not pd.api.types.is_categorical_dtype(adata.obs[nhood_group_obs]): + adata.obs[nhood_group_obs] = adata.obs[nhood_group_obs].astype("category") + + n_non_na = adata.obs[nhood_group_obs].notna().sum() + if n_non_na == 0: + raise ValueError(f"No non‐NA entries found in '{nhood_group_obs}'") + + if sample_col not in adata.obs.columns: + raise KeyError(f"sample_col '{sample_col}' not in adata.obs") + for cov in covariates or []: + if cov not in adata.obs.columns: + raise KeyError(f"Covariate '{cov}' not found in adata.obs") + + # If you expect “sum” or “mean” you might leave as is; if using a custom layer, check name: + if pseudobulk_function not in ("sum", "mean"): + raise KeyError(f"pseudobulk_function '{pseudobulk_function}' is not in 'sum'/'mean'") + + if var_names is not None: + missing = set(var_names) - set(adata.var_names) + if missing: + raise KeyError(f"These var_names are not in adata.var_names: {missing}") + + if group_to_compare is not None or baseline is not None: + levels = adata.obs[nhood_group_obs].cat.categories.tolist() + if group_to_compare not in levels: + raise ValueError(f"group_to_compare '{group_to_compare}' not a level of '{nhood_group_obs}' ({levels})") + if baseline not in levels: + raise ValueError(f"baseline '{baseline}' not a level of '{nhood_group_obs}' ({levels})") + if group_to_compare == baseline: + raise ValueError("group_to_compare and baseline cannot be the same") + + mask = adata.obs[nhood_group_obs].notna() + tmp_data = adata[mask] + + # 2) Build the list of categorical variables to aggregate by + covariates = [] if covariates is None else list(covariates) + + if sample_col in covariates: + all_variables = [nhood_group_obs] + covariates + else: + all_variables = [sample_col, nhood_group_obs] + covariates + + # 3) Pseudobulk aggregation + # counts_per_sample_group = adata.obs.groupby([sample_col, nhood_group_obs]).size() + # if (counts_per_sample_group == 0).any(): + # raise ValueError("Some (sample, Nhood_Group) combinations have zero cells; pseudobulk would be empty.") + pdata = sc.get.aggregate(tmp_data, by=all_variables, func=func, axis=0, layer=layer) + pdata.X = pdata.layers[func].copy() + + if pdata.obs[nhood_group_obs].nunique() < 2: + raise ValueError(f"After aggregation, '{nhood_group_obs}' has fewer than 2 groups; DEA cannot proceed.") + + if group_to_compare is None and baseline is None: + levels_after = pdata.obs[nhood_group_obs].cat.categories.tolist() + if len(levels_after) < 2: + raise ValueError( + f"Need at least two groups in '{nhood_group_obs}' to run one‐vs‐rest; found {levels_after}" + ) + + # Build the design formula string + if not covariates: + base_formula = "~" + nhood_group_obs + else: + base_formula = "~" + " + ".join(covariates) + " + " + nhood_group_obs + + if var_names is not None: + missing = set(var_names) - set(pdata.var_names) + if missing: + raise KeyError(f"Some var_names not found in pdata.var_names: {missing}") + # In‐place subset to exactly var_names: + pdata._inplace_subset_var(var_names) + # 2) If no var_names, but n_top_genes is None or zero skip filtering. + elif not n_top_genes: + pass + # 3) var_names is None and n_top_genes is a positive integer + elif filter_method == "scanpy": + self._filter_highly_variable_scanpy(pdata, n_top_genes, target_sum) + elif filter_method == "scran": + self._filter_highly_variable_scran(pdata, n_top_genes) + elif filter_method == "filterByExpr": + import inspect + + sig = inspect.signature(self._filter_by_expr_edger) + valid_filter_keys = set(sig.parameters) + filter_kwargs = {} + for kwargs_key in valid_filter_keys & set(kwargs): + filter_kwargs[kwargs_key] = kwargs.pop(key) + if not filter_kwargs: + filter_kwargs = {"min_expr": 1, "min_total": 10, "min_prop": 0.1} + if not _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be continuous expression, but filterByExpr requires raw counts.") + self._filter_by_expr_edger(pdata, base_formula, **filter_kwargs) + else: + raise ValueError(f"filter_method must be 'scanpy', 'scran' or 'filterByExpr', not '{filter_method}'") + + if de_method == "pydeseq2": + if not _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects raw counts.") + return self._run_pydeseq2_contrasts( + pdata, + nhood_group_obs=nhood_group_obs, + formula=base_formula, + group_to_compare=group_to_compare, + baseline=baseline, + alpha=alpha, + quiet=quiet, + ) + if de_method == "statsmodels": + raise NotImplementedError( + "statsmodels is not yet implemented for neighborhood group markers; use pydeseq2 or edgeR instead." + ) + logger.warning( + "Using log‐normalized data is not recommended; consider using counts with pydeseq2 or edgeR instead." + ) + if _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") + + return self._run_statsmodels_contrasts( + pdata, + nhood_group_obs=nhood_group_obs, + formula=base_formula, + group_to_compare=group_to_compare, + baseline=baseline, + use_eb=use_eb, + **kwargs, + ) + if de_method == "edgeR": + if not _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects raw counts.") + return self._run_edger_contrasts( + pdata, + nhood_group_obs=nhood_group_obs, + formula=base_formula, + group_to_compare=group_to_compare, + baseline=baseline, + ) + if de_method == "limma": + logger.warning( + "Using log‐normalized data is not recommended; consider using counts with pydeseq2 or edgeR instead." + ) + if _is_counts(pdata.X): + raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") + return self._run_limma_trend_contrasts( + pdata, + nhood_group_obs=nhood_group_obs, + formula=base_formula, + group_to_compare=group_to_compare, + baseline=baseline, + ) else: - raise ValueError("`subset_nhoods` must be a boolean mask, a list of indices, or a list of names.") + raise ValueError( + f"de_method must be one of 'pydeseq2', 'statsmodels', 'edgeR', or 'limma', not '{de_method}'" + ) + + def plot_heatmap_with_dot_and_colorbar( + self, + mean_df: pd.DataFrame, + logfc_ser: pd.Series | None = None, + cmap: str = "YlGnBu", + dot_scale: float = 200.0, + figsize: tuple[float, float] = (6, 10), + panel_ratios: tuple[float, float, float] = (5, 0.6, 0.3), + cbar_tick_count: int = 5, + show_dot: bool = True, + legend_on_right: bool = False, + ) -> plt.Figure: + """Marker heatmap of mean expression across groups, with optional logFC dots and a colorbar. + + Plot a figure with: + • Left: heatmap of mean_df (genes × groups), WITHOUT its default colorbar. + • (Optional) Middle: a single column of dots (size ∝ |logFC|), one per gene. + • Right: a slim vertical colorbar (ggplot2 style) that applies to the heatmap. + • (Optional) A size legend for logFC dots, either just to the right of the colorbar + (legend_on_right=False, the default) or further to the right (legend_on_right=True). + + If show_dot=False, `logfc_ser` may be omitted (and is ignored). If show_dot=True, + then `logfc_ser` must be provided and must match `mean_df.index`. + + Parameters + ---------- + mean_df : pandas.DataFrame, shape (n_genes, n_groups) + Rows = gene names; columns = group labels; values = mean expression. + + logfc_ser : pandas.Series or None, default=None + If show_dot=True, this Series of length n_genes (indexed by gene names) gives + the logFC for each gene. If show_dot=False, you may leave this as None. + + cmap : str, default="YlGnBu" + Colormap for the heatmap and its colorbar. + + dot_scale : float, default=200.0 + Controls the maximum dot area for the largest |logFC| (only used if show_dot=True). + + figsize : tuple (W, H), default=(6, 10) + Total figure size in inches. Width W is split among panels according to ratios. + + panel_ratios : tuple (r1, r2, r3), default=(5, 0.6, 0.3) + Relative widths for [heatmap, dot‐column, colorbar] when show_dot=True. + If show_dot=False, only r1 and r3 are used to split the width. + + cbar_tick_count : int, default=5 + Number of ticks on the vertical colorbar. + + show_dot : bool, default=True + If True, draw the dot column (requires `logfc_ser`). If False, omit dots and + only draw [heatmap | colorbar]. + + legend_on_right : bool, default=False + If True, move the “size legend” further to the right of the figure, + to avoid overlap when the figure is narrow. If False, place it just + to the right of the colorbar (may overlap if figure is very narrow). + + Returns: + ------- + fig : matplotlib.figure.Figure + + Examples: + >>> varnames = ( + >>> nhood_group_markers_results + >>> .query('logFC >= 0.5') + >>> .query('adj_PValue <= 0.01') + >>> .sort_values("logFC", ascending = False) + >>> .variable.to_list() + >>> ) + >>> mean_df = milo.get_mean_expression(mdata["rna"], "nhood_groups", var_names=varnames) + >>> logfc_ser = ( + >>> nhood_group_markers_results + >>> .query('logFC >= 0.5') + >>> .query('adj_PValue <= 0.01') + >>> .set_index("variable") + >>> .logFC + >>> ) + >>> fig = milo.plot_heatmap_with_dot_and_colorbar( + >>> mean_df, + >>> logfc_ser=logfc_ser, + >>> cmap="YlGnBu", + >>> dot_scale=200.0, + >>> figsize=(2, (1.5, len(logfc_ser)*0.15)), + >>> panel_ratios=(5, 0.6, 0.3), + >>> cbar_tick_count=5, + >>> show_dot=True, + >>> legend_on_right=1.3, + >>> ) + + """ + # ──────────────────────────────── + # 1) Validate / align logFC + # ──────────────────────────────── + if show_dot: + if logfc_ser is None: + raise ValueError("`logfc_ser` must be provided when `show_dot=True`.") + genes = list(mean_df.index) + lfc_vals = logfc_ser.reindex(index=genes).fillna(0.0).values + n_genes = len(genes) + else: + genes = list(mean_df.index) + n_genes = len(genes) + lfc_vals = None + + groups = list(mean_df.columns) + + # ──────────────────────────────── + # 2) Dot‐size scaling (if needed) + # ──────────────────────────────── + if show_dot: + max_abs_lfc = np.nanmax(np.abs(lfc_vals)) + if max_abs_lfc == 0 or np.isnan(max_abs_lfc): + max_abs_lfc = 1.0 + + # ──────────────────────────────── + # 3) Heatmap normalization + # ──────────────────────────────── + vmin = mean_df.values.min() + vmax = mean_df.values.max() + norm = Normalize(vmin=vmin, vmax=vmax) + cmap_obj = plt.get_cmap(cmap) + + # ──────────────────────────────── + # 4) Build a GridSpec + # ──────────────────────────────── + W, H = figsize + r1, r2, r3 = panel_ratios + + if show_dot: + # three panels: [heatmap | dots | colorbar] + total_ratio = r1 + r2 + r3 + width_ratios = [r1 / total_ratio, r2 / total_ratio, r3 / total_ratio] + fig = plt.figure(figsize=(W, H)) + gs = fig.add_gridspec(nrows=1, ncols=3, width_ratios=width_ratios, wspace=0.02) + ax_heat = fig.add_subplot(gs[0, 0]) + else: + # two panels: [heatmap | colorbar] + total_ratio = r1 + r3 + width_ratios = [r1 / total_ratio, r3 / total_ratio] + fig = plt.figure(figsize=(W, H)) + gs = fig.add_gridspec(nrows=1, ncols=2, width_ratios=width_ratios, wspace=0.02) + ax_heat = fig.add_subplot(gs[0, 0]) + + # ──────────────────────────────── + # 5) Plot heatmap (no default colorbar) + # ──────────────────────────────── + sns.heatmap( + mean_df, + ax=ax_heat, + cmap=cmap, + norm=norm, + cbar=False, + yticklabels=genes, + xticklabels=groups, + linewidths=0.5, + linecolor="gray", + ) + ax_heat.set_ylabel("Gene", fontsize=10) + ax_heat.set_xlabel("Group", fontsize=10) + plt.setp(ax_heat.get_xticklabels(), rotation=45, ha="right", fontsize=8) + plt.setp(ax_heat.get_yticklabels(), rotation=0, fontsize=6) + + # ──────────────────────────────── + # 6) Dot panel (if requested) + # ──────────────────────────────── + if show_dot: + ax_dot = fig.add_subplot(gs[0, 1]) + for i, val in enumerate(lfc_vals): + if not np.isnan(val) and val != 0.0: + area = (abs(val) / max_abs_lfc) * dot_scale + ax_dot.scatter(0, i, s=area, color="black", alpha=0.8, edgecolors="none") + ax_dot.set_xlim(-0.5, 0.5) + ax_dot.set_ylim(n_genes - 0.5, -0.5) + ax_dot.set_xticks([]) + ax_dot.set_yticks([]) + ax_dot.set_title("logFC", pad=10, fontdict={"fontsize": 7}) + ax_cbar = fig.add_subplot(gs[0, 2]) + else: + ax_cbar = fig.add_subplot(gs[0, 1]) + + # ──────────────────────────────── + # 7) Draw vertical colorbar for heatmap + # ──────────────────────────────── + smap = ScalarMappable(norm=norm, cmap=cmap_obj) + smap.set_array([]) + + cbar = fig.colorbar( + smap, cax=ax_cbar, orientation="vertical", ticks=np.linspace(vmin, vmax, num=cbar_tick_count) + ) + cbar.ax.tick_params(labelsize=8, length=4, width=1) + cbar.ax.set_title("Mean\nExpr.", fontsize=8, pad=6) + cbar.outline.set_linewidth(0.5) + + # ──────────────────────────────── + # 8) Add a size‐legend for the dot‐column (optional) + # ──────────────────────────────── + if show_dot: + # Choose three reference |logFC| values: max, ½ max, ¼ max + ref_vals = np.array([max_abs_lfc, 0.5 * max_abs_lfc, 0.25 * max_abs_lfc]) + legend_handles = [] + legend_labels = [] + for rv in ref_vals: + sz = (rv / max_abs_lfc) * dot_scale + handle = ax_dot.scatter(0, 0, s=sz, color="black", alpha=0.8, edgecolors="none") + legend_handles.append(handle) + legend_labels.append(f"|logFC| = {rv:.2f}") + + # Determine bounding box based on legend_on_right flag + bbox_x = (1.2 if isinstance(legend_on_right, bool) else legend_on_right) if legend_on_right else 1.02 + + fig.legend( + legend_handles, + legend_labels, + title="Dot size legend", + loc="center left", + bbox_to_anchor=(bbox_x, 0.5), + frameon=False, + fontsize=7, + title_fontsize=8, + handletextpad=0.5, + labelspacing=0.6, + ) + + plt.tight_layout() + return fig + + +import statsmodels.stats.multitest +from scipy.optimize import brentq +from scipy.special import digamma, polygamma +from scipy.stats import t as student_t +from statsmodels.nonparametric.smoothers_lowess import lowess + + +def _find_d0_root( + log_z: np.ndarray, + df_res: np.ndarray, + winsor: bool, + w_low: float, + w_high: float, + prop: float, +): + """Internal helper to estimate the prior degrees of freedom d0 by method‐of‐moments on {log(z_i)}, where z_i = (sigma2_i / s0_i^2) if trend, or z_i = sigma2_i if no trend. + + This function does three things: + 1. Optionally trims the bottom ’prop’ fraction and top ’prop’ fraction of z_i + (symmetric trimming) if prop>0. This corresponds to limma’s ‘proportion’‐trimming. + 2. Optionally winsorizes the trimmed z_i at quantiles [w_low, 1−w_high] if winsor=True. + 3. Finally finds the unique root d0>0 of + (1/G) ∑_{i=1}^G ψ¹((d_i + d0)/2) = Var( log(z_i_trimmed_or_winsorized) ) + or, if no sign‐change is found in the usual bracket, picks the d0 that minimizes + |(1/G)∑ψ¹((d_i+d0)/2) − var(log_z)| over a grid. + + Returns. + ------- + d0_hat : float + log_z_used : ndarray of shape (G,) + The log‐values after trimming/winsorizing, for debugging if needed. + """ + G = len(df_res) + # 1) Compute z_i = exp(log_z). (log_z was passed in.) + z = np.exp(log_z) + + # 2) Symmetric trimming of extremes by proportion ’prop’: + # If prop>0, we drop the bottom prop*G and top prop*G of z’s (by value) before + # passing them into variance‐and‐trigamma steps. + if prop > 0: + # Sort by z, find indices to keep + order = np.argsort(z) + n_excl = int(np.floor(prop * G + 0.5)) # number of genes to exclude from each tail + if n_excl >= G // 2: + # If prop is so large that more than half would be excluded, + # just set n_excl = floor((G−1)/2) so that at least one gene remains. + n_excl = max(int((G - 1) / 2), 1) + keep_idx = order[n_excl : G - n_excl] + z_used = z[keep_idx] + df_used = df_res[keep_idx] + # Our new “log_z_used” is the log of those kept z_i + log_z_used = np.log(z_used) + else: + # Use all genes + log_z_used = log_z.copy() + df_used = df_res.copy() + + # 3) If robust=True, winsorize log_z_used at the (w_low, 1−w_high) empirical quantiles: + if winsor: + lower_q = np.quantile(log_z_used, w_low) + upper_q = np.quantile(log_z_used, 1.0 - w_high) + log_z_used = np.clip(log_z_used, lower_q, upper_q) + # df_used remains the same as after trimming (if trimming was done) + + # 4) We now have a final array log_z_used (length G′ ≤ G). Compute + np.mean(log_z_used) + v_logz = np.var(log_z_used, ddof=1) + + # 5) Define f(d0) = (1/G′) ∑_{i=1}^{G′} ψ¹( (df_used[i] + d0) / 2 ) − v_logz. + def average_trigamma(d0): + # note: polygamma(1, x) is ψ¹(x). + return np.mean(polygamma(1, 0.5 * (df_used + d0))) + + def f_to_solve(d0): + return average_trigamma(d0) - v_logz + + # 6) Try to find a sign‐change for d0 in [1e-8, 1e8]. If found, use brentq. + # Otherwise, pick d0 among a log‐grid that minimizes |f|. + candidates = np.logspace(-8, 8, num=25) + f_vals = np.array([f_to_solve(d) for d in candidates]) + sign_changes = np.where(f_vals[:-1] * f_vals[1:] < 0)[0] + + if len(sign_changes) > 0: + k = int(sign_changes[0]) + a, b = float(candidates[k]), float(candidates[k + 1]) + try: + d0_hat = brentq(f_to_solve, a, b) + except ValueError: + # In the unlikely event that f(a)*f(b) is numerically not <0 anymore, + # fall back to the minimum‐|f| grid point: + idx_min = np.argmin(np.abs(f_vals)) + d0_hat = float(candidates[idx_min]) + else: + # No sign‐change—just pick the best grid point + idx_min = np.argmin(np.abs(f_vals)) + d0_hat = float(candidates[idx_min]) + + return d0_hat, log_z_used + + +def ebayes_py( + sigma2: np.ndarray, + df_res: np.ndarray, + beta: np.ndarray, + se_orig: np.ndarray, + var_names: list[str], + A: np.ndarray = None, + proportion: float = 0.01, + stdev_coef_lim: tuple[float, float] = (0.1, 4), + trend: bool = False, + robust: bool = False, + winsor_tail_p: tuple[float, float] = (0.05, 0.1), +) -> pd.DataFrame: + """A Python re‐implementation of limma::eBayes, with options. + + • proportion (fraction to symmetrically trim when fitting hyper‐parameters) + • stdev.coef.lim (bounds on prior standard deviation relative to the median of sigma_i) + • trend (if True, fit a lowess mean‐variance trend) + • robust (if True, winsorize variances before hyper‐parameter estimation) + • winsor.tail.p (tuple of lower and upper tail proportions for winsorization). + + Arguments: + --------- + sigma2 : ndarray, shape (G,) + Sample variances for each gene (i.e. mod.scale from an OLS fit). + df_res : ndarray, shape (G,) + Residual degrees of freedom for each gene (i.e. mod.df_resid). + beta : ndarray, shape (G,) + Estimated coefficient (contrast) for each gene (i.e. mod.t_test(contrast).effect.item()). + se_orig : ndarray, shape (G,) + Original standard error for that contrast (i.e. mod.t_test(contrast).sd.item()). + var_names : list[str] + List of gene names (length G) corresponding to the above arrays. + This is used to build the output DataFrame. + A : ndarray, shape (G,), optional (default=None) + Gene‐wise average expression (e.g. rowMeans(log‐CPM) or log(counts + 1)). Required if trend=True. + proportion : float, default=0.01 + Fraction of genes (from each tail) to drop before estimating the hyper‐parameters. + If proportion=0.01, that means drop the bottom 1% and top 1% of {z_i} (or {sigma2}), + exactly like limma’s “proportion”‐trimming. + stdev_coef_lim : tuple (low, high), default=(0.1, 4) + Bounds on the ratio (prior_s0 / median(sigma_i)). If the naive estimate of s0 is + below low * median(sigma), it is set = low * median(sigma). If > high * median(sigma), + it is set = high * median(sigma). + trend : bool, default=False + If True, fit a lowess‐based trend of log(sigma2) versus A, so that each gene i gets + its own “prior variance” s0_i^2 = exp(fitted_log_sigma2(A_i)). Then the method‐of‐moments + for d0 is done on z_i = sigma2_i / s0_i^2. If False, use a single s0^2 for all genes. + robust : bool, default=False + If True, winsorize log‐variances (or log‐z_i in the trend case) at the quantiles + [winsor_tail_p[0], 1 − winsor_tail_p[1]] before estimating d0. This mimics limma’s + robust = TRUE logic (calling fitFDistRobustly on winsorized variances). + winsor_tail_p : tuple (low_p, high_p), default=(0.05, 0.1) + Tail‐proportions for winsorizing. Only used if robust=True. E.g. (0.05, 0.1) means + lower‐tail at 5% and upper‐tail at 90% (i.e. any log‐variance above the 90th percentile + is replaced by that 90th‐percentile value, and similarly from below). + + Returns: + ------- + results_df : pandas.DataFrame with columns + “beta” : the original contrast estimate β_i + “se_mod” : the moderated standard error + “t_mod” : the moderated t‐statistic + “df_total” : posterior degrees of freedom (d_i + d0) + “p_mod” : two‐sided moderated p‐value + “adj_p_mod” : FDR‐adjusted q‐value (Benjamini‐Hochberg) + “s2_prior” : if trend=False, the single prior variance s0^2; if trend=True, + a per‐gene prior variance s0_i^2 + + Usage Example + ------------- + >>> # Suppose you have G genes, each fitted by statsmodels. You have collected: + >>> # sigma2 = np.array([mod1.scale, mod2.scale, ..., modG.scale]) + >>> # df_res = np.array([mod1.df_resid, ..., modG.df_resid]) + >>> # beta = np.array([mod1.t_test(c).effect, ..., modG.t_test(c).effect]) + >>> # se = np.array([mod1.t_test(c).sd, ..., modG.t_test(c).sd ]) + >>> # A = np.array([adata[:, g].X.mean() for g in range(G)]) # if trend=True + >>> results = ebayes_py( + ... sigma2=sigma2, + ... df_res=df_res, + ... beta=beta, + ... se_orig=se, + ... A=A, + ... proportion=0.01, + ... stdev_coef_lim=(0.1, 4), + ... trend=True, + ... robust=True, + ... winsor_tail_p=(0.05, 0.1), + ... ) + >>> print(results.head()) + """ + G = len(sigma2) + if not (len(df_res) == G == len(beta) == len(se_orig)): + raise ValueError("All input arrays must have the same length G (number of genes).") + + # 1) Optional: Check that proportions are in [0,1): + if not (0 <= proportion < 1): + raise ValueError("proportion must be in [0,1).") + w_low, w_high = winsor_tail_p + if not (0 <= w_low < 1) or not (0 <= w_high < 1): + raise ValueError("winsor_tail_p entries must lie in [0,1).") + + # 2) If trend=True, we need A (gene‐wise average expression) + if trend and (A is None or len(A) != G): + raise ValueError("If trend=True, you must supply A of length G (gene‐wise average).") + + # 3) Fit the mean‐variance trend if requested (trend=True) + # We will fit: y = lowess(log(sigma2), A, frac=0.5) (frac=0.5 is default span in limma) + # Then g_i(A_i) = fitted log(sigma2_i). So prior s0_i^2 = exp(g_i(A_i)). + if trend: + # Prepare data for lowess: sort by A + order = np.argsort(A) + A_sorted = A[order] + log_s2_sorted = np.log(sigma2)[order] + + # Call statsmodels.lowess + fitted = lowess( + endog=log_s2_sorted, + exog=A_sorted, + frac=0.5, # limma’s default span is 0.5 + return_sorted=False, + ) + # Re‐order back to original gene order: + trend_log_s2 = np.empty_like(fitted) + trend_log_s2[order] = fitted + # The “prior variance” for each gene is: + s0sq_i = np.exp(trend_log_s2) # shape (G,) + else: + # If no trend, we will fit a single prior variance s0^2 to all genes, + # so for now store s0sq_i = 1 (placeholder). We’ll overwrite later. + s0sq_i = np.ones(G, dtype=float) + + # 4) Form the array log_z_i for hyperparameter estimation: + # If trend: z_i = sigma2_i / s0sq_i => log_z_i = log(sigma2_i) − log(s0sq_i) + # If no trend: z_i = sigma2_i => log_z_i = log(sigma2_i) + log_z = np.log(sigma2) - np.log(s0sq_i) if trend else np.log(sigma2).copy() + + # 5) Estimate d0 by method‐of‐moments on log_z, with trimming+winsor if requested + d0_hat, log_z_used = _find_d0_root( + log_z=log_z, + df_res=df_res, + winsor=robust, + w_low=w_low, + w_high=w_high, + prop=proportion, + ) + + # 6) If no trend, estimate a single prior variance s0^2; if trend, we already have per‐gene’s s0sq_i + if not trend: + # We need: log(s0^2) = mean(log(sigma2)) − (1/G) ∑ [ψ((d_i + d0)/2) − log((d_i + d0)/2)] + m_log = np.mean(np.log(sigma2)) + alpha_i = digamma(0.5 * (df_res + d0_hat)) - np.log(0.5 * (df_res + d0_hat)) + mean_alpha = np.mean(alpha_i) + log_s0sq = m_log - mean_alpha + s0sq_common = float(np.exp(log_s0sq)) + s0sq_i = np.full(G, s0sq_common, dtype=float) + else: + # trend=True: We already computed s0sq_i = exp(fitted trend). But we may still want to + # “rescale” them so that, on average, they match the method‐of‐moments estimate we would get + # if we had forced a constant prior. In limma, “trend” means the prior var for gene i is s0sq_i, + # and d0 is the same for all genes. We do NOT re‐scale s0sq_i here. The method‐of‐moments for + # d0 only used z_i = sigma2_i / s0sq_i, so s0sq_i is already correct. + s0sq_common = None # not used if trend=True + + # 7) Enforce stdev.coef.lim: s0 must be between [low * median(sigma_i), high * median(sigma_i)] + # “prior standard deviation” is sqrt(s0sq). So: + sigma_i = np.sqrt(sigma2) + median_sigma = np.median(sigma_i) + + if trend: + # We impose the limits on each sqrt(s0sq_i) individually: + s0_i = np.sqrt(s0sq_i) + lower_bound = stdev_coef_lim[0] * median_sigma + upper_bound = stdev_coef_lim[1] * median_sigma + s0_i_clipped = np.clip(s0_i, lower_bound, upper_bound) + # Rewrite s0sq_i accordingly: + s0sq_i = s0_i_clipped**2 + else: + # Single prior s0sq_common. Impose limits on s0 = sqrt(s0sq_common): + s0_common = np.sqrt(s0sq_common) + lower_b = stdev_coef_lim[0] * median_sigma + upper_b = stdev_coef_lim[1] * median_sigma + s0_clipped = float(np.clip(s0_common, lower_b, upper_b)) + s0sq_common = s0_clipped**2 + s0sq_i = np.full(G, s0sq_common, dtype=float) + + # 8) Compute each gene’s posterior (moderated) variance: + # sigma2_post[i] = (d_i * sigma2_i + d0_hat * s0sq_i) / (d_i + d0_hat) + sigma2_post = (df_res * sigma2 + d0_hat * s0sq_i) / (df_res + d0_hat) + + # 9) Recompute (for each gene) the moderated SE, the moderated t, and the moderated p‐value: + mod_t = np.zeros(G, dtype=float) + mod_p = np.zeros(G, dtype=float) + mod_se = np.zeros(G, dtype=float) + + for i in range(G): + # original SE: se_orig[i] = sqrt(v_i * sigma2[i]) + # we want: se_mod[i] = sqrt(v_i * sigma2_post[i]) = se_orig[i] * sqrt(sigma2_post[i]/sigma2[i]) + if sigma2[i] <= 0: + # Should not happen if sigma2 was estimated properly, but guard against numerical issues + raise ValueError(f"Non‐positive sigma2 at index {i}: {sigma2[i]}") + scale_factor = np.sqrt(sigma2_post[i] / sigma2[i]) + se_m = se_orig[i] * scale_factor + mod_se[i] = se_m + + # moderated t‐statistic: + t_m = beta[i] / se_m + mod_t[i] = t_m + + # posterior degrees of freedom: + df_i_post = df_res[i] + d0_hat + + # two‐sided p‐value from Student‐t(df_i_post): + p_m = 2.0 * student_t.sf(np.abs(t_m), df_i_post) + mod_p[i] = p_m + + # 10) Assemble results into a DataFrame, sort by p‐value, and adjust for FDR + results_df = pd.DataFrame( + { + "variable": var_names, + "beta": beta, + "se_mod": mod_se, + "t_mod": mod_t, + "df_total": df_res + d0_hat, + "p_mod": mod_p, + # store “prior variance” or “prior SD” for reference: + "s2_prior": s0sq_i, + }, + index=None, + ) + + # Sort by p_mod ascending, reset index: + results_df = results_df.sort_values("p_mod").reset_index(drop=True) - out[mask_idx] = labels + # Benjamini–Hochberg FDR on the moderated p‐values: + results_df["adj_p_mod"] = statsmodels.stats.multitest.fdrcorrection(results_df["p_mod"].values)[1] - adata.var["nhood_groups"] = out \ No newline at end of file + return results_df diff --git a/pertpy/utils/__init__.py b/pertpy/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pertpy/utils/_lazy_r_namespace.py b/pertpy/utils/_lazy_r_namespace.py deleted file mode 100644 index 58fc346e..00000000 --- a/pertpy/utils/_lazy_r_namespace.py +++ /dev/null @@ -1,22 +0,0 @@ -from types import SimpleNamespace - -def lazy_import_r_env(): - import rpy2.robjects as ro - from rpy2.robjects.packages import importr, STAP - from rpy2.robjects.conversion import localconverter - from rpy2.robjects import default_converter, pandas2ri, numpy2ri - - from pertpy.utils.rpy2_utils import _py_to_r, _r_to_py, lazy_import_r_packages # moved inside function - - r = SimpleNamespace( - ro=ro, - importr=importr, - STAP=STAP, - localconverter=localconverter, - default_converter=default_converter, - pandas2ri=pandas2ri, - numpy2ri=numpy2ri, - lazy_import_r_packages=lazy_import_r_packages - ) - - return r, _py_to_r, _r_to_py \ No newline at end of file diff --git a/pertpy/utils/rpy2_utils.py b/pertpy/utils/rpy2_utils.py deleted file mode 100644 index 35763ff5..00000000 --- a/pertpy/utils/rpy2_utils.py +++ /dev/null @@ -1,245 +0,0 @@ -from functools import singledispatch -from typing import Sequence, Union, Any -from rpy2 import robjects as ro -from rpy2.robjects import vectors, methods -from rpy2.robjects.vectors import ListVector -from rpy2.robjects.methods import RS4 -from rpy2.robjects.conversion import localconverter -from rpy2.robjects import default_converter, numpy2ri, pandas2ri -from anndata2ri import scipy2ri -import numpy as np -import pandas as pd -from scipy.sparse import csr_matrix, csc_matrix -from typing import Sequence, Union, Tuple -import types - -def get_rpy2_objects(): - """ - Return commonly used rpy2 classes, functions, and modules for local use. - - Returns - ------- - tuple : (ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri) - """ - try: - import rpy2.robjects as ro - from rpy2.robjects.packages import importr, STAP - from rpy2.robjects.conversion import localconverter - from rpy2.robjects import pandas2ri, numpy2ri - from rpy2.robjects import default_converter - - except ImportError as e: - raise ImportError("rpy2 must be installed to use this function.") from e - - return ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri - -ro, importr, STAP, localconverter, default_converter, pandas2ri, numpy2ri = get_rpy2_objects() - -def lazy_import_r_packages(packages: Sequence[str] | str) -> tuple[Union[types.ModuleType, str], ...]: - """ - Lazily import R packages using rpy2.robjects.packages.importr. - - For each package name: - - Try to import it. - - If successful, return the imported package object, prefixed with "r_" in variable naming convention. - - If failed, return the package name string (as a marker of failure). - - Parameters - ---------- - packages : list of str - R package names to import. - - Returns - ------- - tuple - A tuple of imported modules or failed package names (as strings), in order. - """ - ro, importr, _, *_ = get_rpy2_objects() - - if isinstance(packages, str): - try: - r_pkg = importr(packages) - except Exception as e: - raise ImportError(f"Failed to import required R package: {packages}") - return r_pkg - - imported = [] - failures = [] - for pkg in packages: - try: - r_pkg = importr(pkg) - imported.append(r_pkg) - except Exception as e: - imported.append(pkg) - failures.append(pkg) - - if failures: - raise ImportError(f"Failed to import required R packages: {', '.join(failures)}") - - return tuple(imported) - - -### - -# ---------------------- -# Python -> R converters -# ---------------------- -@singledispatch -def _py_to_r(obj) -> ro.RObject: - """ - Fallback: convert with rpy2's generic converter. - Lists/tuples of atomic types -> R vector; mixed lists -> R list. - """ - with localconverter(default_converter): - return ro.conversion.py2rpy(obj) - -@_py_to_r.register(type(None)) -def _(obj) -> ro.NULL: - return ro.NULL - -@_py_to_r.register(bool) -def _(obj: bool) -> vectors.BoolVector: - return vectors.BoolVector([obj]) - -@_py_to_r.register(int) -def _(obj: int) -> vectors.IntVector: - return vectors.IntVector([obj]) - -@_py_to_r.register(float) -def _(obj: float) -> vectors.FloatVector: - return vectors.FloatVector([obj]) - -@_py_to_r.register(str) -def _(obj: str) -> vectors.StrVector: - return vectors.StrVector([obj]) - -@_py_to_r.register(dict) -def _(obj: dict) -> ListVector: - # Convert a Python dict to an R named list - rdict = {str(k): _py_to_r(v) for k, v in obj.items()} - return ListVector(rdict) - -@_py_to_r.register(np.ndarray) -def _(obj: np.ndarray) -> ro.Matrix: - with localconverter(default_converter + numpy2ri.converter): - return numpy2ri.py2rpy(obj) - -@_py_to_r.register(pd.DataFrame) -def _(obj: pd.DataFrame) -> ro.DataFrame: - with localconverter(default_converter + pandas2ri.converter): - return ro.conversion.py2rpy(obj) - -@_py_to_r.register(pd.Series) -def _(obj: pd.Series) -> vectors.Vector: - with localconverter(default_converter + pandas2ri.converter): - return ro.conversion.py2rpy(obj) - -@_py_to_r.register(csr_matrix) -def _(obj: csr_matrix) -> ro.Matrix: - with localconverter(default_converter + scipy2ri.converter): - return ro.conversion.py2rpy(obj) - -@_py_to_r.register(csc_matrix) -def _(obj: csc_matrix) -> ro.Matrix: - with localconverter(default_converter + scipy2ri.converter): - return ro.conversion.py2rpy(obj) - -# ---------------------- -# R -> Python converters -# ---------------------- -@singledispatch -def _r_to_py(obj: ro.RObject): - """Fallback: generic R->Python via rpy2""" - with localconverter(default_converter): - return ro.conversion.rpy2py(obj) - -@_r_to_py.register(type(ro.NULL)) -def _(obj) -> None: - return None - -@_r_to_py.register(vectors.BoolVector) -def _(obj: vectors.BoolVector): - py = [bool(x) for x in list(obj)] - return py[0] if len(py) == 1 else py - -@_r_to_py.register(vectors.IntVector) -def _(obj: vectors.IntVector): - py = list(obj) - return int(py[0]) if len(py) == 1 else py - -@_r_to_py.register(vectors.FloatVector) -def _(obj: vectors.FloatVector): - py = list(obj) - return float(py[0]) if len(py) == 1 else py - -@_r_to_py.register(vectors.StrVector) -def _(obj: vectors.StrVector): - py = list(obj) - return str(py[0]) if len(py) == 1 else py - -@_r_to_py.register(ListVector) -def _(obj: ListVector): - # Convert each element first - items = [_r_to_py(obj[i]) for i in range(len(obj))] - # Handle names (NULL means no names) - names_r = obj.names - if names_r == ro.NULL: - return items - names = list(names_r) - return {names[i]: items[i] for i in range(len(items))} - -@_r_to_py.register(vectors.Matrix) -def _(obj: vectors.Matrix): - with localconverter(default_converter + numpy2ri.converter): - return ro.conversion.rpy2py(obj) - -@_r_to_py.register(ro.DataFrame) -def _(obj: ro.DataFrame) -> pd.DataFrame: - with localconverter(default_converter + pandas2ri.converter): - return ro.conversion.rpy2py(obj) - -@_r_to_py.register(vectors.Vector) -def _(obj: vectors.Vector): - return list(obj) - -@_r_to_py.register(RS4) -def _(obj: RS4): - # Sparse S4 matrix types go through scipy2ri - if obj.rclass[0] in ("dgCMatrix", "dgRMatrix"): - with localconverter(default_converter + scipy2ri.converter): - return ro.conversion.rpy2py(obj) - # Other S4 -> dict of slots - return {name: _r_to_py(obj.slots[name]) for name in obj.slotnames()} - - -def _ad_to_rmat(adata, layer="X"): - from rpy2 import robjects as ro - from rpy2.robjects import baseenv - from rpy2.robjects.packages import importr - import numpy as np - - # 1) grab & transpose - mat = adata.X if layer == "X" else adata.layers[layer] - mat = mat.T - - # 2) convert to R - rmat = _py_to_r(mat) - - # 3) build an *unnamed* R list(r_rownames, r_colnames) - r_colnames = _py_to_r(np.asarray(adata.obs_names)) - r_rownames = _py_to_r(np.asarray(adata.var_names)) - dim_list = ro.r.list(r_rownames, r_colnames) - - # 4) set dimnames via baseenv() - assign_dim = baseenv["dimnames<-"] - rmat = assign_dim(rmat, dim_list) - - return rmat - -def _ad_to_dge(adata, layer="X") -> Any: - edgeR = importr("edgeR") - counts = _ad_to_rmat(adata, layer) - samples = _py_to_r(adata.obs) - return edgeR.DGEList(counts=counts, samples=samples) - - From a687a3da0051de13181fb5b1325420b4fc2331dc Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Sun, 8 Jun 2025 12:05:37 +0200 Subject: [PATCH 03/10] changed Literal edgeR to edger to adhere to Milo().da_nhoods --- pertpy/tools/_milo.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 61766a33..578963e0 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -2256,7 +2256,7 @@ def find_nhood_group_markers( n_top_genes: int = 7500, filter_method: str | None = "scanpy", var_names: Collection[str] | None = None, - de_method: Literal["pydeseq2", "statsmodels", "edgeR", "limma"] = "pydeseq2", + de_method: Literal["pydeseq2", "statsmodels", "edger", "limma"] = "pydeseq2", quiet: bool = True, alpha: float = 0.05, use_eb: bool = False, @@ -2445,7 +2445,7 @@ def find_nhood_group_markers( ) if de_method == "statsmodels": raise NotImplementedError( - "statsmodels is not yet implemented for neighborhood group markers; use pydeseq2 or edgeR instead." + "statsmodels is not yet implemented for neighborhood group markers; use pydeseq2 or edgeR with counts, or limma with normalized counts." ) logger.warning( "Using log‐normalized data is not recommended; consider using counts with pydeseq2 or edgeR instead." @@ -2462,7 +2462,7 @@ def find_nhood_group_markers( use_eb=use_eb, **kwargs, ) - if de_method == "edgeR": + if de_method == "edger": if not _is_counts(pdata.X): raise ValueError("`pdata.X` appears to be raw counts, but this function expects raw counts.") return self._run_edger_contrasts( @@ -2487,7 +2487,7 @@ def find_nhood_group_markers( ) else: raise ValueError( - f"de_method must be one of 'pydeseq2', 'statsmodels', 'edgeR', or 'limma', not '{de_method}'" + f"de_method must be one of 'pydeseq2', 'statsmodels', 'edger', or 'limma', not '{de_method}'" ) def plot_heatmap_with_dot_and_colorbar( From d0230ce214dd7b061baef1af32e848a18b2415a4 Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Tue, 10 Jun 2025 08:09:38 +0200 Subject: [PATCH 04/10] Tests imporvement and removed ebayes Improved tests so they rely only on lazily imported rpy2. removed ebayes for previously removed Statsmodels test in find_nhood_group_markers. --- pertpy/tools/_milo.py | 347 +--------------------- tests/tools/test_milo.py | 616 +++++++++++++++++++++++++++++---------- 2 files changed, 472 insertions(+), 491 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 578963e0..454a5311 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -1449,7 +1449,7 @@ def _group_nhoods_from_adjacency( def group_nhoods( self, data: Any, - key: str | None = "rna", + key: str | None = "milo", da_res: pd.DataFrame | None = None, da_fdr: float = 0.1, overlap: int = 1, @@ -1661,6 +1661,11 @@ def _nhood_labels_to_cells_exclude_overlaps( mdata["rna"].obs.loc[ ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), "nhood_groups" ] = np.nan + ### Remove the in_nhoods in nhood_groups columns + mdata["rna"].obs["nhood_groups"] = ( + mdata["rna"].obs["nhood_groups"].apply(lambda x: x.split("_")[-1] if isinstance(x, str) else x) + ) + mdata["rna"].obs["nhood_groups"] = mdata["rna"].obs["nhood_groups"].str.removeprefix("in_nhoods_") def annotate_cells_from_nhoods( self, @@ -2716,343 +2721,3 @@ def plot_heatmap_with_dot_and_colorbar( plt.tight_layout() return fig - - -import statsmodels.stats.multitest -from scipy.optimize import brentq -from scipy.special import digamma, polygamma -from scipy.stats import t as student_t -from statsmodels.nonparametric.smoothers_lowess import lowess - - -def _find_d0_root( - log_z: np.ndarray, - df_res: np.ndarray, - winsor: bool, - w_low: float, - w_high: float, - prop: float, -): - """Internal helper to estimate the prior degrees of freedom d0 by method‐of‐moments on {log(z_i)}, where z_i = (sigma2_i / s0_i^2) if trend, or z_i = sigma2_i if no trend. - - This function does three things: - 1. Optionally trims the bottom ’prop’ fraction and top ’prop’ fraction of z_i - (symmetric trimming) if prop>0. This corresponds to limma’s ‘proportion’‐trimming. - 2. Optionally winsorizes the trimmed z_i at quantiles [w_low, 1−w_high] if winsor=True. - 3. Finally finds the unique root d0>0 of - (1/G) ∑_{i=1}^G ψ¹((d_i + d0)/2) = Var( log(z_i_trimmed_or_winsorized) ) - or, if no sign‐change is found in the usual bracket, picks the d0 that minimizes - |(1/G)∑ψ¹((d_i+d0)/2) − var(log_z)| over a grid. - - Returns. - ------- - d0_hat : float - log_z_used : ndarray of shape (G,) - The log‐values after trimming/winsorizing, for debugging if needed. - """ - G = len(df_res) - # 1) Compute z_i = exp(log_z). (log_z was passed in.) - z = np.exp(log_z) - - # 2) Symmetric trimming of extremes by proportion ’prop’: - # If prop>0, we drop the bottom prop*G and top prop*G of z’s (by value) before - # passing them into variance‐and‐trigamma steps. - if prop > 0: - # Sort by z, find indices to keep - order = np.argsort(z) - n_excl = int(np.floor(prop * G + 0.5)) # number of genes to exclude from each tail - if n_excl >= G // 2: - # If prop is so large that more than half would be excluded, - # just set n_excl = floor((G−1)/2) so that at least one gene remains. - n_excl = max(int((G - 1) / 2), 1) - keep_idx = order[n_excl : G - n_excl] - z_used = z[keep_idx] - df_used = df_res[keep_idx] - # Our new “log_z_used” is the log of those kept z_i - log_z_used = np.log(z_used) - else: - # Use all genes - log_z_used = log_z.copy() - df_used = df_res.copy() - - # 3) If robust=True, winsorize log_z_used at the (w_low, 1−w_high) empirical quantiles: - if winsor: - lower_q = np.quantile(log_z_used, w_low) - upper_q = np.quantile(log_z_used, 1.0 - w_high) - log_z_used = np.clip(log_z_used, lower_q, upper_q) - # df_used remains the same as after trimming (if trimming was done) - - # 4) We now have a final array log_z_used (length G′ ≤ G). Compute - np.mean(log_z_used) - v_logz = np.var(log_z_used, ddof=1) - - # 5) Define f(d0) = (1/G′) ∑_{i=1}^{G′} ψ¹( (df_used[i] + d0) / 2 ) − v_logz. - def average_trigamma(d0): - # note: polygamma(1, x) is ψ¹(x). - return np.mean(polygamma(1, 0.5 * (df_used + d0))) - - def f_to_solve(d0): - return average_trigamma(d0) - v_logz - - # 6) Try to find a sign‐change for d0 in [1e-8, 1e8]. If found, use brentq. - # Otherwise, pick d0 among a log‐grid that minimizes |f|. - candidates = np.logspace(-8, 8, num=25) - f_vals = np.array([f_to_solve(d) for d in candidates]) - sign_changes = np.where(f_vals[:-1] * f_vals[1:] < 0)[0] - - if len(sign_changes) > 0: - k = int(sign_changes[0]) - a, b = float(candidates[k]), float(candidates[k + 1]) - try: - d0_hat = brentq(f_to_solve, a, b) - except ValueError: - # In the unlikely event that f(a)*f(b) is numerically not <0 anymore, - # fall back to the minimum‐|f| grid point: - idx_min = np.argmin(np.abs(f_vals)) - d0_hat = float(candidates[idx_min]) - else: - # No sign‐change—just pick the best grid point - idx_min = np.argmin(np.abs(f_vals)) - d0_hat = float(candidates[idx_min]) - - return d0_hat, log_z_used - - -def ebayes_py( - sigma2: np.ndarray, - df_res: np.ndarray, - beta: np.ndarray, - se_orig: np.ndarray, - var_names: list[str], - A: np.ndarray = None, - proportion: float = 0.01, - stdev_coef_lim: tuple[float, float] = (0.1, 4), - trend: bool = False, - robust: bool = False, - winsor_tail_p: tuple[float, float] = (0.05, 0.1), -) -> pd.DataFrame: - """A Python re‐implementation of limma::eBayes, with options. - - • proportion (fraction to symmetrically trim when fitting hyper‐parameters) - • stdev.coef.lim (bounds on prior standard deviation relative to the median of sigma_i) - • trend (if True, fit a lowess mean‐variance trend) - • robust (if True, winsorize variances before hyper‐parameter estimation) - • winsor.tail.p (tuple of lower and upper tail proportions for winsorization). - - Arguments: - --------- - sigma2 : ndarray, shape (G,) - Sample variances for each gene (i.e. mod.scale from an OLS fit). - df_res : ndarray, shape (G,) - Residual degrees of freedom for each gene (i.e. mod.df_resid). - beta : ndarray, shape (G,) - Estimated coefficient (contrast) for each gene (i.e. mod.t_test(contrast).effect.item()). - se_orig : ndarray, shape (G,) - Original standard error for that contrast (i.e. mod.t_test(contrast).sd.item()). - var_names : list[str] - List of gene names (length G) corresponding to the above arrays. - This is used to build the output DataFrame. - A : ndarray, shape (G,), optional (default=None) - Gene‐wise average expression (e.g. rowMeans(log‐CPM) or log(counts + 1)). Required if trend=True. - proportion : float, default=0.01 - Fraction of genes (from each tail) to drop before estimating the hyper‐parameters. - If proportion=0.01, that means drop the bottom 1% and top 1% of {z_i} (or {sigma2}), - exactly like limma’s “proportion”‐trimming. - stdev_coef_lim : tuple (low, high), default=(0.1, 4) - Bounds on the ratio (prior_s0 / median(sigma_i)). If the naive estimate of s0 is - below low * median(sigma), it is set = low * median(sigma). If > high * median(sigma), - it is set = high * median(sigma). - trend : bool, default=False - If True, fit a lowess‐based trend of log(sigma2) versus A, so that each gene i gets - its own “prior variance” s0_i^2 = exp(fitted_log_sigma2(A_i)). Then the method‐of‐moments - for d0 is done on z_i = sigma2_i / s0_i^2. If False, use a single s0^2 for all genes. - robust : bool, default=False - If True, winsorize log‐variances (or log‐z_i in the trend case) at the quantiles - [winsor_tail_p[0], 1 − winsor_tail_p[1]] before estimating d0. This mimics limma’s - robust = TRUE logic (calling fitFDistRobustly on winsorized variances). - winsor_tail_p : tuple (low_p, high_p), default=(0.05, 0.1) - Tail‐proportions for winsorizing. Only used if robust=True. E.g. (0.05, 0.1) means - lower‐tail at 5% and upper‐tail at 90% (i.e. any log‐variance above the 90th percentile - is replaced by that 90th‐percentile value, and similarly from below). - - Returns: - ------- - results_df : pandas.DataFrame with columns - “beta” : the original contrast estimate β_i - “se_mod” : the moderated standard error - “t_mod” : the moderated t‐statistic - “df_total” : posterior degrees of freedom (d_i + d0) - “p_mod” : two‐sided moderated p‐value - “adj_p_mod” : FDR‐adjusted q‐value (Benjamini‐Hochberg) - “s2_prior” : if trend=False, the single prior variance s0^2; if trend=True, - a per‐gene prior variance s0_i^2 - - Usage Example - ------------- - >>> # Suppose you have G genes, each fitted by statsmodels. You have collected: - >>> # sigma2 = np.array([mod1.scale, mod2.scale, ..., modG.scale]) - >>> # df_res = np.array([mod1.df_resid, ..., modG.df_resid]) - >>> # beta = np.array([mod1.t_test(c).effect, ..., modG.t_test(c).effect]) - >>> # se = np.array([mod1.t_test(c).sd, ..., modG.t_test(c).sd ]) - >>> # A = np.array([adata[:, g].X.mean() for g in range(G)]) # if trend=True - >>> results = ebayes_py( - ... sigma2=sigma2, - ... df_res=df_res, - ... beta=beta, - ... se_orig=se, - ... A=A, - ... proportion=0.01, - ... stdev_coef_lim=(0.1, 4), - ... trend=True, - ... robust=True, - ... winsor_tail_p=(0.05, 0.1), - ... ) - >>> print(results.head()) - """ - G = len(sigma2) - if not (len(df_res) == G == len(beta) == len(se_orig)): - raise ValueError("All input arrays must have the same length G (number of genes).") - - # 1) Optional: Check that proportions are in [0,1): - if not (0 <= proportion < 1): - raise ValueError("proportion must be in [0,1).") - w_low, w_high = winsor_tail_p - if not (0 <= w_low < 1) or not (0 <= w_high < 1): - raise ValueError("winsor_tail_p entries must lie in [0,1).") - - # 2) If trend=True, we need A (gene‐wise average expression) - if trend and (A is None or len(A) != G): - raise ValueError("If trend=True, you must supply A of length G (gene‐wise average).") - - # 3) Fit the mean‐variance trend if requested (trend=True) - # We will fit: y = lowess(log(sigma2), A, frac=0.5) (frac=0.5 is default span in limma) - # Then g_i(A_i) = fitted log(sigma2_i). So prior s0_i^2 = exp(g_i(A_i)). - if trend: - # Prepare data for lowess: sort by A - order = np.argsort(A) - A_sorted = A[order] - log_s2_sorted = np.log(sigma2)[order] - - # Call statsmodels.lowess - fitted = lowess( - endog=log_s2_sorted, - exog=A_sorted, - frac=0.5, # limma’s default span is 0.5 - return_sorted=False, - ) - # Re‐order back to original gene order: - trend_log_s2 = np.empty_like(fitted) - trend_log_s2[order] = fitted - # The “prior variance” for each gene is: - s0sq_i = np.exp(trend_log_s2) # shape (G,) - else: - # If no trend, we will fit a single prior variance s0^2 to all genes, - # so for now store s0sq_i = 1 (placeholder). We’ll overwrite later. - s0sq_i = np.ones(G, dtype=float) - - # 4) Form the array log_z_i for hyperparameter estimation: - # If trend: z_i = sigma2_i / s0sq_i => log_z_i = log(sigma2_i) − log(s0sq_i) - # If no trend: z_i = sigma2_i => log_z_i = log(sigma2_i) - log_z = np.log(sigma2) - np.log(s0sq_i) if trend else np.log(sigma2).copy() - - # 5) Estimate d0 by method‐of‐moments on log_z, with trimming+winsor if requested - d0_hat, log_z_used = _find_d0_root( - log_z=log_z, - df_res=df_res, - winsor=robust, - w_low=w_low, - w_high=w_high, - prop=proportion, - ) - - # 6) If no trend, estimate a single prior variance s0^2; if trend, we already have per‐gene’s s0sq_i - if not trend: - # We need: log(s0^2) = mean(log(sigma2)) − (1/G) ∑ [ψ((d_i + d0)/2) − log((d_i + d0)/2)] - m_log = np.mean(np.log(sigma2)) - alpha_i = digamma(0.5 * (df_res + d0_hat)) - np.log(0.5 * (df_res + d0_hat)) - mean_alpha = np.mean(alpha_i) - log_s0sq = m_log - mean_alpha - s0sq_common = float(np.exp(log_s0sq)) - s0sq_i = np.full(G, s0sq_common, dtype=float) - else: - # trend=True: We already computed s0sq_i = exp(fitted trend). But we may still want to - # “rescale” them so that, on average, they match the method‐of‐moments estimate we would get - # if we had forced a constant prior. In limma, “trend” means the prior var for gene i is s0sq_i, - # and d0 is the same for all genes. We do NOT re‐scale s0sq_i here. The method‐of‐moments for - # d0 only used z_i = sigma2_i / s0sq_i, so s0sq_i is already correct. - s0sq_common = None # not used if trend=True - - # 7) Enforce stdev.coef.lim: s0 must be between [low * median(sigma_i), high * median(sigma_i)] - # “prior standard deviation” is sqrt(s0sq). So: - sigma_i = np.sqrt(sigma2) - median_sigma = np.median(sigma_i) - - if trend: - # We impose the limits on each sqrt(s0sq_i) individually: - s0_i = np.sqrt(s0sq_i) - lower_bound = stdev_coef_lim[0] * median_sigma - upper_bound = stdev_coef_lim[1] * median_sigma - s0_i_clipped = np.clip(s0_i, lower_bound, upper_bound) - # Rewrite s0sq_i accordingly: - s0sq_i = s0_i_clipped**2 - else: - # Single prior s0sq_common. Impose limits on s0 = sqrt(s0sq_common): - s0_common = np.sqrt(s0sq_common) - lower_b = stdev_coef_lim[0] * median_sigma - upper_b = stdev_coef_lim[1] * median_sigma - s0_clipped = float(np.clip(s0_common, lower_b, upper_b)) - s0sq_common = s0_clipped**2 - s0sq_i = np.full(G, s0sq_common, dtype=float) - - # 8) Compute each gene’s posterior (moderated) variance: - # sigma2_post[i] = (d_i * sigma2_i + d0_hat * s0sq_i) / (d_i + d0_hat) - sigma2_post = (df_res * sigma2 + d0_hat * s0sq_i) / (df_res + d0_hat) - - # 9) Recompute (for each gene) the moderated SE, the moderated t, and the moderated p‐value: - mod_t = np.zeros(G, dtype=float) - mod_p = np.zeros(G, dtype=float) - mod_se = np.zeros(G, dtype=float) - - for i in range(G): - # original SE: se_orig[i] = sqrt(v_i * sigma2[i]) - # we want: se_mod[i] = sqrt(v_i * sigma2_post[i]) = se_orig[i] * sqrt(sigma2_post[i]/sigma2[i]) - if sigma2[i] <= 0: - # Should not happen if sigma2 was estimated properly, but guard against numerical issues - raise ValueError(f"Non‐positive sigma2 at index {i}: {sigma2[i]}") - scale_factor = np.sqrt(sigma2_post[i] / sigma2[i]) - se_m = se_orig[i] * scale_factor - mod_se[i] = se_m - - # moderated t‐statistic: - t_m = beta[i] / se_m - mod_t[i] = t_m - - # posterior degrees of freedom: - df_i_post = df_res[i] + d0_hat - - # two‐sided p‐value from Student‐t(df_i_post): - p_m = 2.0 * student_t.sf(np.abs(t_m), df_i_post) - mod_p[i] = p_m - - # 10) Assemble results into a DataFrame, sort by p‐value, and adjust for FDR - results_df = pd.DataFrame( - { - "variable": var_names, - "beta": beta, - "se_mod": mod_se, - "t_mod": mod_t, - "df_total": df_res + d0_hat, - "p_mod": mod_p, - # store “prior variance” or “prior SD” for reference: - "s2_prior": s0sq_i, - }, - index=None, - ) - - # Sort by p_mod ascending, reset index: - results_df = results_df.sort_values("p_mod").reset_index(drop=True) - - # Benjamini–Hochberg FDR on the moderated p‐values: - results_df["adj_p_mod"] = statsmodels.stats.multitest.fdrcorrection(results_df["p_mod"].values)[1] - - return results_df diff --git a/tests/tools/test_milo.py b/tests/tools/test_milo.py index c95e9f72..992d9908 100644 --- a/tests/tools/test_milo.py +++ b/tests/tools/test_milo.py @@ -5,12 +5,9 @@ import pertpy as pt import pytest import scanpy as sc +import scipy.sparse as sp from mudata import MuData -### NEW IMPORTS -from pertpy.utils._lazy_r_namespace import lazy_import_r_env -### - @pytest.fixture(params=["edger", "pydeseq2"]) def solver(request): @@ -315,92 +312,312 @@ def test_add_nhood_expression_nhood_mean_range(add_nhood_expression_mdata, milo) ### NEW TESTS +from scipy.sparse import csr_matrix -import numpy as np -import pandas as pd -import scipy.sparse as sp -import pytest +@pytest.fixture +def group_nhoods_mdata(adata, milo): + adata = adata.copy() + milo.make_nhoods(adata) -from anndata import AnnData - -r, _py_to_r, _r_to_py = lazy_import_r_env() - -r_string = """ -.group_nhoods_from_adjacency_pycomp <- function(nhs, nhood.adj, da.res, is.da, - merge.discord=FALSE, - max.lfc.delta=NULL, - overlap=1, - subset.nhoods=NULL - ){ - # Force everything into a plain base‐R matrix - nhood.adj <- as.matrix(nhood.adj) - - if(is.null(colnames(nhs))){ - warning("No names attributed to nhoods. Converting indices to names") - colnames(nhs) <- as.character(seq_len(ncol(nhs))) - } - - # Subsetting logic (exactly as in miloR) - if(!is.null(subset.nhoods)){ - if(mode(subset.nhoods) %in% c("character", "logical", "numeric")){ - if(mode(subset.nhoods) %in% c("character")){ - sub.log <- colnames(nhs) %in% subset.nhoods - } else if (mode(subset.nhoods) %in% c("numeric")) { - sub.log <- colnames(nhs) %in% colnames(nhs)[subset.nhoods] - } else{ - sub.log <- subset.nhoods + # Simulate experimental condition + rng = np.random.default_rng(seed=42) + adata.obs["condition"] = rng.choice(["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) + # we simulate differential abundance in NK cells + DA_cells = adata.obs["louvain"] == "1" + adata.obs.loc[DA_cells, "condition"] = rng.choice(["ConditionA", "ConditionB"], size=sum(DA_cells), p=[0.2, 0.8]) + + # Simulate replicates + adata.obs["replicate"] = rng.choice(["R1", "R2", "R3"], size=adata.n_obs) + adata.obs["sample"] = adata.obs["replicate"] + adata.obs["condition"] + milo_mdata = milo.count_nhoods(adata, sample_col="sample") + milo.da_nhoods(milo_mdata, design="~condition", solver="pydeseq2") + + var = milo_mdata["milo"].var.copy() + + n = var.shape[0] + k = max(1, int(0.1 * n)) # e.g. guarantee 10% are “significant,” at least 1 + + # fdrs = np.random.rand(n) + # New Generator interface: + rng = np.random.default_rng() + fdrs = rng.random(n) + da_idx = rng.choice(n, size=k, replace=False) + + # da_idx = np.random.choice(n, size=k, replace=False) + # fdrs[da_idx] = np.random.rand(k) * 0.1 + fdrs[da_idx] = rng.random(k) * 0.1 + + # np.random.shuffle(fdrs) + rng.shuffle(fdrs) + milo_mdata["milo"].var["SpatialFDR"] = fdrs + + milo.build_nhood_graph(milo_mdata) + return milo_mdata + + +def csr_to_r_dgCMatrix(csr: csr_matrix): + """ + Convert a SciPy CSR matrix into an R dgCMatrix using rpy2. + + Returns an rpy2 Matrix object (class “dgCMatrix”). + """ + import rpy2.robjects as ro + from rpy2.robjects import FloatVector, IntVector, numpy2ri + from rpy2.robjects.conversion import localconverter + + # 1) Ensure CSR is in COOrdinate form to extract row/col/data + coo = csr.tocoo() + # R is 1-based, so we must add 1 to Python’s 0-based indices: + i_r = (coo.row + 1).astype(int) + j_r = (coo.col + 1).astype(int) + x_r = coo.data + + # 2) Load the Matrix package in R (only if not already loaded) + ro.r("suppressPackageStartupMessages(library(Matrix))") + + # 3) Build the sparseMatrix(...) call in R + # - `sparseMatrix(i=..., j=..., x=..., dims=c(nrow, ncol))` returns a dgCMatrix by default. + nrow, ncol = csr.shape + r_sparse = ro.r["sparseMatrix"] + + # 4) Call sparseMatrix(i=IntVector(i_r), j=IntVector(j_r), x=FloatVector(x_r), dims=c(nrow, ncol)) + with localconverter(ro.default_converter + numpy2ri.converter): + # Pass `dims` as an IntVector of length 2 + dims_vec = IntVector([int(nrow), int(ncol)]) + mat_r = r_sparse( + i=IntVector(i_r.tolist()), + j=IntVector(j_r.tolist()), + x=FloatVector(x_r.tolist()), + dims=dims_vec, + index1=ro.BoolVector([True]), # tell R that i,j are 1-based + ) + + return mat_r + + +# def _py_to_r(obj): +# """ +# Convert a Python object into an R object, using only context‐managed converters. +# - Any 2D array‐like → force to numpy.ndarray, then to R matrix +# - scipy.sparse → dense numpy → R matrix +# - pandas.DataFrame → R data.frame +# - pandas.Series → logical/int/float/character vector +# - 1D numpy array → R vector +# - Python scalar / single‐item list → length‐1 R vector +# - None → R NULL +# """ +# # Import rpy2 constructs lazily +# import rpy2.robjects as ro +# from rpy2.robjects import numpy2ri, pandas2ri +# from rpy2.robjects.conversion import localconverter + +# # (A) scipy.sparse → dense numpy → R matrix +# if sp.issparse(obj): +# arr = obj.toarray() +# rmat = numpy2ri.py2rpy(arr) +# return rmat + +# # (B) pandas.DataFrame → R data.frame +# if isinstance(obj, pd.DataFrame): +# with localconverter(ro.default_converter + pandas2ri.converter): +# return pandas2ri.py2rpy(obj) + +# # (C) pandas.Series → logical/int/float/character R vector +# if isinstance(obj, pd.Series): +# if obj.dtype == bool: +# return ro.BoolVector(obj.values.tolist()) +# elif np.issubdtype(obj.dtype, np.integer): +# return ro.IntVector(obj.values.tolist()) +# elif np.issubdtype(obj.dtype, np.floating): +# return ro.FloatVector(obj.values.tolist()) +# else: +# return ro.StrVector(obj.astype(str).tolist()) + +# # (D) Force anything array‐like into a NumPy array +# try: +# arr = np.asarray(obj) +# except Exception: +# arr = None + +# if isinstance(arr, np.ndarray): +# # 2D array → R matrix +# rmat = numpy2ri.py2rpy(arr) + +# # 1D array → R vector +# if arr.ndim == 1: +# if arr.dtype == bool: +# return ro.BoolVector(arr.tolist()) +# elif np.issubdtype(arr.dtype, np.integer): +# return ro.IntVector(arr.tolist()) +# elif np.issubdtype(arr.dtype, np.floating): +# return ro.FloatVector(arr.tolist()) +# else: +# return ro.StrVector(arr.astype(str).tolist()) + +# # (E) Python scalar or single‐item list/tuple → length‐1 R vector +# if isinstance(obj, bool): +# return ro.BoolVector([obj]) +# if isinstance(obj, int | np.integer): +# return ro.IntVector([int(obj)]) +# if isinstance(obj, float | np.floating): +# return ro.FloatVector([float(obj)]) +# if isinstance(obj, str): +# return ro.StrVector([obj]) + +# # (F) None → R NULL +# if obj is None: +# return ro.NULL + +# # (G) Python list of simple types → convert to numpy array then recurse +# if isinstance(obj, list): +# return _py_to_r(np.asarray(obj)) + +# # (H) Otherwise, cannot convert +# raise ValueError(f"Cannot convert object of type {type(obj)} to R.") + + +def _py_to_r(obj): + import rpy2.robjects as ro + from rpy2.robjects import numpy2ri, pandas2ri + from rpy2.robjects.conversion import localconverter + + if isinstance(obj, np.ndarray): + return numpy2ri.py2rpy(obj) + if isinstance(obj, pd.DataFrame): + with localconverter(ro.default_converter + pandas2ri.converter): + df = pandas2ri.py2rpy(obj) + return df + if obj is None: + return ro.NULL + with localconverter(ro.default_converter): + r_obj = ro.conversion.py2rpy(obj) + return r_obj + + +# def _r_to_py(r_obj): +# """ +# Convert an R object back into a NumPy array or pandas DataFrame, as appropriate. +# """ +# import rpy2.robjects as ro +# from rpy2.robjects import numpy2ri, pandas2ri +# from rpy2.robjects.conversion import localconverter + +# # R matrix → NumPy array +# if isinstance(r_obj, ro.vectors.Matrix): +# with localconverter(ro.default_converter + numpy2ri.converter): +# return np.asarray(r_obj) + +# # R data.frame → pandas DataFrame +# if isinstance(r_obj, ro.vectors.DataFrame): +# with localconverter(ro.default_converter + pandas2ri.converter): +# return pandas2ri.rpy2py(r_obj) + +# # R vector types → NumPy arrays +# if isinstance(r_obj, ro.vectors.BoolVector): +# return np.asarray(r_obj) +# if isinstance(r_obj, ro.vectors.IntVector): +# return np.asarray(r_obj) +# if isinstance(r_obj, ro.vectors.FloatVector): +# return np.asarray(r_obj) +# if isinstance(r_obj, ro.vectors.StrVector): +# return np.asarray(r_obj) + +# # Otherwise (e.g. R NULL), return as‐is +# return r_obj + + +def _group_nhoods_from_adjacency_r( + nhs_r, nhood_adj_r, da_res_r, is_da_r, merge_discord_r, max_lfc_delta_r, overlap_r, subset_nhoods_r +): + """ + Lazily define the R function .group_nhoods_from_adjacency_pycomp in R’s global env, + then call it directly with arguments that are already R objects. + Returns an R matrix of 0/1. + """ + # Import rpy2 inside the function + import rpy2.robjects as ro + + # Define the R function in R’s global environment: + rcode = r""" + .group_nhoods_from_adjacency_pycomp <- function(nhs, nhood.adj, da.res, is.da, + merge.discord=FALSE, + max.lfc.delta=NULL, + overlap=1, + subset.nhoods=NULL + ){ + # Force everything into a plain base‐R matrix + nhood.adj <- as.matrix(nhood.adj) + + if(is.null(colnames(nhs))){ + warning("No names attributed to nhoods. Converting indices to names") + colnames(nhs) <- as.character(seq_len(ncol(nhs))) } - nhood.adj <- nhood.adj[sub.log, sub.log] - if(length(is.da) == ncol(nhs)){ - nhs <- nhs[sub.log] - is.da <- is.da[sub.log] - da.res <- da.res[sub.log, ] + + # Subsetting logic (as in miloR) + if(!is.null(subset.nhoods)){ + if(mode(subset.nhoods) %in% c("character", "logical", "numeric")){ + if(mode(subset.nhoods) %in% c("character")){ + sub.log <- colnames(nhs) %in% subset.nhoods + } else if (mode(subset.nhoods) %in% c("numeric")) { + sub.log <- colnames(nhs) %in% colnames(nhs)[subset.nhoods] + } else{ + sub.log <- subset.nhoods + } + nhood.adj <- nhood.adj[sub.log, sub.log] + if(length(is.da) == ncol(nhs)){ + nhs <- nhs[sub.log] + is.da <- is.da[sub.log] + da.res <- da.res[sub.log, ] + } else{ + stop("Subsetting `is.da` vector length does not equal nhoods length") + } + } else{ + stop("Incorrect subsetting vector provided:", class(subset.nhoods)) + } } else{ - stop("Subsetting `is.da` vector length does not equal nhoods length") + if(length(is.da) != ncol(nhood.adj)){ + stop("Subsetting `is.da` vector length is not the same dimension as adjacency") + } } - } else{ - stop("Incorrect subsetting vector provided:", class(subset.nhoods)) - } - } else{ - if(length(is.da) != ncol(nhood.adj)){ - stop("Subsetting `is.da` vector length is not the same dimension as adjacency") - } - } - # Discord‐filter - if(isFALSE(merge.discord)){ - discord.sign <- sign(da.res[is.da, 'logFC'] %*% t(da.res[is.da, 'logFC'])) < 0 - nhood.adj[is.da, is.da][discord.sign] <- 0 - } + # Discord‐filter + if(isFALSE(merge.discord)){ + discord.sign <- sign(da.res[is.da, 'logFC'] %*% t(da.res[is.da, 'logFC'])) < 0 + nhood.adj[is.da, is.da][discord.sign] <- 0 + } - # Overlap‐filter - if(overlap > 1){ - nhood.adj[nhood.adj < overlap] <- 0 - } + # Overlap‐filter + if(overlap > 1){ + nhood.adj[nhood.adj < overlap] <- 0 + } - # max.lfc.delta‐filter - if(!is.null(max.lfc.delta)){ - lfc.diff <- sapply(da.res[,"logFC"], "-", da.res[,"logFC"]) - nhood.adj[abs(lfc.diff) > max.lfc.delta] <- 0 - } + # max.lfc.delta‐filter + if(!is.null(max.lfc.delta)){ + lfc.diff <- sapply(da.res[,"logFC"], "-", da.res[,"logFC"]) + nhood.adj[abs(lfc.diff) > max.lfc.delta] <- 0 + } - # Binarize - nhood.adj <- as.matrix((nhood.adj > 0) + 0) + # Binarize + nhood.adj <- as.matrix((nhood.adj > 0) + 0) - # Sanity checks - if(!isSymmetric(nhood.adj)){ - stop("Overlap matrix is not symmetric") - } - if(nrow(nhood.adj) != ncol(nhood.adj)){ - stop("Non-square distance matrix - check nhood subsetting") - } + # Sanity checks + if(!isSymmetric(nhood.adj)){ + stop("Overlap matrix is not symmetric") + } + if(nrow(nhood.adj) != ncol(nhood.adj)){ + stop("Non-square distance matrix ‐ check nhood subsetting") + } - return(nhood.adj) -} -""" + return(nhood.adj) + } + """ + # Evaluate rcode in R's global environment (defines the function): + ro.r(rcode) -r_pkg = r.STAP(r_string, "r_pkg") + # Now retrieve that function from R's globalenv and call it: + f = ro.globalenv[".group_nhoods_from_adjacency_pycomp"] + return f(nhs_r, nhood_adj_r, da_res_r, is_da_r, merge_discord_r, max_lfc_delta_r, overlap_r, subset_nhoods_r) def _group_nhoods_from_adjacency_rcomp( @@ -413,13 +630,11 @@ def _group_nhoods_from_adjacency_rcomp( subset_nhoods=None, ) -> np.ndarray: """ - Mirror of the R code above, returning the final binary adjacency - (dense array) after applying Discord, Overlap, and ΔlogFC filters. + Pure‐Python implementation. """ - # 1) Subset if needed if subset_nhoods is not None: - if isinstance(subset_nhoods, (list, np.ndarray)): + if isinstance(subset_nhoods, list | np.ndarray): arr = np.asarray(subset_nhoods) if np.issubdtype(arr.dtype, np.integer): mask = np.zeros(adjacency.shape[0], dtype=bool) @@ -427,7 +642,7 @@ def _group_nhoods_from_adjacency_rcomp( else: names = np.array(da_res.index, dtype=str) mask = np.isin(names, arr.astype(str)) - elif isinstance(subset_nhoods, (pd.Series, np.ndarray)) and subset_nhoods.dtype == bool: + elif isinstance(subset_nhoods, pd.Series | np.ndarray) and getattr(subset_nhoods, "dtype", None) is bool: if len(subset_nhoods) != adjacency.shape[0]: raise ValueError("Boolean subset_nhoods length must match nhood count") mask = np.asarray(subset_nhoods, dtype=bool) @@ -435,8 +650,8 @@ def _group_nhoods_from_adjacency_rcomp( raise ValueError("subset_nhoods must be bool mask, index list, or name list") adjacency = adjacency[mask, :][:, mask] - da_res = da_res.loc[mask].copy() - is_da = is_da[mask] + da_res = da_res.loc[mask].copy() + is_da = is_da[mask] else: mask = np.ones(adjacency.shape[0], dtype=bool) @@ -449,13 +664,11 @@ def _group_nhoods_from_adjacency_rcomp( adjacency = sp.csr_matrix(adjacency) adjacency = adjacency.tocsr() Acoo = adjacency.tocoo() - rows, cols, data = (np.asarray(Acoo.row, int), - np.asarray(Acoo.col, int), - np.asarray(Acoo.data, float)) + rows, cols, data = (np.asarray(Acoo.row, int), np.asarray(Acoo.col, int), np.asarray(Acoo.data, float)) # 3) Precompute logFC and signs lfc_vals = da_res["logFC"].values - signs = np.sign(lfc_vals) + signs = np.sign(lfc_vals) # 4.1) Discord filter if merge_discord: @@ -463,23 +676,20 @@ def _group_nhoods_from_adjacency_rcomp( else: is_da_rows = is_da[rows] is_da_cols = is_da[cols] - sign_rows = signs[rows] - sign_cols = signs[cols] + sign_rows = signs[rows] + sign_cols = signs[cols] discord_pair = (is_da_rows & is_da_cols) & (sign_rows * sign_cols < 0) keep_discord = ~discord_pair # 4.2) Overlap filter - if overlap <= 1: - keep_overlap = np.ones_like(data, dtype=bool) - else: - keep_overlap = (data >= overlap) + keep_overlap = np.ones_like(data, dtype=bool) if overlap <= 1 else data >= overlap # 4.3) ΔlogFC filter if max_lfc_delta is None: keep_lfc = np.ones_like(data, dtype=bool) else: diffs = np.abs(lfc_vals[rows] - lfc_vals[cols]) - keep_lfc = (diffs <= max_lfc_delta) + keep_lfc = diffs <= max_lfc_delta # 5) Combine masks keep_mask = keep_discord & keep_overlap & keep_lfc @@ -494,68 +704,174 @@ def _group_nhoods_from_adjacency_rcomp( return pruned_bin - -@pytest.mark.parametrize("merge_discord_flag, overlap_val, max_lfc_val", [ - (False, 1, None), - (True, 1, None), - (False, 2, None), - (False, 3, None), - (False, 5, None), - (False, 15, None), - (False, 100, None), - (False, 1, 0.5), - (False, 1, 1.0), - (False, 1, 2.0), - (False, 1, 3.0), - (False, 1, 4.0), - (False, 1, 5.0), -]) -@pytest.fixture -def test_sparse_adjacency_filters_match_R(annotate_nhoods_mdata, merge_discord_flag, overlap_val, max_lfc_val): +@pytest.mark.parametrize( + "merge_discord_flag, overlap_val, max_lfc_val", + [ + (False, 1, None), + (True, 1, None), + (False, 2, None), + (False, 3, None), + (False, 5, None), + (False, 15, None), + (False, 100, None), + (False, 1, 0.5), + (False, 1, 1.0), + (False, 1, 2.0), + (False, 1, 3.0), + (False, 1, 4.0), + (False, 1, 5.0), + ], +) +def test_sparse_adjacency_filters_match_R(group_nhoods_mdata, merge_discord_flag, overlap_val, max_lfc_val): """ - Compare the output of the R version (via r_pkg) versus the Python version - for various combinations of merge_discord, overlap, and max_lfc_delta. + Compare the R version against the Python version for various + settings of merge_discord, overlap, and max_lfc_delta. """ - # 4.1) Extract inputs from mdata + # 1) Extract inputs from fixture + mdata = group_nhoods_mdata.copy() + nhs = mdata["rna"].obsm["nhoods"].copy() + nhood_adj = mdata["milo"].varp["nhood_connectivities"].copy() # sparse + da_res = mdata["milo"].var.copy() # DataFrame with "logFC" + is_da = (da_res["SpatialFDR"].values < 0.1) & (da_res["logFC"].values > 0) + + # 2) Convert to R objects + nhs_r = _py_to_r(np.zeros((nhs.shape[0], nhs.shape[1]))) + nhood_adj_r = csr_to_r_dgCMatrix(nhood_adj) + da_res_r = _py_to_r(da_res) + is_da_r = _py_to_r(is_da) + merge_discord_r = _py_to_r(bool(merge_discord_flag)) + overlap_r = _py_to_r(int(overlap_val)) + max_lfc_delta_r = _py_to_r(max_lfc_val) # None → R NULL + subset_nhoods_r = _py_to_r(None) # always None here + + # 3) Call the R implementation + r_out = _group_nhoods_from_adjacency_r( + nhs_r, nhood_adj_r, da_res_r, is_da_r, merge_discord_r, max_lfc_delta_r, overlap_r, subset_nhoods_r + ) - mdata = annotate_nhoods_mdata.copy() + # 4) Convert R output → NumPy + import rpy2.robjects as ro + from rpy2.robjects import numpy2ri + from rpy2.robjects.conversion import localconverter - nhs = mdata["rna"].obsm["nhoods"].copy() - nhood_adj = mdata["milo"].varp["nhood_connectivities"].copy() # sparse - da_res = mdata["milo"].var.copy() - is_da = (da_res["SpatialFDR"].values < 0.1) & (da_res["logFC"].values > 0) - - # 4.2) Run R version (returns a dense matrix) - r_out = r_pkg._group_nhoods_from_adjacency_pycomp( - _py_to_r(nhs), - _py_to_r(nhood_adj), - _py_to_r(da_res), - _py_to_r(is_da), - _py_to_r(merge_discord_flag), - _py_to_r(max_lfc_val), - _py_to_r(overlap_val), - subset_nhoods = r.ro.NULL - ) - adj_R = _r_to_py(r_out) - # adj_R is a dense NumPy matrix of shape (N, N) + if isinstance(r_out, ro.vectors.Matrix): + with localconverter(ro.default_converter + numpy2ri.converter): + adj_R = np.asarray(r_out) + else: + adj_R = np.asarray(r_out) - # 4.3) Run Python version + assert adj_R.shape == nhood_adj.shape + + # 5) Call the Python implementation adj_py = _group_nhoods_from_adjacency_rcomp( nhood_adj, da_res, is_da, - merge_discord = merge_discord_flag, - overlap = overlap_val, - max_lfc_delta = max_lfc_val, - subset_nhoods = None + merge_discord=merge_discord_flag, + overlap=overlap_val, + max_lfc_delta=max_lfc_val, + subset_nhoods=None, + ) + + # 6) Compare + assert adj_py.shape == adj_R.shape + assert np.array_equal(adj_py, adj_R), ( + f"Mismatch for (merge_discord={merge_discord_flag}, overlap={overlap_val}, max_lfc={max_lfc_val})" ) - # adj_py is also a dense NumPy matrix of shape (N, N) - - # 4.4) Compare element‐by‐element - # We convert adj_R (which may be a pandas object) explicitly to NumPy - if not isinstance(adj_R, np.ndarray): - adj_R = np.asarray(adj_R) - assert adj_R.shape == adj_py.shape - # Use a strict equality test (all entries must match) - assert np.array_equal(adj_R, adj_py), \ - f"Difference detected (merge_discord={merge_discord_flag}, overlap={overlap_val}, max_lfc={max_lfc_val})" \ No newline at end of file + + +@pytest.mark.parametrize( + "nhood_group_obs, subset_nhoods, min_n_nhoods, mode", + [ + # default obs-name, all neighborhoods, last-wins + ("nhood_groups", None, 1, "last_wins"), + # default obs-name, only neighborhoods "0" and "1", last-wins + ("nhood_groups", None, 1, "last_wins"), + # default obs-name, all neighborhoods, exclude overlaps with threshold 2 + ("nhood_groups", None, 2, "exclude_overlaps"), + # custom obs-name, only neighborhood "2", exclude overlaps w/ threshold 3 + ("custom_lbls", None, 3, "exclude_overlaps"), + ], +) +def test_annotate_cells_from_nhoods_various( + group_nhoods_mdata, + nhood_group_obs, + subset_nhoods, + min_n_nhoods, + mode, +): + from pertpy.tools._milo import Milo + + milo = Milo() + print(milo) + mdata = group_nhoods_mdata.copy() + + assert "SpatialFDR" in mdata["milo"].var.columns + milo.group_nhoods(mdata) + if nhood_group_obs == "custom_lbls": + # Create a custom nhood group obs column + mdata["milo"].var["custom_lbls"] = mdata["milo"].var["nhood_groups"].copy() + + # run the annotation + milo.annotate_cells_from_nhoods( + mdata, + nhood_group_obs=nhood_group_obs, + subset_nhoods=subset_nhoods, + min_n_nhoods=min_n_nhoods, + mode=mode, + ) + + if nhood_group_obs == "custom_lbls": + # Create a custom nhood group obs column + mdata["rna"].obs["custom_lbls"] = mdata["rna"].obs["nhood_groups"].copy() + + # the new column must exist + assert nhood_group_obs in mdata["rna"].obs.columns + + col = mdata["rna"].obs[nhood_group_obs] + + # type checks + assert col.dtype == object + assert len(col) == mdata["rna"].n_obs + + # non-annotated cells should be NaN + # annotated cells should only use labels from the chosen neighborhoods + # non_null = col.dropna().astype(str).values + # non_null = [ + # x for x in col.astype(str).values + # if x.lower() not in ("nan", "") + # ] + + # if subset_nhoods is None: + # # allowed = set(mdata["milo"].var[nhood_group_obs].astype(str).unique()) + # allowed = { + # x for x in mdata["milo"].var[nhood_group_obs].astype(str).unique() + # if x.lower() != "nan" + # } + # else: + # allowed = set(subset_nhoods) + # 1) grab the raw Series + ser_obs = mdata["rna"].obs[nhood_group_obs] + ser_var = mdata["milo"].var[nhood_group_obs] + + # 2) drop real missing values + ser_obs_non_na = ser_obs[ser_obs.notna()] + ser_var_non_na = ser_var[ser_var.notna()] + + # 3) convert to str for comparison + non_null = set(ser_obs_non_na.astype(str).unique()) + allowed = set(ser_var_non_na.astype(str).unique()) + + assert non_null.issubset(allowed) + + # assert set(non_null).issubset(allowed) + + # For exclude_overlaps, ensure that no cell is assigned if it belongs + # to fewer than min_n_nhoods neighborhoods + if mode == "exclude_overlaps": + # build a quick membership count: + np.asarray(mdata["rna"].obs[nhood_group_obs].notna(), bool) + counts = (mdata["rna"].obsm["nhoods"].astype(int)).sum(axis=1) + too_few = counts < min_n_nhoods + too_few = np.asarray(too_few).ravel() + assert (col[too_few].isna()).all() From 3c0fd6bd448a03de09af0668c90cde6467a7d877 Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Thu, 12 Jun 2025 08:17:34 +0200 Subject: [PATCH 05/10] removed formulaic_contrasts, added tests for find_nhood_group_markers formulaic_contrasts was used only for edgeR, which now uses edgeR internals. The tests for find_nhood_group_markers load the scanpy pbmc3k dataset. All R dependencies required for the tests: base, stats, limma, edgeR, scran, scuttle, SingleCellExperiment. --- pertpy/tools/_milo.py | 411 ++++++++++++--------------------------- tests/tools/test_milo.py | 220 +++++++++++++++++---- 2 files changed, 311 insertions(+), 320 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 454a5311..c3cbe5a8 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -382,7 +382,8 @@ def da_nhoods( # Fit NB-GLM counts_filtered = count_mat[np.ix_(keep_nhoods, keep_smp)] lib_size_filtered = lib_size[keep_smp] - count_mat_r = numpy2ri.py2rpy(counts_filtered) + with localconverter(ro.default_converter + numpy2ri.converter): + count_mat_r = numpy2ri.py2rpy(counts_filtered) lib_size_r = FloatVector(lib_size_filtered) dge = edgeR.DGEList(counts=count_mat_r, lib_size=lib_size_r) dge = edgeR.calcNormFactors(dge, method="TMM") @@ -1349,30 +1350,30 @@ def _group_nhoods_from_adjacency( # 1) Optional subsetting of neighborhoods --------------------------------------------------- # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. if subset_nhoods is not None: - if isinstance(subset_nhoods, list | np.ndarray): - # could be integer indices or names - if all(isinstance(x, int | np.integer) for x in subset_nhoods): - # direct integer indices - mask = np.zeros(adjacency.shape[0], dtype=bool) - mask[np.array(subset_nhoods, dtype=int)] = True - else: - # assume list of names - names = np.array(da_res.index, dtype=str) - mask = np.isin(names, subset_nhoods) - elif isinstance(subset_nhoods, pd.Series | np.ndarray) and subset_nhoods.dtype == bool: - # boolean mask + # 1) boolean‐mask case first + if isinstance(subset_nhoods, pd.Series | np.ndarray) and subset_nhoods.dtype == bool: if len(subset_nhoods) != adjacency.shape[0]: raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") mask = np.asarray(subset_nhoods, dtype=bool) + + # 2) integer‐index or name list next + elif isinstance(subset_nhoods, list | np.ndarray): + arr = np.asarray(subset_nhoods) + # integer indices? + if np.issubdtype(arr.dtype, np.integer): + mask = np.zeros(adjacency.shape[0], dtype=bool) + mask[arr.astype(int)] = True + # name list? + else: + names = da_res.index.to_numpy(dtype=str) + mask = np.isin(names, arr.astype(str)) + else: raise ValueError("subset_nhoods must be a boolean mask, a list of indices, or a list of names.") - # Apply subsetting to adjacency, da_res, and is_da adjacency = adjacency[mask, :][:, mask] da_res = da_res.loc[mask].copy() is_da = is_da[mask] - else: - mask = np.ones(adjacency.shape[0], dtype=bool) M = adjacency.shape[0] if da_res.shape[0] != M or is_da.shape[0] != M: @@ -1435,6 +1436,9 @@ def _group_nhoods_from_adjacency( # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. + # Issue with dematrix after subsetting adjacency matrix: + # dematrix in sc._utils.get_igraph_from_adjacency does not convert to dense numpy matrix. + # Trying direct conversion to igraph: g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- @@ -1548,29 +1552,32 @@ def group_nhoods( # 6) Write results back into `adata.var["NhoodGroup"]` ----------------------------------------------------------- N_full = adata.var.shape[0] - out = np.array([""] * N_full, dtype=object) - out[:] = pd.NA + out = np.array([pd.NA] * N_full, dtype=object) if subset_nhoods is None: - # Every neighborhood was labeled + # no subsetting: every label goes into the full array out[:] = labels else: - # Reconstruct the same mask logic to place `labels` in the correct positions - if isinstance(subset_nhoods, list | np.ndarray): + # 1) Boolean‐mask case first + if isinstance(subset_nhoods, pd.Series | np.ndarray) and getattr(subset_nhoods, "dtype", None).kind == "b": + if len(subset_nhoods) != N_full: + raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") + mask_idx = np.asarray(subset_nhoods, dtype=bool) + + # 2) Integer‐index or name‐list next + elif isinstance(subset_nhoods, list | np.ndarray): arr = np.asarray(subset_nhoods) if np.issubdtype(arr.dtype, np.integer): mask_idx = np.zeros(N_full, dtype=bool) mask_idx[arr.astype(int)] = True else: - names = np.array(adata.var.index, dtype=str) + names = adata.var.index.to_numpy(dtype=str) mask_idx = np.isin(names, arr.astype(str)) - elif isinstance(subset_nhoods, pd.Series | np.ndarray) and subset_nhoods.dtype == bool: - if len(subset_nhoods) != N_full: - raise ValueError("Boolean subset_nhoods must have length = number of neighborhoods.") - mask_idx = np.asarray(subset_nhoods, dtype=bool) + else: raise ValueError("`subset_nhoods` must be a boolean mask, a list of indices, or a list of names.") + # 3) Place the M labels back into the N-length output out[mask_idx] = labels adata.var["nhood_groups"] = out @@ -1604,7 +1611,8 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ fake_meta = pd.DataFrame( { "CellID": nhs.obs_names[(np.asarray(nhs.X.sum(1).flatten()).ravel() != 0)], - "Nhood_Group": [np.nan for _ in range((np.asarray(nhs.X.sum(1).flatten()).ravel() != 0).sum())], + # "Nhood_Group": [np.nan for _ in range((np.asarray(nhs.X.sum(1).flatten()).ravel() != 0).sum())], + "Nhood_Group": [pd.NA for _ in range((np.asarray(nhs.X.sum(1).flatten()).ravel() != 0).sum())], } ) fake_meta.index = fake_meta["CellID"].copy() @@ -1622,19 +1630,13 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ mask = np.asarray(nhs[:, nhood_x].X.sum(1)).ravel() > 0 nhood_gr_cells = nhs.obs_names[mask] - # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = cur_nh_group#fake_meta.loc[nhood_gr_cells, "Nhood_Group"].apply(lambda x: cur_nh_group if np.isnan(x) else np.nan) - # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = [cur_nh_group if np.isnan(x) else np.nan for x in fake_meta.loc[nhood_gr_cells, "Nhood_Group"]] - # fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = fake_meta.loc[nhood_gr_cells, "Nhood_Group"].apply(lambda x: cur_nh_group if np.isnan(x) else np.nan) - # for i in range(len(nhood_gr)): # Assuming you want to iterate over nhood.gr - fake_meta.loc[nhood_gr_cells, "Nhood_Group"] = np.where( (fake_meta.loc[nhood_gr_cells, "Nhood_Group"]).isna(), nhood_gr[i], pd.NA, - # np.nan ) - # fake_meta.loc[fake_meta.Nhood_Group.] - mdata["rna"].obs["nhood_groups"] = np.nan + + mdata["rna"].obs["nhood_groups"] = pd.NA mdata["rna"].obs.loc[fake_meta.CellID.to_list(), "nhood_groups"] = fake_meta.Nhood_Group.to_numpy() def _get_cells_in_nhoods(self, adata, nhood_ids): @@ -1758,146 +1760,6 @@ def get_mean_expression(self, adata, groupby: str, var_names: list[str]) -> pd.D mean_df = pd.DataFrame(mean_mat, index=var_names, columns=groups.columns) return mean_df - def _run_limma_trend_contrasts( - self, - pdata: AnnData, - nhood_group_obs: str, - *, - formula: str, - group_to_compare: str | None = None, - baseline: str | None = None, - subset_samples: list[str] | None = None, - ) -> pd.DataFrame: - """Run limma (with trend) on a pseudobulk AnnData whose .X is continuous (e.g. log‐CPM). - - If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. - Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. - - Returns a pandas DataFrame with columns: - ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). - """ - if _is_counts(pdata.X): - raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") - - # ──────────────────────────────────────────────────────────────────────────────── - # 0) Imports and R‐setup - # ──────────────────────────────────────────────────────────────────────────────── - edger, limma, rstats, rbase = self._setup_rpy2() - import rpy2.robjects as ro - from formulaic_contrasts import FormulaicContrasts - from rpy2.robjects import IntVector, StrVector, baseenv, numpy2ri, pandas2ri - from rpy2.robjects.conversion import localconverter - - # ──────────────────────────────────────────────────────────────────────────────── - # 1) Pull out (n_cells × n_genes) continuous expression matrix and transpose - # so we get (n_genes × n_cells), as required by limma. - # ──────────────────────────────────────────────────────────────────────────────── - expr_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T - - # ──────────────────────────────────────────────────────────────────────────────── - # 2) Build sample_obs (optionally subset to a given list of sample‐IDs) - # ──────────────────────────────────────────────────────────────────────────────── - sample_obs = pdata.obs.copy() - if subset_samples is not None: - sample_obs = sample_obs.loc[subset_samples] - expr_mat = expr_mat[:, np.isin(pdata.obs_names, subset_samples)] - - # ──────────────────────────────────────────────────────────────────────────────── - # 3) Build FormulaicContrasts on the full sample_obs to get “baseline” design - # ──────────────────────────────────────────────────────────────────────────────── - fc_full = FormulaicContrasts(sample_obs, formula) - design_df = pd.DataFrame(fc_full.design_matrix) # ○ shape = (n_samples × K) - with localconverter(ro.default_converter + pandas2ri.converter): - design_r = pandas2ri.py2rpy(design_df) - design_r = rbase.as_matrix(design_r) # R matrix (n_samples × K) - - # ──────────────────────────────────────────────────────────────────────────────── - # 4) Convert expr_mat → an R matrix with rownames & colnames - # ──────────────────────────────────────────────────────────────────────────────── - r_mat = numpy2ri.py2rpy(expr_mat) # now an R “matrix” of shape (n_genes × n_cells) - r_colnames = StrVector(np.asarray(sample_obs.index)) - r_rownames = StrVector(np.asarray(pdata.var_names)) - dim_list = ro.r.list(r_rownames, r_colnames) - assign_dim = baseenv["dimnames<-"] - r_mat = assign_dim(r_mat, dim_list) - - # ──────────────────────────────────────────────────────────────────────────────── - # 5) Fit the linear model (lmFit) once on the “baseline” design - # We skip voom because pdata.X is already log‐normalized. Then call eBayes(..., trend=TRUE). - # ──────────────────────────────────────────────────────────────────────────────── - fit = limma.lmFit(r_mat, design_r) - # fit = limma.eBayes(fit, trend=True,) - - # ──────────────────────────────────────────────────────────────────────────────── - # 6) SINGLE‐CONTRAST branch - # ──────────────────────────────────────────────────────────────────────────────── - if group_to_compare is not None and baseline is not None: - # (a) Build contrast vector from fc_full: - cont = fc_full.contrast(nhood_group_obs, baseline, group_to_compare) - r_contrast = IntVector(np.asarray(cont)) - - # (b) Fit contrasts & re‐run eBayes (with trend) on that single contrast: - fit2 = limma.contrasts_fit(fit, contrasts=r_contrast) - fit2 = limma.eBayes(fit2, trend=True, robust=True) - - # (c) Extract topTable for coefficient 1 (the single contrast) - top = limma.topTable(fit2, coef=1, sort_by="none", number=np.inf) - with localconverter(ro.default_converter + pandas2ri.converter): - top_df = pandas2ri.rpy2py(top) - - # (d) Rename columns: “adj.P.Val”→“adj_PValue”, “P.Value”→“PValue” - top_df = top_df.rename(columns={"adj.P.Val": "adj_PValue", "P.Value": "PValue"}) - top_df = top_df.reset_index().rename(columns={"index": "variable"}) - return top_df[["variable", "logFC", "t", "B", "PValue", "adj_PValue"]] - - # ──────────────────────────────────────────────────────────────────────────────── - # 7) ONE‐VS‐REST branch (group_to_compare == baseline == None) - # ──────────────────────────────────────────────────────────────────────────────── - col = sample_obs[nhood_group_obs] - unique_groups = col.cat.categories.tolist() if pd.api.types.is_categorical_dtype(col) else col.unique().tolist() - - results_list: list[Any] = [] - - for grp in unique_groups: - # (a) Recode sample_obs so that non‐grp → "rest" - tmp_obs = sample_obs.copy() - tmp_obs[nhood_group_obs] = tmp_obs[nhood_group_obs].cat.add_categories("rest") - tmp_obs[nhood_group_obs] = tmp_obs[nhood_group_obs].apply(lambda x, grp=grp: x if x == grp else "rest") - - # (b) Build FormulaicContrasts on tmp_obs with same formula - fc_sub = FormulaicContrasts(tmp_obs, formula) - design_df = pd.DataFrame(fc_sub.design_matrix) - - with localconverter(ro.default_converter + pandas2ri.converter): - design_r_sub = pandas2ri.py2rpy(design_df) - design_r_sub = rbase.as_matrix(design_r_sub) - - # (c) Re‐fit lmFit + eBayes(trend=True) on exactly the same r_mat but new design - fit_sub = limma.lmFit(r_mat, design_r_sub) - fit_sub = limma.eBayes(fit_sub, trend=True, robust=True) - - # (d) Contrast “rest vs grp” - cont_sub = fc_sub.contrast(nhood_group_obs, "rest", grp) - r_cont_sub = IntVector(np.asarray(cont_sub)) - - fit_sub2 = limma.contrasts_fit(fit_sub, contrasts=r_cont_sub) - fit_sub2 = limma.eBayes(fit_sub2, trend=True, robust=True) - - # (e) topTable on that contrast - top_sub = limma.topTable(fit_sub2, coef=1, sort_by="none", number=np.inf) - with localconverter(ro.default_converter + pandas2ri.converter): - top_df_sub = pandas2ri.rpy2py(top_sub) - - top_df_sub = top_df_sub.rename(columns={"adj.P.Val": "adj_PValue", "P.Value": "PValue"}) - top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) - top_df_sub["group"] = grp - - results_list.append(top_df_sub[["variable", "logFC", "t", "B", "PValue", "adj_PValue", "group"]]) - - # (f) Concatenate results and return - final_df = pd.concat(results_list, ignore_index=True) - return final_df - def _run_edger_contrasts( self, pdata: AnnData, @@ -1921,71 +1783,90 @@ def _run_edger_contrasts( edger, limma, rstats, rbase = self._setup_rpy2() import rpy2.robjects as ro - from formulaic_contrasts import FormulaicContrasts from rpy2.robjects import IntVector, StrVector, baseenv, numpy2ri, pandas2ri from rpy2.robjects.conversion import localconverter - count_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T + print(pdata) # 2) Build a pandas DataFrame for sample‐level covariates - sample_obs = pdata.obs.copy() - - fc = FormulaicContrasts(sample_obs, formula) - design_df = pd.DataFrame(fc.design_matrix) - with localconverter(ro.default_converter + pandas2ri.converter): - design_r = pandas2ri.py2rpy(design_df) - design_r = rbase.as_matrix(design_r) - - # Wrap the numpy count_mat into an R integer matrix - # with localconverter(ro.default_converter + numpy2ri.converter): - # rmat = numpy2ri - rmat = numpy2ri.py2rpy(count_mat) - - r_colnames = StrVector(np.asarray(pdata.obs_names)) - r_rownames = StrVector(np.asarray(pdata.var_names)) - dim_list = ro.r.list(r_rownames, r_colnames) - - assign_dim = baseenv["dimnames<-"] - rmat = assign_dim(rmat, dim_list) - - # Build the DGEList - dge = edger.DGEList(counts=rmat) - - # Calculate TMM normalization factors - dge = edger.calcNormFactors(dge, method="TMM") - - # Estimate dispersion - # not needed in edgeR 4.x, automatically calculated in the Cpp implementation - # dge = edger.estimateDisp(dge, r_model_mat) - - # Fit the quasi‐likelihood model - fit = edger.glmQLFit(dge, design_r, robust=True) # 6) Single‐contrast vs one‐vs‐rest results_list: list[Any] = [] # If a specific two‐level contrast was given: if group_to_compare is not None and baseline is not None: - contrast_vec = fc.contrast(nhood_group_obs, baseline, group_to_compare) + # subset pdata to only those two groups + pdata = pdata[pdata.obs[nhood_group_obs].isin([baseline, group_to_compare])].copy() + if pdata.shape[0] == 0: + raise ValueError(f"No samples found with {nhood_group_obs} in [{baseline}, {group_to_compare}].") + + ### build R count matrix + count_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T + with localconverter(ro.default_converter + numpy2ri.converter): + rmat = numpy2ri.py2rpy(count_mat) + + r_colnames = StrVector(np.asarray(pdata.obs_names)) + r_rownames = StrVector(np.asarray(pdata.var_names)) + dim_list = ro.r.list(r_rownames, r_colnames) + + assign_dim = baseenv["dimnames<-"] + rmat = assign_dim(rmat, dim_list) + + # Build the DGEList + dge = edger.DGEList(counts=rmat) + + # build R model matrix from sample_obs, setting levels of nhood_group_obs to baseline and group_to_compare + sample_obs = pdata.obs.copy() + if group_to_compare is not None and baseline is not None: + # If a specific two‐level contrast was given, subset to those samples only + sample_obs[nhood_group_obs] = pd.Categorical( + sample_obs[nhood_group_obs].values, categories=[baseline, group_to_compare] + ) + print(sample_obs.shape) + print(count_mat.shape) + + with localconverter(ro.default_converter + pandas2ri.converter): + robs = pandas2ri.py2rpy(sample_obs) + design_r = rstats.model_matrix(rstats.as_formula(formula), robs) + print(design_r.nrow) + + # Fit the quasi‐likelihood model + dge = edger.calcNormFactors(dge, method="TMM") - r_contrast = IntVector(np.asarray(contrast_vec)) + fit = edger.glmQLFit(dge, design_r, robust=True) # Now run QLF test with that contrast - qlf = edger.glmQLFTest(fit, contrast=r_contrast) + qlf = edger.glmQLFTest(fit, coef=nhood_group_obs + group_to_compare) top = edger.topTags(qlf, sort_by="none", n=np.inf)[0] # Convert top (an R data.frame) to pandas with localconverter(ro.default_converter + pandas2ri.converter): top_df = pandas2ri.rpy2py(top) # Clean up column names (they come as “logFC”, “PValue”, “FDR”) - top_df = top_df.rename(columns={"FDR": "adj_PValue"}) + top_df = top_df.rename(columns={"FDR": "adj_p_value", "PValue": "p_value", "logFC": "log_fc"}) top_df = top_df.reset_index().rename(columns={"index": "variable"}) return top_df # results_list.append(top_df[["variable", "logFC", "PValue", "adj_PValue"]]) else: + ### build R count matrix + count_mat = pdata.X.toarray().T if hasattr(pdata.X, "toarray") else np.asarray(pdata.X).T + with localconverter(ro.default_converter + numpy2ri.converter): + rmat = numpy2ri.py2rpy(count_mat) + + r_colnames = StrVector(np.asarray(pdata.obs_names)) + r_rownames = StrVector(np.asarray(pdata.var_names)) + dim_list = ro.r.list(r_rownames, r_colnames) + + assign_dim = baseenv["dimnames<-"] + rmat = assign_dim(rmat, dim_list) + + # Build the DGEList + dge = edger.DGEList(counts=rmat) + sample_obs = pdata.obs.copy() + col = sample_obs[nhood_group_obs] - if pd.api.types.is_categorical_dtype(col): + if isinstance(col, pd.api.types.CategoricalDtype): unique_groups = col.cat.categories.tolist() else: unique_groups = col.unique().tolist() @@ -1993,49 +1874,31 @@ def _run_edger_contrasts( results_list = [] for grp in unique_groups: + # build group‐specific design matrix tmp_obs = pdata.obs.copy() tmp_obs[nhood_group_obs] = [x if x == grp else "rest" for x in tmp_obs[nhood_group_obs]] tmp_obs[nhood_group_obs] = pd.Categorical(tmp_obs[nhood_group_obs].values, categories=["rest", grp]) - - # 2) Build a new FormulaicContrasts on tmp_obs - fc = FormulaicContrasts(tmp_obs, formula) - design_df = pd.DataFrame(fc.design_matrix) - with localconverter(ro.default_converter + pandas2ri.converter): - design_r = pandas2ri.py2rpy(design_df) - design_r = rbase.as_matrix(design_r) - - # # 3) Convert design_df_sub to an R matrix - # rmat = numpy2ri.py2rpy(count_mat) - - # r_colnames = StrVector(np.asarray(pdata.obs_names)) - # r_rownames = StrVector(np.asarray(pdata.var_names)) - # dim_list = ro.r.list(r_rownames, r_colnames) - - # assign_dim = baseenv["dimnames<-"] - # rmat = assign_dim(rmat, dim_list) + robs = pandas2ri.py2rpy(tmp_obs) + design_r = rstats.model_matrix(rstats.as_formula(formula), robs) # 6) Build a DGEList for this subset (or reuse dge_full but safer to make a fresh one) dge = edger.calcNormFactors(dge, method="TMM") fit_sub = edger.glmQLFit(dge, design_r, robust=True) - # 7) Build contrast vector: “rest” vs “grp” - contrast_vec = fc.contrast(nhood_group_obs, "rest", grp) - contrast_r = IntVector(np.asarray(contrast_vec)) - # 8) QLF test on that contrast - qlf_sub = edger.glmQLFTest(fit_sub, contrast=contrast_r) + qlf_sub = edger.glmQLFTest(fit_sub, coef=nhood_group_obs + grp) top_sub = edger.topTags(qlf_sub, sort_by="none", n=np.inf)[0] with localconverter(ro.default_converter + pandas2ri.converter): top_df_sub = pandas2ri.rpy2py(top_sub) - top_df_sub = top_df_sub.rename(columns={"FDR": "adj_PValue"}) + top_df_sub = top_df_sub.rename(columns={"FDR": "adj_p_value", "PValue": "p_value", "logFC": "log_fc"}) top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) top_df_sub["group"] = grp - results_list.append(top_df_sub[["variable", "logFC", "PValue", "adj_PValue", "group"]]) + results_list.append(top_df_sub[["variable", "log_fc", "p_value", "adj_p_value", "group"]]) # 9) Concatenate and return final_df = pd.concat(results_list, ignore_index=True) @@ -2127,13 +1990,15 @@ def _run_pydeseq2_contrasts( } ) .sort_values("p_value") - .reset_index(drop=True) + .reset_index(names=["variable"]) ) return df # 2) One‐vs‐rest: get all levels of nhood_group_obs col = pdata.obs[nhood_group_obs] - unique_groups = col.cat.categories.tolist() if pd.api.types.is_categorical_dtype(col) else col.unique().tolist() + unique_groups = ( + col.cat.categories.tolist() if isinstance(col, pd.api.types.CategoricalDtype) else col.unique().tolist() + ) all_results = [] for grp in unique_groups: @@ -2172,7 +2037,6 @@ def _run_pydeseq2_contrasts( .reset_index(names=["variable"]) .assign(group=grp) .sort_values("p_value") - .reset_index(drop=True) ) all_results.append(df) @@ -2190,7 +2054,8 @@ def _filter_by_expr_edger(self, pdata, formula, **kwargs): counts = pdata.X counts = counts.toarray().T if hasattr(counts, "toarray") else np.asarray(counts).T - rcounts = numpy2ri.py2rpy(counts) + with localconverter(ro.default_converter + numpy2ri.converter): + rcounts = numpy2ri.py2rpy(counts) obs = pdata.obs with localconverter(ro.default_converter + pandas2ri.converter): robs = pandas2ri.py2rpy(obs) @@ -2224,7 +2089,8 @@ def _filter_highly_variable_scran(self, pdata, n_top_genes): from rpy2.robjects.conversion import localconverter counts = pdata.X - rcounts = numpy2ri.py2rpy(counts.T) + with localconverter(ro.default_converter + numpy2ri.converter): + rcounts = numpy2ri.py2rpy(counts.T) obs = pdata.obs var = pdata.var @@ -2248,7 +2114,7 @@ def _filter_highly_variable_scran(self, pdata, n_top_genes): def find_nhood_group_markers( self, - mdata: MuData, + data: AnnData | MuData, group_to_compare: str | None = None, baseline: str | None = None, nhood_group_obs: str = "nhood_groups", @@ -2261,7 +2127,7 @@ def find_nhood_group_markers( n_top_genes: int = 7500, filter_method: str | None = "scanpy", var_names: Collection[str] | None = None, - de_method: Literal["pydeseq2", "statsmodels", "edger", "limma"] = "pydeseq2", + de_method: Literal["pydeseq2", "edger"] = "pydeseq2", quiet: bool = True, alpha: float = 0.05, use_eb: bool = False, @@ -2335,13 +2201,22 @@ def find_nhood_group_markers( func = pseudobulk_function # 1) Subset to cells that have a non‐NA group label - if key not in mdata.mod_names: - raise KeyError(f"Modality '{key}' not found in mdata; available keys: {list(mdata.keys())}") - adata = mdata[key] + if isinstance(data, AnnData): + adata = data + elif isinstance(data, MuData): + mdata = data + if key not in mdata.mod_names: + raise KeyError(f"Modality '{key}' not found in mdata; available keys: {list(mdata.keys())}") + adata = mdata[key] + else: + raise TypeError("data must be an AnnData or MuData object.") if nhood_group_obs not in adata.obs.columns: raise KeyError(f"Column '{nhood_group_obs}' not found in adata.obs") - if not pd.api.types.is_categorical_dtype(adata.obs[nhood_group_obs]): + + from pandas.api.types import CategoricalDtype + + if not isinstance(adata.obs[nhood_group_obs].dtype, CategoricalDtype): adata.obs[nhood_group_obs] = adata.obs[nhood_group_obs].astype("category") n_non_na = adata.obs[nhood_group_obs].notna().sum() @@ -2384,9 +2259,6 @@ def find_nhood_group_markers( all_variables = [sample_col, nhood_group_obs] + covariates # 3) Pseudobulk aggregation - # counts_per_sample_group = adata.obs.groupby([sample_col, nhood_group_obs]).size() - # if (counts_per_sample_group == 0).any(): - # raise ValueError("Some (sample, Nhood_Group) combinations have zero cells; pseudobulk would be empty.") pdata = sc.get.aggregate(tmp_data, by=all_variables, func=func, axis=0, layer=layer) pdata.X = pdata.layers[func].copy() @@ -2448,25 +2320,7 @@ def find_nhood_group_markers( alpha=alpha, quiet=quiet, ) - if de_method == "statsmodels": - raise NotImplementedError( - "statsmodels is not yet implemented for neighborhood group markers; use pydeseq2 or edgeR with counts, or limma with normalized counts." - ) - logger.warning( - "Using log‐normalized data is not recommended; consider using counts with pydeseq2 or edgeR instead." - ) - if _is_counts(pdata.X): - raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") - return self._run_statsmodels_contrasts( - pdata, - nhood_group_obs=nhood_group_obs, - formula=base_formula, - group_to_compare=group_to_compare, - baseline=baseline, - use_eb=use_eb, - **kwargs, - ) if de_method == "edger": if not _is_counts(pdata.X): raise ValueError("`pdata.X` appears to be raw counts, but this function expects raw counts.") @@ -2477,23 +2331,8 @@ def find_nhood_group_markers( group_to_compare=group_to_compare, baseline=baseline, ) - if de_method == "limma": - logger.warning( - "Using log‐normalized data is not recommended; consider using counts with pydeseq2 or edgeR instead." - ) - if _is_counts(pdata.X): - raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") - return self._run_limma_trend_contrasts( - pdata, - nhood_group_obs=nhood_group_obs, - formula=base_formula, - group_to_compare=group_to_compare, - baseline=baseline, - ) else: - raise ValueError( - f"de_method must be one of 'pydeseq2', 'statsmodels', 'edger', or 'limma', not '{de_method}'" - ) + raise ValueError(f"de_method must be one of 'pydeseq2' or 'edger', not '{de_method}'") def plot_heatmap_with_dot_and_colorbar( self, diff --git a/tests/tools/test_milo.py b/tests/tools/test_milo.py index 992d9908..32f5924d 100644 --- a/tests/tools/test_milo.py +++ b/tests/tools/test_milo.py @@ -483,7 +483,9 @@ def _py_to_r(obj): from rpy2.robjects.conversion import localconverter if isinstance(obj, np.ndarray): - return numpy2ri.py2rpy(obj) + with localconverter(ro.default_converter + numpy2ri.converter): + r_obj = numpy2ri.py2rpy(obj) + return r_obj if isinstance(obj, pd.DataFrame): with localconverter(ro.default_converter + pandas2ri.converter): df = pandas2ri.py2rpy(obj) @@ -495,38 +497,6 @@ def _py_to_r(obj): return r_obj -# def _r_to_py(r_obj): -# """ -# Convert an R object back into a NumPy array or pandas DataFrame, as appropriate. -# """ -# import rpy2.robjects as ro -# from rpy2.robjects import numpy2ri, pandas2ri -# from rpy2.robjects.conversion import localconverter - -# # R matrix → NumPy array -# if isinstance(r_obj, ro.vectors.Matrix): -# with localconverter(ro.default_converter + numpy2ri.converter): -# return np.asarray(r_obj) - -# # R data.frame → pandas DataFrame -# if isinstance(r_obj, ro.vectors.DataFrame): -# with localconverter(ro.default_converter + pandas2ri.converter): -# return pandas2ri.rpy2py(r_obj) - -# # R vector types → NumPy arrays -# if isinstance(r_obj, ro.vectors.BoolVector): -# return np.asarray(r_obj) -# if isinstance(r_obj, ro.vectors.IntVector): -# return np.asarray(r_obj) -# if isinstance(r_obj, ro.vectors.FloatVector): -# return np.asarray(r_obj) -# if isinstance(r_obj, ro.vectors.StrVector): -# return np.asarray(r_obj) - -# # Otherwise (e.g. R NULL), return as‐is -# return r_obj - - def _group_nhoods_from_adjacency_r( nhs_r, nhood_adj_r, da_res_r, is_da_r, merge_discord_r, max_lfc_delta_r, overlap_r, subset_nhoods_r ): @@ -803,7 +773,7 @@ def test_annotate_cells_from_nhoods_various( from pertpy.tools._milo import Milo milo = Milo() - print(milo) + mdata = group_nhoods_mdata.copy() assert "SpatialFDR" in mdata["milo"].var.columns @@ -875,3 +845,185 @@ def test_annotate_cells_from_nhoods_various( too_few = counts < min_n_nhoods too_few = np.asarray(too_few).ravel() assert (col[too_few].isna()).all() + + +#### +# test find_nhood_group_markers + + +@pytest.fixture +def nhood_markers_mdata(milo): + # 1) Load pbmc3k and make a private copy + adata = sc.datasets.pbmc3k().copy() + + adata.layers["counts"] = adata.X.copy() # keep raw counts + sc.pp.normalize_total(adata, target_sum=1e4) # normalize + sc.pp.log1p(adata) # log transform + sc.pp.highly_variable_genes(adata, n_top_genes=2000) + sc.pp.pca(adata, n_comps=50) # PCA + sc.pp.neighbors(adata, n_neighbors=10, n_pcs=30) # build neighbors + sc.tl.louvain(adata, resolution=0.5) # Louvain clustering + sc.tl.umap(adata) + + # 2) Build neighborhoods + milo.make_nhoods(adata) + + # 3) Simulate an experimental condition + rng = np.random.default_rng(seed=42) + adata.obs["condition"] = rng.choice(["ConditionA", "ConditionB"], size=adata.n_obs, p=[0.5, 0.5]) + # bump one cluster to have DA + DA_cells = adata.obs["louvain"] == "1" + adata.obs.loc[DA_cells, "condition"] = rng.choice(["ConditionA", "ConditionB"], size=DA_cells.sum(), p=[0.2, 0.8]) + + # 4) Simulate replicates & build sample IDs + adata.obs["replicate"] = rng.choice(["R1", "R2", "R3"], size=adata.n_obs) + adata.obs["sample"] = adata.obs["replicate"] + "_" + adata.obs["condition"] + + # 5) Count & test DA neighborhoods + mdata = milo.count_nhoods(adata, sample_col="sample") + milo.da_nhoods(mdata, design="~condition", solver="pydeseq2") + + # 6) Overwrite SpatialFDR so we have ~10% “significant” at random + var = mdata["milo"].var + n = var.shape[0] + k = max(1, int(0.1 * n)) + fdrs = rng.random(n) + da_idx = rng.choice(n, size=k, replace=False) + fdrs[da_idx] = rng.random(k) * 0.1 + rng.shuffle(fdrs) + mdata["milo"].var["SpatialFDR"] = fdrs + + # 7) Build the neighborhood graph + milo.build_nhood_graph(mdata) + + milo.group_nhoods(mdata) + + # 8) Annotate cells from those nhoods + milo.annotate_cells_from_nhoods( + mdata, + nhood_group_obs="nhood_groups", # use the default + subset_nhoods=None, # annotate across all groups + min_n_nhoods=1, # default + mode="last_wins", # default + ) + + return mdata + + +@pytest.mark.parametrize( + "group_to_compare, baseline, expect_group_col, filter_method, de_method", + [ + ("1", "0", False, "scanpy", "pydeseq2"), # two‐level contrast: no “group” column + (None, None, True, "scanpy", "pydeseq2"), # one‐vs‐rest: should have “group” column + ("1", "0", False, "filterByExpr", "pydeseq2"), + (None, None, True, "filterByExpr", "pydeseq2"), + ("1", "0", False, "scran", "pydeseq2"), + (None, None, True, "scran", "pydeseq2"), + ("1", "0", False, "scanpy", "edger"), + (None, None, True, "scanpy", "edger"), + ("1", "0", False, "filterByExpr", "edger"), + (None, None, True, "filterByExpr", "edger"), + ("1", "0", False, "scran", "edger"), + (None, None, True, "scran", "edger"), + ], +) +def test_find_markers_returns_expected_structure( + nhood_markers_mdata, milo, group_to_compare, baseline, expect_group_col, filter_method, de_method +): + """Test that find_nhood_group_markers returns a properly shaped DataFrame + and that the expected columns are present or absent.""" + + mdata = nhood_markers_mdata.copy() + df = milo.find_nhood_group_markers( + mdata, + group_to_compare=group_to_compare, + baseline=baseline, + nhood_group_obs="nhood_groups", + sample_col="sample", + covariates=None, + layer="counts", + filter_method=filter_method, + de_method=de_method, + ) + # Basic sanity checks + assert isinstance(df, pd.DataFrame) + # Must have at least one row and one variable + assert df.shape[0] > 0 + # Check core columns + core_cols = {"variable", "log_fc", "p_value", "adj_p_value"} + assert core_cols.issubset(df.columns) + # “group” only appears in one‐vs‐rest branch + if expect_group_col: + assert "group" in df.columns + # Should see at least two distinct group labels + groups = set(df["group"].unique()) + assert len(groups) > 1 + else: + assert "group" not in df.columns + + +def test_find_markers_two_level_effect_sizes(nhood_markers_mdata, milo): + """In the two-level case, log_fc should not all be zero + and p-values should be between 0 and 1.""" + + mdata = nhood_markers_mdata.copy() + + rng = np.random.default_rng(seed=42) + mdata["rna"].obs["nhood_groups"] = pd.Categorical( + rng.choice(["ConditionA", "ConditionB", pd.NA], size=mdata["rna"].n_obs) + ) + + res = milo.find_nhood_group_markers( + mdata, + group_to_compare="ConditionB", + baseline="ConditionA", + nhood_group_obs="nhood_groups", + sample_col="sample", + covariates=None, + layer="counts", + ) + # Check that we got at least one positive and one negative log fold–change + assert (res["log_fc"] > 0).any() + assert (res["log_fc"] < 0).any() + # p-values and adjusted p-values should lie in [0,1] + # assert res["p_value"].notna().all() + res = res.query("p_value == p_value") + assert ((res["p_value"] >= 0) & (res["p_value"] <= 1)).all() + res = res.query("adj_p_value == adj_p_value") + assert ((res["adj_p_value"] >= 0) & (res["adj_p_value"] <= 1)).all() + + +def test_find_markers_invalid_args_raises(nhood_markers_mdata, milo): + """Check that missing or bogus contrast arguments raise a ValueError.""" + + mdata = nhood_markers_mdata.copy() + with pytest.raises(ValueError): + # baseline without group_to_compare + milo.find_nhood_group_markers( + mdata, + group_to_compare=None, + baseline="ConditionA", + nhood_group_obs="nhood_groups", + sample_col="sample", + layer="counts", + ) + with pytest.raises(ValueError): + # group_to_compare == baseline + milo.find_nhood_group_markers( + mdata, + group_to_compare="ConditionA", + baseline="ConditionA", + nhood_group_obs="nhood_groups", + sample_col="sample", + layer="counts", + ) + with pytest.raises(KeyError): + # non‐existent column name + milo.find_nhood_group_markers( + mdata, + group_to_compare="ConditionB", + baseline="ConditionA", + nhood_group_obs="not_a_column", + sample_col="sample", + layer="counts", + ) From 780f499ec9d5c3af3a1435f06ab8c14ecbfd2aed Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Thu, 12 Jun 2025 14:31:11 +0200 Subject: [PATCH 06/10] Update to nhood_gr in _nhood_labels_to_cells_last_wins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the old version, nhood_gr first dropped NA by all columns in the dataframe and then took unique values, without control of ordering by the user. This change let´s the user control the ordering of groups, and removes the problem as described, by using pd.Categorical. Reran tests, and it works. --- pertpy/tools/_milo.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index c3cbe5a8..90e97cab 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -1586,6 +1586,12 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ nhood_mat = mdata["rna"].obsm["nhoods"] da_res = mdata["milo"].var.copy() + ### update for categorical nhood_group_obs to control order of levels + # This turns the nhood_group_obs into a CategoricalDtype if it isn't already + col = nhood_group_obs + # if it isn’t already a CategoricalDtype, cast it + if not isinstance(da_res[col].dtype, pd.api.types.CategoricalDtype): + da_res[col] = da_res[col].astype("category") nhood_mat = AnnData(X=nhood_mat) nhood_mat.obs_names = mdata["rna"].obs_names @@ -1594,7 +1600,9 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ nhs_da_gr = da_res[nhood_group_obs].copy() nhs_da_gr.index = da_res.index.to_numpy() - nhood_gr = da_res.dropna()[nhood_group_obs].unique() + # We want to drop NAs from the nhood_group_obs column, not the whole DataFrame + # nhood_gr = da_res.dropna()[nhood_group_obs].unique() + nhood_gr = da_res[nhood_group_obs].cat.categories nhs = nhood_mat.copy() @@ -1786,8 +1794,6 @@ def _run_edger_contrasts( from rpy2.robjects import IntVector, StrVector, baseenv, numpy2ri, pandas2ri from rpy2.robjects.conversion import localconverter - print(pdata) - # 2) Build a pandas DataFrame for sample‐level covariates # 6) Single‐contrast vs one‐vs‐rest @@ -1822,13 +1828,10 @@ def _run_edger_contrasts( sample_obs[nhood_group_obs] = pd.Categorical( sample_obs[nhood_group_obs].values, categories=[baseline, group_to_compare] ) - print(sample_obs.shape) - print(count_mat.shape) with localconverter(ro.default_converter + pandas2ri.converter): robs = pandas2ri.py2rpy(sample_obs) design_r = rstats.model_matrix(rstats.as_formula(formula), robs) - print(design_r.nrow) # Fit the quasi‐likelihood model dge = edger.calcNormFactors(dge, method="TMM") From 5a303075bbbf28369524768643b37eea3cbdc881 Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Mon, 16 Jun 2025 09:43:23 +0200 Subject: [PATCH 07/10] Updated doc strings and common_plot_args in plot_nhood_annotation Updated doc strings to google format. Added common_plot_args to milo.plot_nhood_annotation. Added plot in ReadTheDocs for plot_nhood_annotation --- .../milo_nhood_annotation.png | Bin 0 -> 336759 bytes pertpy/tools/_milo.py | 584 ++++++++++++------ 2 files changed, 399 insertions(+), 185 deletions(-) create mode 100644 docs/_static/docstring_previews/milo_nhood_annotation.png diff --git a/docs/_static/docstring_previews/milo_nhood_annotation.png b/docs/_static/docstring_previews/milo_nhood_annotation.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1cdb6261783d8d2114ae9e8ba418644c1aafc8 GIT binary patch literal 336759 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 z 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%0DG0-)@EBDI#*O;-3->`;i-RIIxpiS=p8QDJ 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�{|4sX^vWG~r9mAo`tET#%uunhqT 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 diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 3336b599..90e97cab 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -416,11 +416,7 @@ def da_nhoods( raise with localconverter(ro.default_converter + pandas2ri.converter + numpy2ri.converter): res = base.as_data_frame( - edgeR.topTags( - edgeR.glmQLFTest(fit, contrast=mod_contrast), - sort_by="none", - n=np.inf, - ) + edgeR.topTags(edgeR.glmQLFTest(fit, contrast=mod_contrast), sort_by="none", n=np.inf) ) else: with localconverter(ro.default_converter + numpy2ri.converter + pandas2ri.converter): @@ -442,10 +438,7 @@ def da_nhoods( design_df_filtered = design_df.iloc[keep_smp].copy() design_df_filtered = design_df_filtered.astype( - dict.fromkeys( - design_df_filtered.select_dtypes(exclude=["number"]).columns, - "category", - ) + dict.fromkeys(design_df_filtered.select_dtypes(exclude=["number"]).columns, "category") ) design_clean = design if design.startswith("~") else f"~{design}" @@ -482,12 +475,7 @@ def da_nhoods( res = stat_res.results_df res = res.rename( - columns={ - "baseMean": "logCPM", - "log2FoldChange": "logFC", - "pvalue": "PValue", - "padj": "FDR", - } + columns={"baseMean": "logCPM", "log2FoldChange": "logFC", "pvalue": "PValue", "padj": "FDR"} ) res = res[["logCPM", "logFC", "PValue", "FDR"]] @@ -874,12 +862,7 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 ordered = nhood_adata.obs.sort_values("abs_logFC", na_position="first").index nhood_adata = nhood_adata[ordered] - vmax = np.max( - [ - nhood_adata.obs["graph_color"].max(), - abs(nhood_adata.obs["graph_color"].min()), - ] - ) + vmax = np.max([nhood_adata.obs["graph_color"].max(), abs(nhood_adata.obs["graph_color"].min())]) vmin = -vmax fig = sc.pl.embedding( @@ -907,80 +890,63 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 plt.show() return None - # In plot_nhood_annotation color_map, palette, and ax are not documented, and not part of common_plot_args - # Should I add them or will they be part of common_plot_args in the future? - @_doc_params(common_plot_args=doc_common_plot_args) - def plot_nhood_annotation( # pragma: no cover # noqa: D417 + from collections.abc import Sequence + from typing import Union + + def plot_nhood_annotation( # pragma: no cover self, mdata: MuData, *, - adata_key: str = "milo", - annotation_key: str | None = "nhood_annotation", + # ------------------------------------------------------------------- + # Styling / filtering parameters for logFC‐based coloring: alpha: float = 0.1, min_logFC: float = 0.0, min_size: int = 10, plot_edges: bool = False, - title: str = "DA log-Fold Change", + title: str = "DA log‐Fold Change", color_map: Colormap | str | None = None, palette: str | Sequence[str] | None = None, ax: Axes | None = None, return_fig: bool = False, + # ------------------------------------------------------------------- + # New arguments: + adata_key: str = "milo", + annotation_key: str | None = "nhood_annotation", + # ------------------------------------------------------------------- **kwargs, ) -> Figure | None: - """Visualize Milo differential-abundance results on the neighborhood graph. + """Visualize Milo differential‐abundance results on the abstracted neighborhood graph. - By default, neighborhoods are colored by filtered logFC (|logFC| ≥ `min_logFC` - and SpatialFDR ≤ `alpha`). If `annotation_key` is provided, this column from - `mdata[adata_key].obs` will be used instead for coloring. + By default (annotation_key=None), nodes are colored by filtered logFC (SpatialFDR ≤ alpha, + |logFC| ≥ min_logFC). If annotation_key is provided, instead draw node colors from + mdata[adata_key].obs[annotation_key]. Args: - mdata: A MuData object with: - - mdata["milo"]: Milo-neighborhood AnnData (transposed). - - mdata[adata_key]: AnnData containing annotation in `.obs`. - adata_key: Key for the AnnData within `mdata` that contains `.obs[annotation_key]`. - Defaults to "milo". - annotation_key: Name of the `.obs` column to use for coloring. If not None, - disables logFC-based coloring. Defaults to "nhood_annotation". - alpha: Significance threshold for SpatialFDR. Used only if `annotation_key` is None. - Defaults to 0.1. - min_logFC: Minimum absolute logFC to show. Used only if `annotation_key` is None. - Defaults to 0.0. - min_size: Scaling factor for node size. Actual size = `Nhood_size × min_size`. - Defaults to 10. - plot_edges: Whether to plot edges in the neighborhood overlap graph. - Defaults to False. - title: Title for the plot. Ignored if `annotation_key` is provided. - Defaults to "DA log-Fold Change". - color_map: Colormap to use for coloring. - palette: Name of Seaborn color palette for violinplots. - Defaults to pre-defined category colors for violinplots. - ax: Axes to plot on. - {common_plot_args} - **kwargs: Additional keyword arguments to pass directly to `scanpy.pl.embedding`. + mdata: MuData object containing at least: + • mdata["milo"] (the Milo‐neighborhood AnnData, transposed) + • mdata[adata_key] (the AnnData where your annotation lives) + alpha: Significance threshold for SpatialFDR (only used if annotation_key is None). + min_logFC: Minimum absolute logFC to display (only used if annotation_key is None). + min_size: Scaling factor: actual marker size = Nhood_size × min_size. + plot_edges: If True, draw edges of the neighborhood overlap graph. + title: Plot title (ignored if annotation_key is not None; you can override if you like). + color_map: Passed through to sc.pl.embedding for discrete palettes (optional). + palette: Passed through to sc.pl.embedding (optional). + ax: Matplotlib Axes to plot on (optional). + return_fig: If True, return the Figure object instead of calling plt.show(). + + adata_key: Key in mdata corresponding to the AnnData whose `.obs` has the annotation. + Default = "rna". + + annotation_key: If not None, the name of a column in mdata[adata_key].obs whose values + should be used to color the Milo neighborhood graph. If provided, + we ignore all logFC / FDR logic and simply color by that annotation. + Example: "nhood_annotation". If None, revert to the original logFC‐based coloring. + + **kwargs: Additional keyword arguments passed to sc.pl.embedding. Returns: - matplotlib.figure.Figure or None: The matplotlib Figure, if `return_fig` is True; - otherwise, displays the plot and returns None. - - Examples: - >>> import pertpy as pt - >>> import scanpy as sc - >>> adata = pt.dt.bhattacherjee() - >>> milo = pt.tl.Milo() - >>> mdata = milo.load(adata) - >>> sc.pp.neighbors(mdata["rna"]) - >>> sc.tl.umap(mdata["rna"]) - >>> milo.make_nhoods(mdata["rna"]) - >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") - >>> milo.da_nhoods(mdata, - >>> design='~label', - >>> model_contrasts='labelwithdraw_15d_Cocaine-labelwithdraw_48h_Cocaine') - >>> milo.build_nhood_graph(mdata) - >>> milo.group_nhoods(mdata) - >>> milo.plot_nhood_annotation(mdata, annotation_key="nhood_groups") - - Preview: - .. image:: /_static/docstring_previews/milo_nhood_annotation.png + If return_fig == True → returns the matplotlib Figure. Otherwise, shows the plot and returns None. """ # ------------------------------------------------------------------- # 1) Extract and copy the Milo neighborhood AnnData: @@ -1032,7 +998,6 @@ def plot_nhood_annotation( # pragma: no cover # noqa: D417 palette=palette, ax=ax, show=False, - return_fig=return_fig, **kwargs, ) @@ -1064,12 +1029,7 @@ def plot_nhood_annotation( # pragma: no cover # noqa: D417 nhood_adata = nhood_adata[ordered] # Determine symmetric color limits: - vmax = np.nanmax( - [ - nhood_adata.obs["graph_color"].max(), - -nhood_adata.obs["graph_color"].min(), - ] - ) + vmax = np.nanmax([nhood_adata.obs["graph_color"].max(), -nhood_adata.obs["graph_color"].min()]) vmin = -vmax # Finally, call scanpy to draw the embedding: @@ -1089,7 +1049,6 @@ def plot_nhood_annotation( # pragma: no cover # noqa: D417 palette=palette, ax=ax, show=False, - return_fig=return_fig, **kwargs, ) @@ -1277,12 +1236,7 @@ def plot_da_beeswarm( # pragma: no cover # noqa: D417 orient="h", alpha=0.5, ) - plt.legend( - loc="upper left", - title=f"< {int(alpha * 100)}% SpatialFDR", - bbox_to_anchor=(1, 1), - frameon=False, - ) + plt.legend(loc="upper left", title=f"< {int(alpha * 100)}% SpatialFDR", bbox_to_anchor=(1, 1), frameon=False) plt.axvline(x=0, ymin=0, ymax=1, color="black", linestyle="--") if return_fig: @@ -1372,30 +1326,26 @@ def _group_nhoods_from_adjacency( merge_discord: bool = False, overlap: int = 1, max_lfc_delta: float | None = None, - subset_nhoods: list | np.ndarray | None = None, + subset_nhoods=None, ) -> np.ndarray: - """Group neighborhoods using filtered adjacency and Louvain clustering. - - Filters the neighborhood adjacency matrix based on overlap, DA agreement, - and logFC similarity, then performs Louvain clustering on the resulting graph. - - Args: - adjacency: Sparse square matrix (shape: N × N) containing overlap counts between neighborhoods. - da_res: DataFrame of shape (N,), containing columns "SpatialFDR" and "logFC". - is_da: Boolean array of length N; True where a neighborhood is differentially abundant. - merge_discord: If False, remove edges between DA neighborhoods with opposite logFC signs. - Defaults to False. - overlap: Minimum overlap count required to retain an edge. Defaults to 1. - max_lfc_delta: If set, removes edges where the absolute difference in logFC exceeds this threshold. - Defaults to None (no filtering). - subset_nhoods: Optional subsetting of neighborhoods. Can be one of: - - Boolean mask of length N - - List/array of integer indices - - List/array of neighborhood names matching `da_res.index` + """Core neighborhood‐grouping logic (vectorized, no Python loops). + + Inputs: + - adjacency: scipy.sparse square matrix of shape (N, N), + storing neighborhood adjacency (overlap counts). + - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. + - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. + - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. + - overlap: integer threshold; zero edges with weight < overlap. + - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. + - subset_nhoods: None or one of: + • boolean mask (length N), + • list/array of integer indices, + • list/array of string names (matching da_res.index). Returns: - np.ndarray: Array of string cluster labels, of length equal to the number of selected neighborhoods. - These correspond to rows of `da_res` after subsetting. + - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), + giving a Louvain cluster label for each neighborhood (in the same order as da_res). """ # 1) Optional subsetting of neighborhoods --------------------------------------------------- # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. @@ -1486,6 +1436,9 @@ def _group_nhoods_from_adjacency( # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. + # Issue with dematrix after subsetting adjacency matrix: + # dematrix in sc._utils.get_igraph_from_adjacency does not convert to dense numpy matrix. + # Trying direct conversion to igraph: g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- @@ -1507,7 +1460,7 @@ def group_nhoods( max_lfc_delta: float | None = None, merge_discord: bool = False, subset_nhoods=None, - ) -> None: + ) -> pd.DataFrame: """Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. Parameters @@ -1530,10 +1483,10 @@ def group_nhoods( If provided, only cluster that subset of neighborhoods. Returns: - None: The function modifies `adata` in place by adding the column - `"nhood_groups"` to `adata.var`, containing the cluster labels for - each neighborhood. Neighborhoods not included in `subset_nhoods` are - assigned `pd.NA`. + ------- + pd.DataFrame + A copy of `adata.var`, with a new column "nhood_groups" of dtype string giving each + neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). Examples: @@ -1629,33 +1582,7 @@ def group_nhoods( adata.var["nhood_groups"] = out - def _nhood_labels_to_cells_last_wins( - self, - mdata: MuData, - nhood_group_obs: str = "nhood_groups", - subset_nhoods: list | np.ndarray | None = None, - ) -> None: - """Map neighborhood group labels back to single cells (last group wins). - - Assigns a neighborhood group label to each cell based on the neighborhoods - it belongs to. If a cell belongs to multiple neighborhoods with different - labels, the first non-missing label (by category order) is used. Operates - in-place on `mdata["rna"].obs["nhood_groups"]`. - - Args: - mdata: MuData object with: - - mdata["milo"]: contains `.var[nhood_group_obs]` and neighborhood indices. - - mdata["rna"]: must have `.obsm["nhoods"]` sparse binary matrix of shape (cells × neighborhoods). - nhood_group_obs: Column name in `mdata["milo"].var` holding the neighborhood group labels. - Must be categorical or convertible to categorical. Defaults to "nhood_groups". - subset_nhoods: Optional subset of neighborhood indices to consider. Can be: - - A boolean mask, - - A list/array of integer indices, - - A list/array of string IDs matching `mdata["milo"].var.index`. - - Returns: - None: The results are written to `mdata["rna"].obs["nhood_groups"]` in place. - """ + def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_groups", subset_nhoods=None): nhood_mat = mdata["rna"].obsm["nhoods"] da_res = mdata["milo"].var.copy() @@ -1720,52 +1647,17 @@ def _nhood_labels_to_cells_last_wins( mdata["rna"].obs["nhood_groups"] = pd.NA mdata["rna"].obs.loc[fake_meta.CellID.to_list(), "nhood_groups"] = fake_meta.Nhood_Group.to_numpy() - def _get_cells_in_nhoods( - self, - adata: AnnData, - nhood_ids: np.ndarray | list, - ) -> None: - """Compute number of neighborhood memberships per cell and store in `.obs`. - - For the selected neighborhoods, calculates how many of them each cell belongs to. - Stores the result in `adata.obs["in_nhoods"]`. - - Args: - adata: AnnData object with `.obsm["nhoods"]`, a binary matrix of shape (cells × neighborhoods). - nhood_ids: List or array of neighborhood indices to include in the count. - - Returns: - None: The result is stored in-place in `adata.obs["in_nhoods"]`. - """ - if not isinstance(nhood_ids, np.ndarray): - nhood_ids = np.asarray(nhood_ids, dtype=int) + def _get_cells_in_nhoods(self, adata, nhood_ids): + """Get cells in neighbourhoods of interest, store the number of neighbourhoods for each cell in adata.obs['in_nhoods'].""" in_nhoods = np.array(adata.obsm["nhoods"][:, nhood_ids.astype("int")].sum(1)) adata.obs["in_nhoods"] = in_nhoods def _nhood_labels_to_cells_exclude_overlaps( self, - mdata: MuData, + mdata, nhood_group_obs: str = "nhood_groups", min_n_nhoods: int = 3, - ) -> None: - """Assign cells to a dominant neighborhood group, excluding ambiguous overlaps. - - For each neighborhood group, compute how many neighborhoods each cell belongs to. - Then, assign each cell to the group with the most memberships, if that count exceeds - `min_n_nhoods`. All other cells are left unassigned (NaN). - - Args: - mdata: MuData object with: - - `mdata["milo"].var[nhood_group_obs]`: categorical group labels for neighborhoods. - - `mdata["rna"].obsm["nhoods"]`: binary matrix (cells × neighborhoods) indicating memberships. - nhood_group_obs: Name of the column in `mdata["milo"].var` containing group labels. - Defaults to "nhood_groups". - min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to - in order to be assigned. Defaults to 3. - - Returns: - None: Results are written in-place to `mdata["rna"].obs["nhood_groups"]`. - """ + ): groups = mdata["milo"].var[nhood_group_obs].dropna().unique() for g in groups: nhoods_oi = mdata["milo"].var_names[mdata["milo"].var[nhood_group_obs] == g] @@ -1777,8 +1669,7 @@ def _nhood_labels_to_cells_exclude_overlaps( mdata["rna"].obs["nhood_groups"] = mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]].idxmax(1) ## Keep only if cell is in at least min_n_nhoods nhoods of the same group mdata["rna"].obs.loc[ - ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), - "nhood_groups", + ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), "nhood_groups" ] = np.nan ### Remove the in_nhoods in nhood_groups columns mdata["rna"].obs["nhood_groups"] = ( @@ -1794,28 +1685,21 @@ def annotate_cells_from_nhoods( min_n_nhoods: int = 3, mode: Literal["last_wins", "exclude_overlaps"] = "last_wins", ) -> None: - """Assign neighborhood group labels to cells based on neighborhood membership. - - This function annotates cells in `mdata["rna"].obs` using group labels from - `mdata["milo"].var[nhood_group_obs]`. Supports two modes for resolving overlaps: - - "last_wins": Assign the last matching group label (default; mimics MiloR behavior). - - "exclude_overlaps": Assign only if the cell belongs to a minimum number of neighborhoods - from a single group. - - Args: - mdata: MuData object with: - - `mdata["milo"].var[nhood_group_obs]`: categorical group labels. - - `mdata["rna"].obsm["nhoods"]`: binary matrix of cell–neighborhood memberships. - nhood_group_obs: Column name in `mdata["milo"].var` with group labels. Defaults to "nhood_groups". - subset_nhoods: Optional list of neighborhood IDs to restrict annotation. If None, all neighborhoods are used. - min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to in order to be assigned - (only used in mode `"exclude_overlaps"`). Defaults to 3. - mode: Strategy for resolving overlapping group assignments. One of: - - `"last_wins"`: Assign label from last matching neighborhood. - - `"exclude_overlaps"`: Assign only if group dominates cell’s memberships. + """Annotate cells with neighborhood group labels. + + Parameters: + ----------- + mdata: MuData object with 'milo' modality. + nhood_group_obs: Column in `mdata["milo"].var` to use for neighborhood group labels. + subset_nhoods: List of neighborhood IDs to consider. If None, all neighborhoods are used. + min_n_nhoods: Minimum number of neighborhoods a cell must belong to in order to be annotated. Used for mode "exclude_overlaps". + mode: Mode for annotation. Options are: + - "last_wins": Last neighborhood label wins, adapted from miloR. + - "exclude_overlaps": Exclude overlaps, keeping only the most representative cells within groups. Returns: - Updates `mdata["rna"].obs["nhood_groups"]` with the assigned labels in place. + -------- + None: Modifies `mdata["rna"].obs` in place, adding a column `nhood_groups` with the assigned labels. Examples: >>> import pertpy as pt @@ -1894,37 +1778,13 @@ def _run_edger_contrasts( baseline: str | None = None, subset_samples: list[str] | None = None, ) -> pd.DataFrame: - """Run edgeR QLF tests on pseudobulk data using specified contrasts. + """Run edgeR QLF tests on a pseudobulk AnnData. - Performs differential expression analysis using edgeR's quasi-likelihood - F-tests on pseudobulked expression data. Supports either a user-specified - two-level contrast (`baseline` vs `group_to_compare`), or one-vs-rest testing - across all groups in `pdata.obs[nhood_group_obs]`. + If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. + Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. - Args: - pdata: AnnData object with pseudobulked expression data in `.X` and - sample-level annotations in `.obs`. - nhood_group_obs: Name of the `.obs` column used to define group membership for contrast. - formula: R-style design formula (e.g., `"~ group"`). Used to generate design matrices in edgeR. - group_to_compare: Name of the group to compare (e.g., `"treated"`). - If provided along with `baseline`, a two-group test is run. - baseline: Reference group (e.g., `"control"`) for the two-group contrast. - subset_samples: Optional list of sample names to subset `pdata` before analysis. - - Returns: - pd.DataFrame: Differential expression results with columns: - - `"variable"`: gene/feature name - - `"log_fc"`: log-fold change estimate - - `"p_value"`: raw p-value - - `"adj_p_value"`: multiple-testing corrected p-value - - `"group"` (optional): group name (only present in one-vs-rest mode) - - Raises: - ValueError: If contrast groups are not present in the data or input is malformed. - - Example: - >>> de_df = milo._run_edger_contrasts(pdata, "condition", formula="~ condition", - >>> group_to_compare="treated", baseline="control") + Returns a pandas DataFrame with columns: + ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). """ if not _is_counts(pdata.X): raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") @@ -1966,8 +1826,7 @@ def _run_edger_contrasts( if group_to_compare is not None and baseline is not None: # If a specific two‐level contrast was given, subset to those samples only sample_obs[nhood_group_obs] = pd.Categorical( - sample_obs[nhood_group_obs].values, - categories=[baseline, group_to_compare], + sample_obs[nhood_group_obs].values, categories=[baseline, group_to_compare] ) with localconverter(ro.default_converter + pandas2ri.converter): @@ -2038,13 +1897,7 @@ def _run_edger_contrasts( with localconverter(ro.default_converter + pandas2ri.converter): top_df_sub = pandas2ri.rpy2py(top_sub) - top_df_sub = top_df_sub.rename( - columns={ - "FDR": "adj_p_value", - "PValue": "p_value", - "logFC": "log_fc", - } - ) + top_df_sub = top_df_sub.rename(columns={"FDR": "adj_p_value", "PValue": "p_value", "logFC": "log_fc"}) top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) top_df_sub["group"] = grp @@ -2065,47 +1918,45 @@ def _run_pydeseq2_contrasts( alpha: float = 0.05, quiet: bool = True, ) -> pd.DataFrame: - """Run PyDESeq2 differential testing on pseudobulked AnnData using a design formula. + """Run PyDESeq2 on a pseudobulk AnnData (`pdata`) with a given neighborhood grouping, using exactly the design `formula` you supply. - Supports either a two-level contrast (`group_to_compare` vs `baseline`) or one-vs-rest - comparisons for all levels of a categorical column in `.obs`. Results are returned - as a tidy `DataFrame` compatible with downstream analysis. + Parameters + ---------- + pdata : AnnData + Pseudobulk AnnData, where .obs[nhood_group_obs] is a categorical allowing + you to compare levels. - Args: - pdata: Pseudobulk `AnnData` object with expression matrix in `.X` and - covariates in `.obs`, including `nhood_group_obs`. - nhood_group_obs: Name of the `.obs` column to use for contrast groups. - formula: R-style design formula (e.g., `"~ batch + group"`), passed directly to PyDESeq2. - group_to_compare: Name of the group to test against `baseline`. If None, - one-vs-rest mode is triggered. - baseline: Name of the baseline group for contrast. Must be specified if `group_to_compare` is given. - alpha: FDR threshold passed to PyDESeq2's `DeseqStats`. Defaults to 0.05. - quiet: If True, suppresses progress messages from PyDESeq2. Defaults to True. + nhood_group_obs : str + The column name in pdata.obs that holds the neighborhood groups. + + formula : str + An R‐style design formula, e.g. "~ batch + Nhood_Group". Must include + `nhood_group_obs` as one of the terms. This is used verbatim for both the + single‐contrast and one‐vs‐rest calls. + + group_to_compare : Optional[str] + If non‐None (and `baseline` is also non‐None), run only the single contrast + [nhood_group_obs, group_to_compare, baseline] with design = `formula`. + + baseline : Optional[str] + If non‐None (and `group_to_compare` is non‐None), run only that one contrast. + If either is None, the function does a one‐vs‐rest loop over all levels of + pdata.obs[nhood_group_obs]. + + alpha : float, default=0.05 + Significance threshold passed to PyrDESeq2’s `DeseqStats`. + + quiet : bool, default=True + Whether to suppress PyDESeq2’s “DESeq2()” progress messages. Returns: - pd.DataFrame: If `group_to_compare` and `baseline` are specified, returns a - single contrast result with columns: - - `"variable"`: feature name - - `"log_fc"`: log2 fold change - - `"p_value"`: raw p-value - - `"adj_p_value"`: FDR-corrected p-value - - If no contrast is specified, performs one-vs-rest for each group and returns - a concatenated DataFrame with the same columns plus: - - `"group"`: the group tested against all others - - Raises: - ImportError: If `pydeseq2` is not installed. - ValueError: If only one of `group_to_compare` or `baseline` is provided. - - Example: - >>> de_df = milo._run_pydeseq2_contrasts( - ... pdata, - ... nhood_group_obs="condition", - ... formula="~ condition", - ... group_to_compare="treated", - ... baseline="control", - ... ) + ------- + pd.DataFrame + If `group_to_compare` and `baseline` are provided: a DataFrame with columns + ["variable","log_fc","p_value","adj_p_value"], sorted by p_value. + + Otherwise (one‐vs‐rest): a concatenated DataFrame with those columns plus + a “group” column indicating which level was tested vs “rest.” """ if find_spec("pydeseq2") is None: raise ImportError("pydeseq2 is required but not installed. Install with: pip install pydeseq2") @@ -2197,32 +2048,8 @@ def _run_pydeseq2_contrasts( final_df = pd.concat(all_results, ignore_index=True) return final_df - def _filter_by_expr_edger( - self, - pdata: AnnData, - formula: str, - **kwargs, - ) -> None: - """Filter low-expressed genes from a pseudobulk AnnData object using edgeR. - - This function uses `edgeR::filterByExpr()` via rpy2 to identify and retain - genes with sufficient expression for differential testing, based on the - provided design formula and expression thresholds. - - The filtering is performed in-place by subsetting `pdata.var`. - - Args: - pdata: Pseudobulk `AnnData` object with raw counts in `.X` and - covariates in `.obs`. - formula: R-style design formula (e.g., `"~ condition + batch"`), used to - compute the design matrix in edgeR. - **kwargs: Additional keyword arguments passed to `edgeR::filterByExpr()`. - Examples include `min.count`, `min.total.count`, etc. - - Returns: - None: The function modifies `pdata` in place by subsetting `pdata.var` - to include only retained genes. - """ + def _filter_by_expr_edger(self, pdata, formula, **kwargs): + """Filter genes in `pdata` based on expression criteria using edgeR.""" edger, _, rstats, rbase = self._setup_rpy2() import rpy2.robjects as ro from rpy2.robjects import numpy2ri, pandas2ri @@ -2241,31 +2068,7 @@ def _filter_by_expr_edger( pdata._inplace_subset_var(keep) - def _filter_highly_variable_scanpy( - self, - pdata: AnnData, - n_top_genes: int = 7500, - target_sum: float = 1e6, - **kwargs, - ) -> None: - """Filter highly variable genes from a pseudobulk AnnData using Scanpy. - - Normalizes and log-transforms raw count data if needed, then selects the - top `n_top_genes` most variable genes using `scanpy.pp.highly_variable_genes`. - Results are stored in-place by subsetting `pdata.var`. - - Args: - pdata: AnnData object with raw or normalized pseudobulk expression in `.X`. - n_top_genes: Number of top variable genes to retain. Defaults to 7500. - target_sum: Target total count for normalization (used only if `.X` is raw counts). - Defaults to 1e6. - **kwargs: Additional keyword arguments passed to `scanpy.pp.highly_variable_genes()`. - - Returns: - None: The function modifies `pdata` in place: - - Adds normalized expression to `pdata.layers["normalized"]` - - Filters `.var` to include only the top `n_top_genes` genes - """ + def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6, **kwargs): if _is_counts(pdata.X): pdata.layers["normalized"] = pdata.X.copy() sc.pp.normalize_total( @@ -2279,29 +2082,7 @@ def _filter_highly_variable_scanpy( sc.pp.highly_variable_genes(pdata, layer="normalized", n_top_genes=n_top_genes, subset=True, **kwargs) - def _filter_highly_variable_scran( - self, - pdata: AnnData, - n_top_genes: int, - ) -> None: - """Filter highly variable genes using R's scran and scuttle packages. - - If `pdata.X` contains raw counts, normalization is performed using - `logNormCounts()` from `scuttle`. Otherwise, the matrix is assumed - to be already log-normalized. - - The top `n_top_genes` most variable genes are selected using - `scran.modelGeneVar()` and `scran.getTopHVGs()` and used to subset - `pdata.var` in place. - - Args: - pdata: AnnData object containing pseudobulk expression matrix. - n_top_genes: Number of top highly variable genes to retain. - - Returns: - None: The function modifies `pdata` in place by subsetting `.var` - to contain only the selected HVGs. - """ + def _filter_highly_variable_scran(self, pdata, n_top_genes): scran = self._try_import_bioc_library("scran") scuttle = self._try_import_bioc_library("scuttle") singlecellexperiment = self._try_import_bioc_library("SingleCellExperiment") @@ -2354,49 +2135,57 @@ def find_nhood_group_markers( alpha: float = 0.05, use_eb: bool = False, **kwargs, - ) -> pd.DataFrame: - """Perform differential expression analysis on neighborhood groups in a MuData or AnnData object. - - This function performs pseudobulk aggregation over neighborhood groupings and tests for differential - expression (DE) between groups using either `pydeseq2` or `edgeR`. - - The MuData must contain a modality (default `"rna"`) used for pseudobulk aggregation. - Group labels must be stored in `nhood_group_obs`, and sample labels in `sample_col`. - - If both `group_to_compare` and `baseline` are provided, a specific two-group contrast is tested. - Otherwise, one-vs-rest DE is performed for each level in `nhood_group_obs`. - - Notes: - - All NAs in `nhood_group_obs` are removed before pseudobulk aggregation. - - If annotating neighborhood groups manually, you can introduce NAs beforehand to exclude neighborhoods. + ): + """Perform differential expression analysis on neighborhood groups in a MuData object. - Args: - data: A `MuData` or `AnnData` object. - group_to_compare: The group to compare (e.g. case) in a specific contrast. Must be in `nhood_group_obs`. - baseline: The baseline group (e.g. control). Must be in `nhood_group_obs` if `group_to_compare` is given. - nhood_group_obs: Column in `.obs` with neighborhood group labels. Must be categorical or string-typed. - sample_col: Column in `.obs` specifying sample identifiers. - covariates: Optional list of covariates to include in the DE model formula. - key: Name of modality in `MuData` used for pseudobulk aggregation (default `"rna"`). - pseudobulk_function: Aggregation function used for pseudobulk (either `"sum"` or `"mean"`). - layer: Optional layer to use for aggregation. Defaults to `X` if not provided. - target_sum: Used for Scanpy-based normalization when filtering (default: `1e6`). - n_top_genes: Number of highly variable genes to retain (if filtering is applied). - filter_method: How to filter genes before DE analysis. One of `"scanpy"`, `"scran"`, or `"filterByExpr"`. - var_names: Optional list of variable (gene) names to restrict analysis to. Overrides filtering if provided. - de_method: Differential expression method: `"pydeseq2"` (default) or `"edger"`. - quiet: Whether to suppress console output from PyDESeq2 (default: True). - alpha: Significance threshold passed to DE test (used in PyDESeq2). - use_eb: If `True`, applies empirical Bayes shrinkage (not implemented yet, reserved for future limma-style methods). - **kwargs: Additional arguments passed to filtering or DE methods (e.g., `min_expr`, `min_total` for edgeR filtering). + The MuData object must contain a modality with the name `key`, which is used for pseudobulk aggregation. + The column `nhood_group_obs` in `mdata[key]` must contain the neighborhood group labels, and `sample_col` must contain the sample labels. + Neighborhood group labels can be assigned to the single-cell data using ´milo.group_nhoods(...)`, or manually set in `mdata[key].obs[nhood_group_obs]`. + Neighborhood group labels must be strings or categorical values and are used for pseudobulk aggregation. + If both `group_to_compare` and `baseline` are given, runs exactly that contrast. Otherwise, runs one‐vs‐rest for every level of `nhood_group_obs`. + All NAs in mdata[key].obs[nhood_group_obs] are filtered out before running the analysis. + Therefore, if annotating nhood_group_obs manually, introducing NAs before Milo().group_nhoods(...) is can exclude unwanted neighborhoods from the analysis. - Returns: - pd.DataFrame: DE results with columns: - - "variable": Gene/feature name - - "log_fc": log2 fold change - - "p_value": Unadjusted p-value - - "adj_p_value": Multiple testing-corrected p-value - - "group": (only for one-vs-rest) the group being compared vs rest + Parameters + ---------- + mdata : MuData + A MuData object containing the data. Must have a modality with the name `key`. + group_to_compare : Optional[str] + If provided, runs a single contrast comparing this group to `baseline`. + baseline : Optional[str] + The reference group for the contrast. Must be provided if `group_to_compare` is provided. + nhood_group_obs : str, default="nhood_groups" + The name of the column in `adata.obs` that contains the neighborhood group labels. + sample_col : str, default="sample" + The name of the column in `adata.obs` that contains the sample labels. + covariates : Collection[str] | None, default=None + A collection of additional covariates to include in the design formula. + If None, no additional covariates are used. + key : str, default="rna" + The key in `mdata` that corresponds to the modality to be used for pseudobulk aggregation. + pseudobulk_function : str, default="sum" + The function to use for pseudobulk aggregation. Can be "sum" or "mean". + layer : str | None, default=None + If provided, the layer to use for pseudobulk aggregation. If None, uses the default layer. + target_sum : float, default=1e6 + The target sum for normalization when using the "scanpy" filter method. + n_top_genes : int, default=7500 + The number of top variable genes to retain after filtering. Only used if `filter_method` is `scanpy` `scran`. + filter_method : str | None, default="scanpy" + The method to use for filtering highly variable genes. Can be "scanpy", "scran", or "filterByExpr". + If None, no filtering is applied. + var_names : Collection[str] | None, default=None + A collection of variable names to restrict the analysis to. If None, all variables are used. + de_method : Literal["pydeseq2", "statsmodels", "edgeR", "limma"], default="pydeseq2" + The method to use for differential expression analysis. Can be "pydeseq2", "statsmodels", "edgeR", or "limma". + quiet : bool, default=True + If True, suppresses output messages from pydeseq2. + alpha : float, default=0.05 + The significance threshold for differential expression analysis in pydeseq2. + use_eb : bool, default=False + If True, applies empirical Bayes moderation to the results in statsmodels. Not for serious use, but a starting point for limma-like differential testing in pure Python. + **kwargs : dict + Additional keyword arguments passed to the filtering methods or differential expression methods. Examples: >>> import pertpy as pt @@ -2736,10 +2525,7 @@ def plot_heatmap_with_dot_and_colorbar( smap.set_array([]) cbar = fig.colorbar( - smap, - cax=ax_cbar, - orientation="vertical", - ticks=np.linspace(vmin, vmax, num=cbar_tick_count), + smap, cax=ax_cbar, orientation="vertical", ticks=np.linspace(vmin, vmax, num=cbar_tick_count) ) cbar.ax.tick_params(labelsize=8, length=4, width=1) cbar.ax.set_title("Mean\nExpr.", fontsize=8, pad=6) From c8bfd0a87da102d560c372565d79076c5054241b Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Mon, 16 Jun 2025 15:02:54 +0200 Subject: [PATCH 09/10] doc_strings update, plot_nhood_annotation common_doc_params --- pertpy/tools/_milo.py | 595 +++++++++++++++++++++++++++--------------- 1 file changed, 388 insertions(+), 207 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 90e97cab..eb709f93 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -893,60 +893,80 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 from collections.abc import Sequence from typing import Union - def plot_nhood_annotation( # pragma: no cover + # In plot_nhood_annotation color_map, palette, and ax are not documented, and not part of common_plot_args + # Should I add them or will they be part of common_plot_args in the future? + @_doc_params(common_plot_args=doc_common_plot_args) + def plot_nhood_annotation( # pragma: no cover # noqa: D417 self, mdata: MuData, *, - # ------------------------------------------------------------------- - # Styling / filtering parameters for logFC‐based coloring: + adata_key: str = "milo", + annotation_key: str | None = "nhood_annotation", alpha: float = 0.1, min_logFC: float = 0.0, min_size: int = 10, plot_edges: bool = False, - title: str = "DA log‐Fold Change", + title: str = "DA log-Fold Change", color_map: Colormap | str | None = None, palette: str | Sequence[str] | None = None, ax: Axes | None = None, return_fig: bool = False, - # ------------------------------------------------------------------- - # New arguments: - adata_key: str = "milo", - annotation_key: str | None = "nhood_annotation", - # ------------------------------------------------------------------- **kwargs, ) -> Figure | None: - """Visualize Milo differential‐abundance results on the abstracted neighborhood graph. + """Visualize Milo differential-abundance results on the neighborhood graph. - By default (annotation_key=None), nodes are colored by filtered logFC (SpatialFDR ≤ alpha, - |logFC| ≥ min_logFC). If annotation_key is provided, instead draw node colors from - mdata[adata_key].obs[annotation_key]. + By default, neighborhoods are colored by filtered logFC (|logFC| ≥ `min_logFC` + and SpatialFDR ≤ `alpha`). If `annotation_key` is provided, this column from + `mdata[adata_key].obs` will be used instead for coloring. Args: - mdata: MuData object containing at least: - • mdata["milo"] (the Milo‐neighborhood AnnData, transposed) - • mdata[adata_key] (the AnnData where your annotation lives) - alpha: Significance threshold for SpatialFDR (only used if annotation_key is None). - min_logFC: Minimum absolute logFC to display (only used if annotation_key is None). - min_size: Scaling factor: actual marker size = Nhood_size × min_size. - plot_edges: If True, draw edges of the neighborhood overlap graph. - title: Plot title (ignored if annotation_key is not None; you can override if you like). - color_map: Passed through to sc.pl.embedding for discrete palettes (optional). - palette: Passed through to sc.pl.embedding (optional). - ax: Matplotlib Axes to plot on (optional). - return_fig: If True, return the Figure object instead of calling plt.show(). - - adata_key: Key in mdata corresponding to the AnnData whose `.obs` has the annotation. - Default = "rna". - - annotation_key: If not None, the name of a column in mdata[adata_key].obs whose values - should be used to color the Milo neighborhood graph. If provided, - we ignore all logFC / FDR logic and simply color by that annotation. - Example: "nhood_annotation". If None, revert to the original logFC‐based coloring. - - **kwargs: Additional keyword arguments passed to sc.pl.embedding. + mdata: A MuData object with: + - mdata["milo"]: Milo-neighborhood AnnData (transposed). + - mdata[adata_key]: AnnData containing annotation in `.obs`. + adata_key: Key for the AnnData within `mdata` that contains `.obs[annotation_key]`. + Defaults to "milo". + annotation_key: Name of the `.obs` column to use for coloring. If not None, + disables logFC-based coloring. Defaults to "nhood_annotation". + alpha: Significance threshold for SpatialFDR. Used only if `annotation_key` is None. + Defaults to 0.1. + min_logFC: Minimum absolute logFC to show. Used only if `annotation_key` is None. + Defaults to 0.0. + min_size: Scaling factor for node size. Actual size = `Nhood_size × min_size`. + Defaults to 10. + plot_edges: Whether to plot edges in the neighborhood overlap graph. + Defaults to False. + title: Title for the plot. Ignored if `annotation_key` is provided. + Defaults to "DA log-Fold Change". + color_map: Colormap to use for coloring. + palette: Name of Seaborn color palette for violinplots. + Defaults to pre-defined category colors for violinplots. + ax: Axes to plot on. + {common_plot_args} + **kwargs: Additional keyword arguments to pass directly to `scanpy.pl.embedding`. Returns: - If return_fig == True → returns the matplotlib Figure. Otherwise, shows the plot and returns None. + matplotlib.figure.Figure or None: The matplotlib Figure, if `return_fig` is True; + otherwise, displays the plot and returns None. + + Examples: + >>> import pertpy as pt + >>> import scanpy as sc + >>> adata = pt.dt.bhattacherjee() + >>> milo = pt.tl.Milo() + >>> mdata = milo.load(adata) + >>> sc.pp.neighbors(mdata["rna"]) + >>> sc.tl.umap(mdata["rna"]) + >>> milo.make_nhoods(mdata["rna"]) + >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") + >>> milo.da_nhoods(mdata, + >>> design='~label', + >>> model_contrasts='labelwithdraw_15d_Cocaine-labelwithdraw_48h_Cocaine') + >>> milo.build_nhood_graph(mdata) + >>> milo.group_nhoods(mdata) + >>> milo.plot_nhood_annotation(mdata, annotation_key="nhood_groups") + + Preview: + .. image:: /_static/docstring_previews/milo_nhood_annotation.png """ # ------------------------------------------------------------------- # 1) Extract and copy the Milo neighborhood AnnData: @@ -1326,26 +1346,30 @@ def _group_nhoods_from_adjacency( merge_discord: bool = False, overlap: int = 1, max_lfc_delta: float | None = None, - subset_nhoods=None, + subset_nhoods: list | np.ndarray | None = None, ) -> np.ndarray: - """Core neighborhood‐grouping logic (vectorized, no Python loops). - - Inputs: - - adjacency: scipy.sparse square matrix of shape (N, N), - storing neighborhood adjacency (overlap counts). - - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. - - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. - - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. - - overlap: integer threshold; zero edges with weight < overlap. - - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. - - subset_nhoods: None or one of: - • boolean mask (length N), - • list/array of integer indices, - • list/array of string names (matching da_res.index). + """Group neighborhoods using filtered adjacency and Louvain clustering. + + Filters the neighborhood adjacency matrix based on overlap, DA agreement, + and logFC similarity, then performs Louvain clustering on the resulting graph. + + Args: + adjacency: Sparse square matrix (shape: N × N) containing overlap counts between neighborhoods. + da_res: DataFrame of shape (N,), containing columns "SpatialFDR" and "logFC". + is_da: Boolean array of length N; True where a neighborhood is differentially abundant. + merge_discord: If False, remove edges between DA neighborhoods with opposite logFC signs. + Defaults to False. + overlap: Minimum overlap count required to retain an edge. Defaults to 1. + max_lfc_delta: If set, removes edges where the absolute difference in logFC exceeds this threshold. + Defaults to None (no filtering). + subset_nhoods: Optional subsetting of neighborhoods. Can be one of: + - Boolean mask of length N + - List/array of integer indices + - List/array of neighborhood names matching `da_res.index` Returns: - - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), - giving a Louvain cluster label for each neighborhood (in the same order as da_res). + np.ndarray: Array of string cluster labels, of length equal to the number of selected neighborhoods. + These correspond to rows of `da_res` after subsetting. """ # 1) Optional subsetting of neighborhoods --------------------------------------------------- # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. @@ -1459,38 +1483,39 @@ def group_nhoods( overlap: int = 1, max_lfc_delta: float | None = None, merge_discord: bool = False, - subset_nhoods=None, - ) -> pd.DataFrame: - """Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. + subset_nhoods: (pd.Series | np.ndarray | list[int] | list[str] | None) = None, + ) -> None: + """Cluster Milo neighborhoods into groups (Louvain) and annotate `adata.var`. - Parameters - ---------- - adata : AnnData - Must contain: - - `adata.var` with columns "SpatialFDR" (float) and "logFC" (float) - - `adata.varp["nhood_connectivities"]` as an (N×N) sparse adjacency matrix - da_res : pd.DataFrame, optional - If provided, must match `adata.var`. Otherwise, `adata.var` is used directly. - da_fdr : float, default=0.1 - Neighborhoods with `SpatialFDR < da_fdr` are called “DA.” - overlap : int, default=1 - Drop any adjacency entry (edge) with weight < overlap. - max_lfc_delta : float or None, default=None - If not None, drop edges where |lfc_i - lfc_j| > max_lfc_delta. - merge_discord : bool, default=False - If False, drop edges between DA neighborhoods whose logFC signs disagree. - subset_nhoods : None or boolean mask / list of indices / list of names - If provided, only cluster that subset of neighborhoods. + A Python re-implementation of MiloR’s `groupNhoods()`. Given an AnnData (or a modality + within a MuData) containing precomputed neighborhood connectivity and differential + abundance results, compute connected components of DA neighborhoods (with optional + filters) and write back a categorical `"nhood_groups"` column in `adata.var`. - Returns: - ------- - pd.DataFrame - A copy of `adata.var`, with a new column "nhood_groups" of dtype string giving each - neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). + Args: + data: AnnData or MuData object. If MuData, `key` selects the modality to use. + key: Modality name within `data` when using a MuData. Defaults to "milo". + da_res: DataFrame of neighborhood‐level results with index matching + `adata.var.index` and columns "SpatialFDR" and "logFC". If None, uses `adata.var`. + da_fdr: Threshold for SpatialFDR below which neighborhoods are considered + differentially abundant and included in the clustering. Defaults to 0.1. + overlap: Minimum adjacency weight to retain an edge; edges with weight below + this value are dropped. Defaults to 1. + max_lfc_delta: Maximum allowed absolute difference in logFC between two + neighborhoods; edges exceeding this value are dropped. Defaults to None. + merge_discord: If False, edges between two DA neighborhoods whose logFC + signs disagree are dropped. Defaults to False. + subset_nhoods: Boolean mask, list/array of integer indices, or list of + neighborhood ID strings to restrict clustering. Defaults to None. + Returns: + Updates `adata.var["nhood_groups"]` in place with each neighborhood’s + Louvain group label. Neighborhoods not included in `subset_nhoods` + will have `pd.NA` in that column. Examples: - >>> import pertpy as pt + >>> import perturbpy as pt + >>> import scanpy as sc >>> adata = pt.dt.bhattacherjee() >>> milo = pt.tl.Milo() >>> mdata = milo.load(adata) @@ -1582,7 +1607,33 @@ def group_nhoods( adata.var["nhood_groups"] = out - def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_groups", subset_nhoods=None): + def _nhood_labels_to_cells_last_wins( + self, + mdata: MuData, + nhood_group_obs: str = "nhood_groups", + subset_nhoods: list | np.ndarray | None = None, + ) -> None: + """Map neighborhood group labels back to single cells (last group wins). + + Assigns a neighborhood group label to each cell based on the neighborhoods + it belongs to. If a cell belongs to multiple neighborhoods with different + labels, the first non-missing label (by category order) is used. Operates + in-place on `mdata["rna"].obs["nhood_groups"]`. + + Args: + mdata: MuData object with: + - mdata["milo"]: contains `.var[nhood_group_obs]` and neighborhood indices. + - mdata["rna"]: must have `.obsm["nhoods"]` sparse binary matrix of shape (cells × neighborhoods). + nhood_group_obs: Column name in `mdata["milo"].var` holding the neighborhood group labels. + Must be categorical or convertible to categorical. Defaults to "nhood_groups". + subset_nhoods: Optional subset of neighborhood indices to consider. Can be: + - A boolean mask, + - A list/array of integer indices, + - A list/array of string IDs matching `mdata["milo"].var.index`. + + Returns: + None: The results are written to `mdata["rna"].obs["nhood_groups"]` in place. + """ nhood_mat = mdata["rna"].obsm["nhoods"] da_res = mdata["milo"].var.copy() @@ -1647,17 +1698,52 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ mdata["rna"].obs["nhood_groups"] = pd.NA mdata["rna"].obs.loc[fake_meta.CellID.to_list(), "nhood_groups"] = fake_meta.Nhood_Group.to_numpy() - def _get_cells_in_nhoods(self, adata, nhood_ids): - """Get cells in neighbourhoods of interest, store the number of neighbourhoods for each cell in adata.obs['in_nhoods'].""" - in_nhoods = np.array(adata.obsm["nhoods"][:, nhood_ids.astype("int")].sum(1)) + def _get_cells_in_nhoods( + self, + adata: AnnData, + nhood_ids: np.ndarray | list, + ) -> None: + """Compute number of neighborhood memberships per cell and store in `.obs`. + + For the selected neighborhoods, calculates how many of them each cell belongs to. + Stores the result in `adata.obs["in_nhoods"]`. + + Args: + adata: AnnData object with `.obsm["nhoods"]`, a binary matrix of shape (cells × neighborhoods). + nhood_ids: List or array of neighborhood indices to include in the count. + + Returns: + None: The result is stored in-place in `adata.obs["in_nhoods"]`. + """ + if not isinstance(nhood_ids, np.ndarray): + nhood_ids = np.asarray(nhood_ids, dtype=int) + in_nhoods = np.array(adata.obsm["nhoods"][:, nhood_ids].sum(1)) adata.obs["in_nhoods"] = in_nhoods def _nhood_labels_to_cells_exclude_overlaps( self, - mdata, + mdata: MuData, nhood_group_obs: str = "nhood_groups", min_n_nhoods: int = 3, - ): + ) -> None: + """Assign cells to a dominant neighborhood group, excluding ambiguous overlaps. + + For each neighborhood group, compute how many neighborhoods each cell belongs to. + Then, assign each cell to the group with the most memberships, if that count exceeds + `min_n_nhoods`. All other cells are left unassigned (NaN). + + Args: + mdata: MuData object with: + - `mdata["milo"].var[nhood_group_obs]`: categorical group labels for neighborhoods. + - `mdata["rna"].obsm["nhoods"]`: binary matrix (cells × neighborhoods) indicating memberships. + nhood_group_obs: Name of the column in `mdata["milo"].var` containing group labels. + Defaults to "nhood_groups". + min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to + in order to be assigned. Defaults to 3. + + Returns: + None: Results are written in-place to `mdata["rna"].obs["nhood_groups"]`. + """ groups = mdata["milo"].var[nhood_group_obs].dropna().unique() for g in groups: nhoods_oi = mdata["milo"].var_names[mdata["milo"].var[nhood_group_obs] == g] @@ -1685,21 +1771,28 @@ def annotate_cells_from_nhoods( min_n_nhoods: int = 3, mode: Literal["last_wins", "exclude_overlaps"] = "last_wins", ) -> None: - """Annotate cells with neighborhood group labels. - - Parameters: - ----------- - mdata: MuData object with 'milo' modality. - nhood_group_obs: Column in `mdata["milo"].var` to use for neighborhood group labels. - subset_nhoods: List of neighborhood IDs to consider. If None, all neighborhoods are used. - min_n_nhoods: Minimum number of neighborhoods a cell must belong to in order to be annotated. Used for mode "exclude_overlaps". - mode: Mode for annotation. Options are: - - "last_wins": Last neighborhood label wins, adapted from miloR. - - "exclude_overlaps": Exclude overlaps, keeping only the most representative cells within groups. + """Assign neighborhood group labels to cells based on neighborhood membership. + + This function annotates cells in `mdata["rna"].obs` using group labels from + `mdata["milo"].var[nhood_group_obs]`. Supports two modes for resolving overlaps: + - "last_wins": Assign the last matching group label (default; mimics MiloR behavior). + - "exclude_overlaps": Assign only if the cell belongs to a minimum number of neighborhoods + from a single group. + + Args: + mdata: MuData object with: + - `mdata["milo"].var[nhood_group_obs]`: categorical group labels. + - `mdata["rna"].obsm["nhoods"]`: binary matrix of cell–neighborhood memberships. + nhood_group_obs: Column name in `mdata["milo"].var` with group labels. Defaults to "nhood_groups". + subset_nhoods: Optional list of neighborhood IDs to restrict annotation. If None, all neighborhoods are used. + min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to in order to be assigned + (only used in mode `"exclude_overlaps"`). Defaults to 3. + mode: Strategy for resolving overlapping group assignments. One of: + - `"last_wins"`: Assign label from last matching neighborhood. + - `"exclude_overlaps"`: Assign only if group dominates cell’s memberships. Returns: - -------- - None: Modifies `mdata["rna"].obs` in place, adding a column `nhood_groups` with the assigned labels. + Updates `mdata["rna"].obs["nhood_groups"]` with the assigned labels in place. Examples: >>> import pertpy as pt @@ -1721,24 +1814,24 @@ def annotate_cells_from_nhoods( else: raise ValueError(f"Unknown mode '{mode}'. Use 'last_wins' or 'exclude_overlaps'.") - def get_mean_expression(self, adata, groupby: str, var_names: list[str]) -> pd.DataFrame: - """Compute the *mean* expression (counts) of each gene in `var_names`, stratified by a categorical column `groupby` in adata.obs. + def get_mean_expression( + self, + adata: AnnData, + groupby: str, + var_names: list[str], + ) -> pd.DataFrame: + """Compute the mean expression of selected genes stratified by a categorical grouping. - Parameters - ---------- - adata : AnnData - AnnData object containing the expression matrix in `.X` and categorical metadata in `.obs`. - groupby : str - Column name in `adata.obs` that contains the categorical variable to group by. - var_names : list of str - List of gene names (or variable names) for which to compute the mean expression. + Args: + adata: AnnData object containing the expression matrix in `X` and categorical metadata in `obs`. + groupby: Name of the column in `adata.obs` to group cells by. + var_names: List of variable (gene) names for which to compute the mean expression. Returns: - ------- - mean_df : pandas.DataFrame (n_genes × n_groups) - Rows are `var_names`, columns are the unique categories of `adata.obs[groupby]`. - Each entry mean_df.loc[g, grp] = (sum of adata[:, g].X over all cells in `grp`) - / (number of cells in that `grp`). + mean_df: A pandas DataFrame of shape (len(var_names), n_groups) where + - rows are the genes in `var_names` + - columns are the unique categories in `adata.obs[groupby]` + - each entry is the average count of that gene over all cells in the corresponding group. """ # 1) Subset the matrix to just the columns (genes) in var_names: subX = adata[:, var_names].X.copy() # shape: (n_cells, n_genes) @@ -1778,13 +1871,37 @@ def _run_edger_contrasts( baseline: str | None = None, subset_samples: list[str] | None = None, ) -> pd.DataFrame: - """Run edgeR QLF tests on a pseudobulk AnnData. + """Run edgeR QLF tests on pseudobulk data using specified contrasts. - If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. - Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. + Performs differential expression analysis using edgeR's quasi-likelihood + F-tests on pseudobulked expression data. Supports either a user-specified + two-level contrast (`baseline` vs `group_to_compare`), or one-vs-rest testing + across all groups in `pdata.obs[nhood_group_obs]`. + + Args: + pdata: AnnData object with pseudobulked expression data in `.X` and + sample-level annotations in `.obs`. + nhood_group_obs: Name of the `.obs` column used to define group membership for contrast. + formula: R-style design formula (e.g., `"~ group"`). Used to generate design matrices in edgeR. + group_to_compare: Name of the group to compare (e.g., `"treated"`). + If provided along with `baseline`, a two-group test is run. + baseline: Reference group (e.g., `"control"`) for the two-group contrast. + subset_samples: Optional list of sample names to subset `pdata` before analysis. - Returns a pandas DataFrame with columns: - ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). + Returns: + pd.DataFrame: Differential expression results with columns: + - `"variable"`: gene/feature name + - `"log_fc"`: log-fold change estimate + - `"p_value"`: raw p-value + - `"adj_p_value"`: multiple-testing corrected p-value + - `"group"` (optional): group name (only present in one-vs-rest mode) + + Raises: + ValueError: If contrast groups are not present in the data or input is malformed. + + Example: + >>> de_df = milo._run_edger_contrasts(pdata, "condition", formula="~ condition", + >>> group_to_compare="treated", baseline="control") """ if not _is_counts(pdata.X): raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") @@ -1918,45 +2035,47 @@ def _run_pydeseq2_contrasts( alpha: float = 0.05, quiet: bool = True, ) -> pd.DataFrame: - """Run PyDESeq2 on a pseudobulk AnnData (`pdata`) with a given neighborhood grouping, using exactly the design `formula` you supply. - - Parameters - ---------- - pdata : AnnData - Pseudobulk AnnData, where .obs[nhood_group_obs] is a categorical allowing - you to compare levels. + """Run PyDESeq2 differential testing on pseudobulked AnnData using a design formula. - nhood_group_obs : str - The column name in pdata.obs that holds the neighborhood groups. + Supports either a two-level contrast (`group_to_compare` vs `baseline`) or one-vs-rest + comparisons for all levels of a categorical column in `.obs`. Results are returned + as a tidy `DataFrame` compatible with downstream analysis. - formula : str - An R‐style design formula, e.g. "~ batch + Nhood_Group". Must include - `nhood_group_obs` as one of the terms. This is used verbatim for both the - single‐contrast and one‐vs‐rest calls. - - group_to_compare : Optional[str] - If non‐None (and `baseline` is also non‐None), run only the single contrast - [nhood_group_obs, group_to_compare, baseline] with design = `formula`. - - baseline : Optional[str] - If non‐None (and `group_to_compare` is non‐None), run only that one contrast. - If either is None, the function does a one‐vs‐rest loop over all levels of - pdata.obs[nhood_group_obs]. - - alpha : float, default=0.05 - Significance threshold passed to PyrDESeq2’s `DeseqStats`. - - quiet : bool, default=True - Whether to suppress PyDESeq2’s “DESeq2()” progress messages. + Args: + pdata: Pseudobulk `AnnData` object with expression matrix in `.X` and + covariates in `.obs`, including `nhood_group_obs`. + nhood_group_obs: Name of the `.obs` column to use for contrast groups. + formula: R-style design formula (e.g., `"~ batch + group"`), passed directly to PyDESeq2. + group_to_compare: Name of the group to test against `baseline`. If None, + one-vs-rest mode is triggered. + baseline: Name of the baseline group for contrast. Must be specified if `group_to_compare` is given. + alpha: FDR threshold passed to PyDESeq2's `DeseqStats`. Defaults to 0.05. + quiet: If True, suppresses progress messages from PyDESeq2. Defaults to True. Returns: - ------- - pd.DataFrame - If `group_to_compare` and `baseline` are provided: a DataFrame with columns - ["variable","log_fc","p_value","adj_p_value"], sorted by p_value. - - Otherwise (one‐vs‐rest): a concatenated DataFrame with those columns plus - a “group” column indicating which level was tested vs “rest.” + pd.DataFrame: If `group_to_compare` and `baseline` are specified, returns a + single contrast result with columns: + - `"variable"`: feature name + - `"log_fc"`: log2 fold change + - `"p_value"`: raw p-value + - `"adj_p_value"`: FDR-corrected p-value + + If no contrast is specified, performs one-vs-rest for each group and returns + a concatenated DataFrame with the same columns plus: + - `"group"`: the group tested against all others + + Raises: + ImportError: If `pydeseq2` is not installed. + ValueError: If only one of `group_to_compare` or `baseline` is provided. + + Example: + >>> de_df = milo._run_pydeseq2_contrasts( + ... pdata, + ... nhood_group_obs="condition", + ... formula="~ condition", + ... group_to_compare="treated", + ... baseline="control", + ... ) """ if find_spec("pydeseq2") is None: raise ImportError("pydeseq2 is required but not installed. Install with: pip install pydeseq2") @@ -2048,8 +2167,32 @@ def _run_pydeseq2_contrasts( final_df = pd.concat(all_results, ignore_index=True) return final_df - def _filter_by_expr_edger(self, pdata, formula, **kwargs): - """Filter genes in `pdata` based on expression criteria using edgeR.""" + def _filter_by_expr_edger( + self, + pdata: AnnData, + formula: str, + **kwargs, + ) -> None: + """Filter low-expressed genes from a pseudobulk AnnData object using edgeR. + + This function uses `edgeR::filterByExpr()` via rpy2 to identify and retain + genes with sufficient expression for differential testing, based on the + provided design formula and expression thresholds. + + The filtering is performed in-place by subsetting `pdata.var`. + + Args: + pdata: Pseudobulk `AnnData` object with raw counts in `.X` and + covariates in `.obs`. + formula: R-style design formula (e.g., `"~ condition + batch"`), used to + compute the design matrix in edgeR. + **kwargs: Additional keyword arguments passed to `edgeR::filterByExpr()`. + Examples include `min.count`, `min.total.count`, etc. + + Returns: + None: The function modifies `pdata` in place by subsetting `pdata.var` + to include only retained genes. + """ edger, _, rstats, rbase = self._setup_rpy2() import rpy2.robjects as ro from rpy2.robjects import numpy2ri, pandas2ri @@ -2068,7 +2211,31 @@ def _filter_by_expr_edger(self, pdata, formula, **kwargs): pdata._inplace_subset_var(keep) - def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6, **kwargs): + def _filter_highly_variable_scanpy( + self, + pdata: AnnData, + n_top_genes: int = 7500, + target_sum: float = 1e6, + **kwargs, + ) -> None: + """Filter highly variable genes from a pseudobulk AnnData using Scanpy. + + Normalizes and log-transforms raw count data if needed, then selects the + top `n_top_genes` most variable genes using `scanpy.pp.highly_variable_genes`. + Results are stored in-place by subsetting `pdata.var`. + + Args: + pdata: AnnData object with raw or normalized pseudobulk expression in `.X`. + n_top_genes: Number of top variable genes to retain. Defaults to 7500. + target_sum: Target total count for normalization (used only if `.X` is raw counts). + Defaults to 1e6. + **kwargs: Additional keyword arguments passed to `scanpy.pp.highly_variable_genes()`. + + Returns: + None: The function modifies `pdata` in place: + - Adds normalized expression to `pdata.layers["normalized"]` + - Filters `.var` to include only the top `n_top_genes` genes + """ if _is_counts(pdata.X): pdata.layers["normalized"] = pdata.X.copy() sc.pp.normalize_total( @@ -2082,7 +2249,29 @@ def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6 sc.pp.highly_variable_genes(pdata, layer="normalized", n_top_genes=n_top_genes, subset=True, **kwargs) - def _filter_highly_variable_scran(self, pdata, n_top_genes): + def _filter_highly_variable_scran( + self, + pdata: AnnData, + n_top_genes: int, + ) -> None: + """Filter highly variable genes using R's scran and scuttle packages. + + If `pdata.X` contains raw counts, normalization is performed using + `logNormCounts()` from `scuttle`. Otherwise, the matrix is assumed + to be already log-normalized. + + The top `n_top_genes` most variable genes are selected using + `scran.modelGeneVar()` and `scran.getTopHVGs()` and used to subset + `pdata.var` in place. + + Args: + pdata: AnnData object containing pseudobulk expression matrix. + n_top_genes: Number of top highly variable genes to retain. + + Returns: + None: The function modifies `pdata` in place by subsetting `.var` + to contain only the selected HVGs. + """ scran = self._try_import_bioc_library("scran") scuttle = self._try_import_bioc_library("scuttle") singlecellexperiment = self._try_import_bioc_library("SingleCellExperiment") @@ -2135,57 +2324,49 @@ def find_nhood_group_markers( alpha: float = 0.05, use_eb: bool = False, **kwargs, - ): - """Perform differential expression analysis on neighborhood groups in a MuData object. + ) -> pd.DataFrame: + """Perform differential expression analysis on neighborhood groups in a MuData or AnnData object. - The MuData object must contain a modality with the name `key`, which is used for pseudobulk aggregation. - The column `nhood_group_obs` in `mdata[key]` must contain the neighborhood group labels, and `sample_col` must contain the sample labels. - Neighborhood group labels can be assigned to the single-cell data using ´milo.group_nhoods(...)`, or manually set in `mdata[key].obs[nhood_group_obs]`. - Neighborhood group labels must be strings or categorical values and are used for pseudobulk aggregation. - If both `group_to_compare` and `baseline` are given, runs exactly that contrast. Otherwise, runs one‐vs‐rest for every level of `nhood_group_obs`. - All NAs in mdata[key].obs[nhood_group_obs] are filtered out before running the analysis. - Therefore, if annotating nhood_group_obs manually, introducing NAs before Milo().group_nhoods(...) is can exclude unwanted neighborhoods from the analysis. + This function performs pseudobulk aggregation over neighborhood groupings and tests for differential + expression (DE) between groups using either `pydeseq2` or `edgeR`. - Parameters - ---------- - mdata : MuData - A MuData object containing the data. Must have a modality with the name `key`. - group_to_compare : Optional[str] - If provided, runs a single contrast comparing this group to `baseline`. - baseline : Optional[str] - The reference group for the contrast. Must be provided if `group_to_compare` is provided. - nhood_group_obs : str, default="nhood_groups" - The name of the column in `adata.obs` that contains the neighborhood group labels. - sample_col : str, default="sample" - The name of the column in `adata.obs` that contains the sample labels. - covariates : Collection[str] | None, default=None - A collection of additional covariates to include in the design formula. - If None, no additional covariates are used. - key : str, default="rna" - The key in `mdata` that corresponds to the modality to be used for pseudobulk aggregation. - pseudobulk_function : str, default="sum" - The function to use for pseudobulk aggregation. Can be "sum" or "mean". - layer : str | None, default=None - If provided, the layer to use for pseudobulk aggregation. If None, uses the default layer. - target_sum : float, default=1e6 - The target sum for normalization when using the "scanpy" filter method. - n_top_genes : int, default=7500 - The number of top variable genes to retain after filtering. Only used if `filter_method` is `scanpy` `scran`. - filter_method : str | None, default="scanpy" - The method to use for filtering highly variable genes. Can be "scanpy", "scran", or "filterByExpr". - If None, no filtering is applied. - var_names : Collection[str] | None, default=None - A collection of variable names to restrict the analysis to. If None, all variables are used. - de_method : Literal["pydeseq2", "statsmodels", "edgeR", "limma"], default="pydeseq2" - The method to use for differential expression analysis. Can be "pydeseq2", "statsmodels", "edgeR", or "limma". - quiet : bool, default=True - If True, suppresses output messages from pydeseq2. - alpha : float, default=0.05 - The significance threshold for differential expression analysis in pydeseq2. - use_eb : bool, default=False - If True, applies empirical Bayes moderation to the results in statsmodels. Not for serious use, but a starting point for limma-like differential testing in pure Python. - **kwargs : dict - Additional keyword arguments passed to the filtering methods or differential expression methods. + The MuData must contain a modality (default `"rna"`) used for pseudobulk aggregation. + Group labels must be stored in `nhood_group_obs`, and sample labels in `sample_col`. + + If both `group_to_compare` and `baseline` are provided, a specific two-group contrast is tested. + Otherwise, one-vs-rest DE is performed for each level in `nhood_group_obs`. + + Notes: + - All NAs in `nhood_group_obs` are removed before pseudobulk aggregation. + - If annotating neighborhood groups manually, you can introduce NAs beforehand to exclude neighborhoods. + + Args: + data: A `MuData` or `AnnData` object. + group_to_compare: The group to compare (e.g. case) in a specific contrast. Must be in `nhood_group_obs`. + baseline: The baseline group (e.g. control). Must be in `nhood_group_obs` if `group_to_compare` is given. + nhood_group_obs: Column in `.obs` with neighborhood group labels. Must be categorical or string-typed. + sample_col: Column in `.obs` specifying sample identifiers. + covariates: Optional list of covariates to include in the DE model formula. + key: Name of modality in `MuData` used for pseudobulk aggregation (default `"rna"`). + pseudobulk_function: Aggregation function used for pseudobulk (either `"sum"` or `"mean"`). + layer: Optional layer to use for aggregation. Defaults to `X` if not provided. + target_sum: Used for Scanpy-based normalization when filtering (default: `1e6`). + n_top_genes: Number of highly variable genes to retain (if filtering is applied). + filter_method: How to filter genes before DE analysis. One of `"scanpy"`, `"scran"`, or `"filterByExpr"`. + var_names: Optional list of variable (gene) names to restrict analysis to. Overrides filtering if provided. + de_method: Differential expression method: `"pydeseq2"` (default) or `"edger"`. + quiet: Whether to suppress console output from PyDESeq2 (default: True). + alpha: Significance threshold passed to DE test (used in PyDESeq2). + use_eb: If `True`, applies empirical Bayes shrinkage (not implemented yet, reserved for future limma-style methods). + **kwargs: Additional arguments passed to filtering or DE methods (e.g., `min_expr`, `min_total` for edgeR filtering). + + Returns: + pd.DataFrame: DE results with columns: + - "variable": Gene/feature name + - "log_fc": log2 fold change + - "p_value": Unadjusted p-value + - "adj_p_value": Multiple testing-corrected p-value + - "group": (only for one-vs-rest) the group being compared vs rest Examples: >>> import pertpy as pt From 976e9039b386fafb8c4c049f059056050ad96ac7 Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Tue, 17 Jun 2025 06:22:04 +0200 Subject: [PATCH 10/10] Updated :class:`pandas.DataFrame` in doc strings and ``|logFC|`` for sphinx parsing. Also commented out get_mean_expression and plot_heatmap_with_dots_and_colorbar, they introduced errors and the plot is hard to make compatible with the scanpy API. --- pertpy/tools/_milo.py | 555 +++++++++++++++++++++--------------------- 1 file changed, 276 insertions(+), 279 deletions(-) diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index eb709f93..9e74684a 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -890,9 +890,6 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 plt.show() return None - from collections.abc import Sequence - from typing import Union - # In plot_nhood_annotation color_map, palette, and ax are not documented, and not part of common_plot_args # Should I add them or will they be part of common_plot_args in the future? @_doc_params(common_plot_args=doc_common_plot_args) @@ -915,7 +912,7 @@ def plot_nhood_annotation( # pragma: no cover # noqa: D417 ) -> Figure | None: """Visualize Milo differential-abundance results on the neighborhood graph. - By default, neighborhoods are colored by filtered logFC (|logFC| ≥ `min_logFC` + By default, neighborhoods are colored by filtered logFC (``|logFC|`` ≥ `min_logFC` and SpatialFDR ≤ `alpha`). If `annotation_key` is provided, this column from `mdata[adata_key].obs` will be used instead for coloring. @@ -1814,52 +1811,52 @@ def annotate_cells_from_nhoods( else: raise ValueError(f"Unknown mode '{mode}'. Use 'last_wins' or 'exclude_overlaps'.") - def get_mean_expression( - self, - adata: AnnData, - groupby: str, - var_names: list[str], - ) -> pd.DataFrame: - """Compute the mean expression of selected genes stratified by a categorical grouping. - - Args: - adata: AnnData object containing the expression matrix in `X` and categorical metadata in `obs`. - groupby: Name of the column in `adata.obs` to group cells by. - var_names: List of variable (gene) names for which to compute the mean expression. - - Returns: - mean_df: A pandas DataFrame of shape (len(var_names), n_groups) where - - rows are the genes in `var_names` - - columns are the unique categories in `adata.obs[groupby]` - - each entry is the average count of that gene over all cells in the corresponding group. - """ - # 1) Subset the matrix to just the columns (genes) in var_names: - subX = adata[:, var_names].X.copy() # shape: (n_cells, n_genes) - - # 2) Build a one‐hot (dummy) matrix of shape (n_cells, n_groups): - groups = pd.get_dummies(adata.obs[groupby], drop_first=False) - # groups.values is (n_cells, n_groups). groups.sum() is a Series: number of cells per group. - n_per_group = groups.sum().astype(float) # length = n_groups - - # 3) Compute Σ_counts_{gene i, group j} by matrix‐multiplication: - # - If subX is sparse, convert to a CSR; otherwise treat as dense. - if issparse(subX): - subX = csr_matrix(subX) - sum_counts = subX.T.dot(csr_matrix(groups.values)) # shape (n_genes, n_groups), sparse - sum_counts = sum_counts.toarray() # convert to dense (n_genes, n_groups) - else: - # dense case: subX is (n_cells, n_genes), so subX.T is (n_genes, n_cells), - # dot with (n_cells, n_groups) → (n_genes, n_groups) - sum_counts = subX.T.dot(groups.values) - - # 4) Divide each column (group) by its total cell count to get means: - # We want mean_counts[i, j] = sum_counts[i, j] / n_per_group[j]. - # n_per_group.values is shape (n_groups,), so broadcasting works. - mean_mat = sum_counts / n_per_group.values[np.newaxis, :] - - # 5) Build a DataFrame, indexed by var_names, columns = groups.columns - mean_df = pd.DataFrame(mean_mat, index=var_names, columns=groups.columns) - return mean_df + # def get_mean_expression( + # self, + # adata: AnnData, + # groupby: str, + # var_names: list[str], + # ) -> pd.DataFrame: + # """Compute the mean expression of selected genes stratified by a categorical grouping. + + # Args: + # adata: AnnData object containing the expression matrix in `X` and categorical metadata in `obs`. + # groupby: Name of the column in `adata.obs` to group cells by. + # var_names: List of variable (gene) names for which to compute the mean expression. + + # Returns: + # mean_df: A pandas DataFrame of shape (len(var_names), n_groups) where + # - rows are the genes in `var_names` + # - columns are the unique categories in `adata.obs[groupby]` + # - each entry is the average count of that gene over all cells in the corresponding group. + # """ + # # 1) Subset the matrix to just the columns (genes) in var_names: + # subX = adata[:, var_names].X.copy() # shape: (n_cells, n_genes) + + # # 2) Build a one‐hot (dummy) matrix of shape (n_cells, n_groups): + # groups = pd.get_dummies(adata.obs[groupby], drop_first=False) + # # groups.values is (n_cells, n_groups). groups.sum() is a Series: number of cells per group. + # n_per_group = groups.sum().astype(float) # length = n_groups + + # # 3) Compute Σ_counts_{gene i, group j} by matrix‐multiplication: + # # - If subX is sparse, convert to a CSR; otherwise treat as dense. + # if issparse(subX): + # subX = csr_matrix(subX) + # sum_counts = subX.T.dot(csr_matrix(groups.values)) # shape (n_genes, n_groups), sparse + # sum_counts = sum_counts.toarray() # convert to dense (n_genes, n_groups) + # else: + # # dense case: subX is (n_cells, n_genes), so subX.T is (n_genes, n_cells), + # # dot with (n_cells, n_groups) → (n_genes, n_groups) + # sum_counts = subX.T.dot(groups.values) + + # # 4) Divide each column (group) by its total cell count to get means: + # # We want mean_counts[i, j] = sum_counts[i, j] / n_per_group[j]. + # # n_per_group.values is shape (n_groups,), so broadcasting works. + # mean_mat = sum_counts / n_per_group.values[np.newaxis, :] + + # # 5) Build a DataFrame, indexed by var_names, columns = groups.columns + # mean_df = pd.DataFrame(mean_mat, index=var_names, columns=groups.columns) + # return mean_df def _run_edger_contrasts( self, @@ -1889,7 +1886,7 @@ def _run_edger_contrasts( subset_samples: Optional list of sample names to subset `pdata` before analysis. Returns: - pd.DataFrame: Differential expression results with columns: + :class:`pandas.DataFrame`: Differential expression results with columns: - `"variable"`: gene/feature name - `"log_fc"`: log-fold change estimate - `"p_value"`: raw p-value @@ -2053,7 +2050,7 @@ def _run_pydeseq2_contrasts( quiet: If True, suppresses progress messages from PyDESeq2. Defaults to True. Returns: - pd.DataFrame: If `group_to_compare` and `baseline` are specified, returns a + :class:`pandas.DataFrame`: If `group_to_compare` and `baseline` are specified, returns a single contrast result with columns: - `"variable"`: feature name - `"log_fc"`: log2 fold change @@ -2361,7 +2358,7 @@ def find_nhood_group_markers( **kwargs: Additional arguments passed to filtering or DE methods (e.g., `min_expr`, `min_total` for edgeR filtering). Returns: - pd.DataFrame: DE results with columns: + :class:`pandas.DataFrame`: DE results with columns: - "variable": Gene/feature name - "log_fc": log2 fold change - "p_value": Unadjusted p-value @@ -2518,229 +2515,229 @@ def find_nhood_group_markers( else: raise ValueError(f"de_method must be one of 'pydeseq2' or 'edger', not '{de_method}'") - def plot_heatmap_with_dot_and_colorbar( - self, - mean_df: pd.DataFrame, - logfc_ser: pd.Series | None = None, - cmap: str = "YlGnBu", - dot_scale: float = 200.0, - figsize: tuple[float, float] = (6, 10), - panel_ratios: tuple[float, float, float] = (5, 0.6, 0.3), - cbar_tick_count: int = 5, - show_dot: bool = True, - legend_on_right: bool = False, - ) -> plt.Figure: - """Marker heatmap of mean expression across groups, with optional logFC dots and a colorbar. - - Plot a figure with: - • Left: heatmap of mean_df (genes × groups), WITHOUT its default colorbar. - • (Optional) Middle: a single column of dots (size ∝ |logFC|), one per gene. - • Right: a slim vertical colorbar (ggplot2 style) that applies to the heatmap. - • (Optional) A size legend for logFC dots, either just to the right of the colorbar - (legend_on_right=False, the default) or further to the right (legend_on_right=True). - - If show_dot=False, `logfc_ser` may be omitted (and is ignored). If show_dot=True, - then `logfc_ser` must be provided and must match `mean_df.index`. - - Parameters - ---------- - mean_df : pandas.DataFrame, shape (n_genes, n_groups) - Rows = gene names; columns = group labels; values = mean expression. - - logfc_ser : pandas.Series or None, default=None - If show_dot=True, this Series of length n_genes (indexed by gene names) gives - the logFC for each gene. If show_dot=False, you may leave this as None. - - cmap : str, default="YlGnBu" - Colormap for the heatmap and its colorbar. - - dot_scale : float, default=200.0 - Controls the maximum dot area for the largest |logFC| (only used if show_dot=True). - - figsize : tuple (W, H), default=(6, 10) - Total figure size in inches. Width W is split among panels according to ratios. - - panel_ratios : tuple (r1, r2, r3), default=(5, 0.6, 0.3) - Relative widths for [heatmap, dot‐column, colorbar] when show_dot=True. - If show_dot=False, only r1 and r3 are used to split the width. - - cbar_tick_count : int, default=5 - Number of ticks on the vertical colorbar. - - show_dot : bool, default=True - If True, draw the dot column (requires `logfc_ser`). If False, omit dots and - only draw [heatmap | colorbar]. - - legend_on_right : bool, default=False - If True, move the “size legend” further to the right of the figure, - to avoid overlap when the figure is narrow. If False, place it just - to the right of the colorbar (may overlap if figure is very narrow). - - Returns: - ------- - fig : matplotlib.figure.Figure - - Examples: - >>> varnames = ( - >>> nhood_group_markers_results - >>> .query('logFC >= 0.5') - >>> .query('adj_PValue <= 0.01') - >>> .sort_values("logFC", ascending = False) - >>> .variable.to_list() - >>> ) - >>> mean_df = milo.get_mean_expression(mdata["rna"], "nhood_groups", var_names=varnames) - >>> logfc_ser = ( - >>> nhood_group_markers_results - >>> .query('logFC >= 0.5') - >>> .query('adj_PValue <= 0.01') - >>> .set_index("variable") - >>> .logFC - >>> ) - >>> fig = milo.plot_heatmap_with_dot_and_colorbar( - >>> mean_df, - >>> logfc_ser=logfc_ser, - >>> cmap="YlGnBu", - >>> dot_scale=200.0, - >>> figsize=(2, (1.5, len(logfc_ser)*0.15)), - >>> panel_ratios=(5, 0.6, 0.3), - >>> cbar_tick_count=5, - >>> show_dot=True, - >>> legend_on_right=1.3, - >>> ) - - """ - # ──────────────────────────────── - # 1) Validate / align logFC - # ──────────────────────────────── - if show_dot: - if logfc_ser is None: - raise ValueError("`logfc_ser` must be provided when `show_dot=True`.") - genes = list(mean_df.index) - lfc_vals = logfc_ser.reindex(index=genes).fillna(0.0).values - n_genes = len(genes) - else: - genes = list(mean_df.index) - n_genes = len(genes) - lfc_vals = None - - groups = list(mean_df.columns) - - # ──────────────────────────────── - # 2) Dot‐size scaling (if needed) - # ──────────────────────────────── - if show_dot: - max_abs_lfc = np.nanmax(np.abs(lfc_vals)) - if max_abs_lfc == 0 or np.isnan(max_abs_lfc): - max_abs_lfc = 1.0 - - # ──────────────────────────────── - # 3) Heatmap normalization - # ──────────────────────────────── - vmin = mean_df.values.min() - vmax = mean_df.values.max() - norm = Normalize(vmin=vmin, vmax=vmax) - cmap_obj = plt.get_cmap(cmap) - - # ──────────────────────────────── - # 4) Build a GridSpec - # ──────────────────────────────── - W, H = figsize - r1, r2, r3 = panel_ratios - - if show_dot: - # three panels: [heatmap | dots | colorbar] - total_ratio = r1 + r2 + r3 - width_ratios = [r1 / total_ratio, r2 / total_ratio, r3 / total_ratio] - fig = plt.figure(figsize=(W, H)) - gs = fig.add_gridspec(nrows=1, ncols=3, width_ratios=width_ratios, wspace=0.02) - ax_heat = fig.add_subplot(gs[0, 0]) - else: - # two panels: [heatmap | colorbar] - total_ratio = r1 + r3 - width_ratios = [r1 / total_ratio, r3 / total_ratio] - fig = plt.figure(figsize=(W, H)) - gs = fig.add_gridspec(nrows=1, ncols=2, width_ratios=width_ratios, wspace=0.02) - ax_heat = fig.add_subplot(gs[0, 0]) - - # ──────────────────────────────── - # 5) Plot heatmap (no default colorbar) - # ──────────────────────────────── - sns.heatmap( - mean_df, - ax=ax_heat, - cmap=cmap, - norm=norm, - cbar=False, - yticklabels=genes, - xticklabels=groups, - linewidths=0.5, - linecolor="gray", - ) - ax_heat.set_ylabel("Gene", fontsize=10) - ax_heat.set_xlabel("Group", fontsize=10) - plt.setp(ax_heat.get_xticklabels(), rotation=45, ha="right", fontsize=8) - plt.setp(ax_heat.get_yticklabels(), rotation=0, fontsize=6) - - # ──────────────────────────────── - # 6) Dot panel (if requested) - # ──────────────────────────────── - if show_dot: - ax_dot = fig.add_subplot(gs[0, 1]) - for i, val in enumerate(lfc_vals): - if not np.isnan(val) and val != 0.0: - area = (abs(val) / max_abs_lfc) * dot_scale - ax_dot.scatter(0, i, s=area, color="black", alpha=0.8, edgecolors="none") - ax_dot.set_xlim(-0.5, 0.5) - ax_dot.set_ylim(n_genes - 0.5, -0.5) - ax_dot.set_xticks([]) - ax_dot.set_yticks([]) - ax_dot.set_title("logFC", pad=10, fontdict={"fontsize": 7}) - ax_cbar = fig.add_subplot(gs[0, 2]) - else: - ax_cbar = fig.add_subplot(gs[0, 1]) - - # ──────────────────────────────── - # 7) Draw vertical colorbar for heatmap - # ──────────────────────────────── - smap = ScalarMappable(norm=norm, cmap=cmap_obj) - smap.set_array([]) - - cbar = fig.colorbar( - smap, cax=ax_cbar, orientation="vertical", ticks=np.linspace(vmin, vmax, num=cbar_tick_count) - ) - cbar.ax.tick_params(labelsize=8, length=4, width=1) - cbar.ax.set_title("Mean\nExpr.", fontsize=8, pad=6) - cbar.outline.set_linewidth(0.5) - - # ──────────────────────────────── - # 8) Add a size‐legend for the dot‐column (optional) - # ──────────────────────────────── - if show_dot: - # Choose three reference |logFC| values: max, ½ max, ¼ max - ref_vals = np.array([max_abs_lfc, 0.5 * max_abs_lfc, 0.25 * max_abs_lfc]) - legend_handles = [] - legend_labels = [] - for rv in ref_vals: - sz = (rv / max_abs_lfc) * dot_scale - handle = ax_dot.scatter(0, 0, s=sz, color="black", alpha=0.8, edgecolors="none") - legend_handles.append(handle) - legend_labels.append(f"|logFC| = {rv:.2f}") - - # Determine bounding box based on legend_on_right flag - bbox_x = (1.2 if isinstance(legend_on_right, bool) else legend_on_right) if legend_on_right else 1.02 - - fig.legend( - legend_handles, - legend_labels, - title="Dot size legend", - loc="center left", - bbox_to_anchor=(bbox_x, 0.5), - frameon=False, - fontsize=7, - title_fontsize=8, - handletextpad=0.5, - labelspacing=0.6, - ) - - plt.tight_layout() - return fig + # def plot_heatmap_with_dot_and_colorbar( + # self, + # mean_df: pd.DataFrame, + # logfc_ser: pd.Series | None = None, + # cmap: str = "YlGnBu", + # dot_scale: float = 200.0, + # figsize: tuple[float, float] = (6, 10), + # panel_ratios: tuple[float, float, float] = (5, 0.6, 0.3), + # cbar_tick_count: int = 5, + # show_dot: bool = True, + # legend_on_right: bool = False, + # ) -> plt.Figure: + # """Marker heatmap of mean expression across groups, with optional logFC dots and a colorbar. + + # Plot a figure with: + # • Left: heatmap of mean_df (genes × groups), WITHOUT its default colorbar. + # • (Optional) Middle: a single column of dots (size ∝ |logFC|), one per gene. + # • Right: a slim vertical colorbar (ggplot2 style) that applies to the heatmap. + # • (Optional) A size legend for logFC dots, either just to the right of the colorbar + # (legend_on_right=False, the default) or further to the right (legend_on_right=True). + + # If show_dot=False, `logfc_ser` may be omitted (and is ignored). If show_dot=True, + # then `logfc_ser` must be provided and must match `mean_df.index`. + + # Parameters + # ---------- + # mean_df : pandas.DataFrame, shape (n_genes, n_groups) + # Rows = gene names; columns = group labels; values = mean expression. + + # logfc_ser : pandas.Series or None, default=None + # If show_dot=True, this Series of length n_genes (indexed by gene names) gives + # the logFC for each gene. If show_dot=False, you may leave this as None. + + # cmap : str, default="YlGnBu" + # Colormap for the heatmap and its colorbar. + + # dot_scale : float, default=200.0 + # Controls the maximum dot area for the largest |logFC| (only used if show_dot=True). + + # figsize : tuple (W, H), default=(6, 10) + # Total figure size in inches. Width W is split among panels according to ratios. + + # panel_ratios : tuple (r1, r2, r3), default=(5, 0.6, 0.3) + # Relative widths for [heatmap, dot‐column, colorbar] when show_dot=True. + # If show_dot=False, only r1 and r3 are used to split the width. + + # cbar_tick_count : int, default=5 + # Number of ticks on the vertical colorbar. + + # show_dot : bool, default=True + # If True, draw the dot column (requires `logfc_ser`). If False, omit dots and + # only draw [heatmap | colorbar]. + + # legend_on_right : bool, default=False + # If True, move the “size legend” further to the right of the figure, + # to avoid overlap when the figure is narrow. If False, place it just + # to the right of the colorbar (may overlap if figure is very narrow). + + # Returns: + # ------- + # fig : matplotlib.figure.Figure + + # Examples: + # >>> varnames = ( + # >>> nhood_group_markers_results + # >>> .query('logFC >= 0.5') + # >>> .query('adj_PValue <= 0.01') + # >>> .sort_values("logFC", ascending = False) + # >>> .variable.to_list() + # >>> ) + # >>> mean_df = milo.get_mean_expression(mdata["rna"], "nhood_groups", var_names=varnames) + # >>> logfc_ser = ( + # >>> nhood_group_markers_results + # >>> .query('logFC >= 0.5') + # >>> .query('adj_PValue <= 0.01') + # >>> .set_index("variable") + # >>> .logFC + # >>> ) + # >>> fig = milo.plot_heatmap_with_dot_and_colorbar( + # >>> mean_df, + # >>> logfc_ser=logfc_ser, + # >>> cmap="YlGnBu", + # >>> dot_scale=200.0, + # >>> figsize=(2, (1.5, len(logfc_ser)*0.15)), + # >>> panel_ratios=(5, 0.6, 0.3), + # >>> cbar_tick_count=5, + # >>> show_dot=True, + # >>> legend_on_right=1.3, + # >>> ) + + # """ + # # ──────────────────────────────── + # # 1) Validate / align logFC + # # ──────────────────────────────── + # if show_dot: + # if logfc_ser is None: + # raise ValueError("`logfc_ser` must be provided when `show_dot=True`.") + # genes = list(mean_df.index) + # lfc_vals = logfc_ser.reindex(index=genes).fillna(0.0).values + # n_genes = len(genes) + # else: + # genes = list(mean_df.index) + # n_genes = len(genes) + # lfc_vals = None + + # groups = list(mean_df.columns) + + # # ──────────────────────────────── + # # 2) Dot‐size scaling (if needed) + # # ──────────────────────────────── + # if show_dot: + # max_abs_lfc = np.nanmax(np.abs(lfc_vals)) + # if max_abs_lfc == 0 or np.isnan(max_abs_lfc): + # max_abs_lfc = 1.0 + + # # ──────────────────────────────── + # # 3) Heatmap normalization + # # ──────────────────────────────── + # vmin = mean_df.values.min() + # vmax = mean_df.values.max() + # norm = Normalize(vmin=vmin, vmax=vmax) + # cmap_obj = plt.get_cmap(cmap) + + # # ──────────────────────────────── + # # 4) Build a GridSpec + # # ──────────────────────────────── + # W, H = figsize + # r1, r2, r3 = panel_ratios + + # if show_dot: + # # three panels: [heatmap | dots | colorbar] + # total_ratio = r1 + r2 + r3 + # width_ratios = [r1 / total_ratio, r2 / total_ratio, r3 / total_ratio] + # fig = plt.figure(figsize=(W, H)) + # gs = fig.add_gridspec(nrows=1, ncols=3, width_ratios=width_ratios, wspace=0.02) + # ax_heat = fig.add_subplot(gs[0, 0]) + # else: + # # two panels: [heatmap | colorbar] + # total_ratio = r1 + r3 + # width_ratios = [r1 / total_ratio, r3 / total_ratio] + # fig = plt.figure(figsize=(W, H)) + # gs = fig.add_gridspec(nrows=1, ncols=2, width_ratios=width_ratios, wspace=0.02) + # ax_heat = fig.add_subplot(gs[0, 0]) + + # # ──────────────────────────────── + # # 5) Plot heatmap (no default colorbar) + # # ──────────────────────────────── + # sns.heatmap( + # mean_df, + # ax=ax_heat, + # cmap=cmap, + # norm=norm, + # cbar=False, + # yticklabels=genes, + # xticklabels=groups, + # linewidths=0.5, + # linecolor="gray", + # ) + # ax_heat.set_ylabel("Gene", fontsize=10) + # ax_heat.set_xlabel("Group", fontsize=10) + # plt.setp(ax_heat.get_xticklabels(), rotation=45, ha="right", fontsize=8) + # plt.setp(ax_heat.get_yticklabels(), rotation=0, fontsize=6) + + # # ──────────────────────────────── + # # 6) Dot panel (if requested) + # # ──────────────────────────────── + # if show_dot: + # ax_dot = fig.add_subplot(gs[0, 1]) + # for i, val in enumerate(lfc_vals): + # if not np.isnan(val) and val != 0.0: + # area = (abs(val) / max_abs_lfc) * dot_scale + # ax_dot.scatter(0, i, s=area, color="black", alpha=0.8, edgecolors="none") + # ax_dot.set_xlim(-0.5, 0.5) + # ax_dot.set_ylim(n_genes - 0.5, -0.5) + # ax_dot.set_xticks([]) + # ax_dot.set_yticks([]) + # ax_dot.set_title("logFC", pad=10, fontdict={"fontsize": 7}) + # ax_cbar = fig.add_subplot(gs[0, 2]) + # else: + # ax_cbar = fig.add_subplot(gs[0, 1]) + + # # ──────────────────────────────── + # # 7) Draw vertical colorbar for heatmap + # # ──────────────────────────────── + # smap = ScalarMappable(norm=norm, cmap=cmap_obj) + # smap.set_array([]) + + # cbar = fig.colorbar( + # smap, cax=ax_cbar, orientation="vertical", ticks=np.linspace(vmin, vmax, num=cbar_tick_count) + # ) + # cbar.ax.tick_params(labelsize=8, length=4, width=1) + # cbar.ax.set_title("Mean\nExpr.", fontsize=8, pad=6) + # cbar.outline.set_linewidth(0.5) + + # # ──────────────────────────────── + # # 8) Add a size‐legend for the dot‐column (optional) + # # ──────────────────────────────── + # if show_dot: + # # Choose three reference |logFC| values: max, ½ max, ¼ max + # ref_vals = np.array([max_abs_lfc, 0.5 * max_abs_lfc, 0.25 * max_abs_lfc]) + # legend_handles = [] + # legend_labels = [] + # for rv in ref_vals: + # sz = (rv / max_abs_lfc) * dot_scale + # handle = ax_dot.scatter(0, 0, s=sz, color="black", alpha=0.8, edgecolors="none") + # legend_handles.append(handle) + # legend_labels.append(f"|logFC| = {rv:.2f}") + + # # Determine bounding box based on legend_on_right flag + # bbox_x = (1.2 if isinstance(legend_on_right, bool) else legend_on_right) if legend_on_right else 1.02 + + # fig.legend( + # legend_handles, + # legend_labels, + # title="Dot size legend", + # loc="center left", + # bbox_to_anchor=(bbox_x, 0.5), + # frameon=False, + # fontsize=7, + # title_fontsize=8, + # handletextpad=0.5, + # labelspacing=0.6, + # ) + + # plt.tight_layout() + # return fig

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�{|4sX^vWG~r9mAo`tET#%uunhqT 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 literal 0 HcmV?d00001 diff --git a/pertpy/tools/_milo.py b/pertpy/tools/_milo.py index 90e97cab..3336b599 100644 --- a/pertpy/tools/_milo.py +++ b/pertpy/tools/_milo.py @@ -416,7 +416,11 @@ def da_nhoods( raise with localconverter(ro.default_converter + pandas2ri.converter + numpy2ri.converter): res = base.as_data_frame( - edgeR.topTags(edgeR.glmQLFTest(fit, contrast=mod_contrast), sort_by="none", n=np.inf) + edgeR.topTags( + edgeR.glmQLFTest(fit, contrast=mod_contrast), + sort_by="none", + n=np.inf, + ) ) else: with localconverter(ro.default_converter + numpy2ri.converter + pandas2ri.converter): @@ -438,7 +442,10 @@ def da_nhoods( design_df_filtered = design_df.iloc[keep_smp].copy() design_df_filtered = design_df_filtered.astype( - dict.fromkeys(design_df_filtered.select_dtypes(exclude=["number"]).columns, "category") + dict.fromkeys( + design_df_filtered.select_dtypes(exclude=["number"]).columns, + "category", + ) ) design_clean = design if design.startswith("~") else f"~{design}" @@ -475,7 +482,12 @@ def da_nhoods( res = stat_res.results_df res = res.rename( - columns={"baseMean": "logCPM", "log2FoldChange": "logFC", "pvalue": "PValue", "padj": "FDR"} + columns={ + "baseMean": "logCPM", + "log2FoldChange": "logFC", + "pvalue": "PValue", + "padj": "FDR", + } ) res = res[["logCPM", "logFC", "PValue", "FDR"]] @@ -862,7 +874,12 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 ordered = nhood_adata.obs.sort_values("abs_logFC", na_position="first").index nhood_adata = nhood_adata[ordered] - vmax = np.max([nhood_adata.obs["graph_color"].max(), abs(nhood_adata.obs["graph_color"].min())]) + vmax = np.max( + [ + nhood_adata.obs["graph_color"].max(), + abs(nhood_adata.obs["graph_color"].min()), + ] + ) vmin = -vmax fig = sc.pl.embedding( @@ -890,63 +907,80 @@ def plot_nhood_graph( # pragma: no cover # noqa: D417 plt.show() return None - from collections.abc import Sequence - from typing import Union - - def plot_nhood_annotation( # pragma: no cover + # In plot_nhood_annotation color_map, palette, and ax are not documented, and not part of common_plot_args + # Should I add them or will they be part of common_plot_args in the future? + @_doc_params(common_plot_args=doc_common_plot_args) + def plot_nhood_annotation( # pragma: no cover # noqa: D417 self, mdata: MuData, *, - # ------------------------------------------------------------------- - # Styling / filtering parameters for logFC‐based coloring: + adata_key: str = "milo", + annotation_key: str | None = "nhood_annotation", alpha: float = 0.1, min_logFC: float = 0.0, min_size: int = 10, plot_edges: bool = False, - title: str = "DA log‐Fold Change", + title: str = "DA log-Fold Change", color_map: Colormap | str | None = None, palette: str | Sequence[str] | None = None, ax: Axes | None = None, return_fig: bool = False, - # ------------------------------------------------------------------- - # New arguments: - adata_key: str = "milo", - annotation_key: str | None = "nhood_annotation", - # ------------------------------------------------------------------- **kwargs, ) -> Figure | None: - """Visualize Milo differential‐abundance results on the abstracted neighborhood graph. + """Visualize Milo differential-abundance results on the neighborhood graph. - By default (annotation_key=None), nodes are colored by filtered logFC (SpatialFDR ≤ alpha, - |logFC| ≥ min_logFC). If annotation_key is provided, instead draw node colors from - mdata[adata_key].obs[annotation_key]. + By default, neighborhoods are colored by filtered logFC (|logFC| ≥ `min_logFC` + and SpatialFDR ≤ `alpha`). If `annotation_key` is provided, this column from + `mdata[adata_key].obs` will be used instead for coloring. Args: - mdata: MuData object containing at least: - • mdata["milo"] (the Milo‐neighborhood AnnData, transposed) - • mdata[adata_key] (the AnnData where your annotation lives) - alpha: Significance threshold for SpatialFDR (only used if annotation_key is None). - min_logFC: Minimum absolute logFC to display (only used if annotation_key is None). - min_size: Scaling factor: actual marker size = Nhood_size × min_size. - plot_edges: If True, draw edges of the neighborhood overlap graph. - title: Plot title (ignored if annotation_key is not None; you can override if you like). - color_map: Passed through to sc.pl.embedding for discrete palettes (optional). - palette: Passed through to sc.pl.embedding (optional). - ax: Matplotlib Axes to plot on (optional). - return_fig: If True, return the Figure object instead of calling plt.show(). - - adata_key: Key in mdata corresponding to the AnnData whose `.obs` has the annotation. - Default = "rna". - - annotation_key: If not None, the name of a column in mdata[adata_key].obs whose values - should be used to color the Milo neighborhood graph. If provided, - we ignore all logFC / FDR logic and simply color by that annotation. - Example: "nhood_annotation". If None, revert to the original logFC‐based coloring. - - **kwargs: Additional keyword arguments passed to sc.pl.embedding. + mdata: A MuData object with: + - mdata["milo"]: Milo-neighborhood AnnData (transposed). + - mdata[adata_key]: AnnData containing annotation in `.obs`. + adata_key: Key for the AnnData within `mdata` that contains `.obs[annotation_key]`. + Defaults to "milo". + annotation_key: Name of the `.obs` column to use for coloring. If not None, + disables logFC-based coloring. Defaults to "nhood_annotation". + alpha: Significance threshold for SpatialFDR. Used only if `annotation_key` is None. + Defaults to 0.1. + min_logFC: Minimum absolute logFC to show. Used only if `annotation_key` is None. + Defaults to 0.0. + min_size: Scaling factor for node size. Actual size = `Nhood_size × min_size`. + Defaults to 10. + plot_edges: Whether to plot edges in the neighborhood overlap graph. + Defaults to False. + title: Title for the plot. Ignored if `annotation_key` is provided. + Defaults to "DA log-Fold Change". + color_map: Colormap to use for coloring. + palette: Name of Seaborn color palette for violinplots. + Defaults to pre-defined category colors for violinplots. + ax: Axes to plot on. + {common_plot_args} + **kwargs: Additional keyword arguments to pass directly to `scanpy.pl.embedding`. Returns: - If return_fig == True → returns the matplotlib Figure. Otherwise, shows the plot and returns None. + matplotlib.figure.Figure or None: The matplotlib Figure, if `return_fig` is True; + otherwise, displays the plot and returns None. + + Examples: + >>> import pertpy as pt + >>> import scanpy as sc + >>> adata = pt.dt.bhattacherjee() + >>> milo = pt.tl.Milo() + >>> mdata = milo.load(adata) + >>> sc.pp.neighbors(mdata["rna"]) + >>> sc.tl.umap(mdata["rna"]) + >>> milo.make_nhoods(mdata["rna"]) + >>> mdata = milo.count_nhoods(mdata, sample_col="orig.ident") + >>> milo.da_nhoods(mdata, + >>> design='~label', + >>> model_contrasts='labelwithdraw_15d_Cocaine-labelwithdraw_48h_Cocaine') + >>> milo.build_nhood_graph(mdata) + >>> milo.group_nhoods(mdata) + >>> milo.plot_nhood_annotation(mdata, annotation_key="nhood_groups") + + Preview: + .. image:: /_static/docstring_previews/milo_nhood_annotation.png """ # ------------------------------------------------------------------- # 1) Extract and copy the Milo neighborhood AnnData: @@ -998,6 +1032,7 @@ def plot_nhood_annotation( # pragma: no cover palette=palette, ax=ax, show=False, + return_fig=return_fig, **kwargs, ) @@ -1029,7 +1064,12 @@ def plot_nhood_annotation( # pragma: no cover nhood_adata = nhood_adata[ordered] # Determine symmetric color limits: - vmax = np.nanmax([nhood_adata.obs["graph_color"].max(), -nhood_adata.obs["graph_color"].min()]) + vmax = np.nanmax( + [ + nhood_adata.obs["graph_color"].max(), + -nhood_adata.obs["graph_color"].min(), + ] + ) vmin = -vmax # Finally, call scanpy to draw the embedding: @@ -1049,6 +1089,7 @@ def plot_nhood_annotation( # pragma: no cover palette=palette, ax=ax, show=False, + return_fig=return_fig, **kwargs, ) @@ -1236,7 +1277,12 @@ def plot_da_beeswarm( # pragma: no cover # noqa: D417 orient="h", alpha=0.5, ) - plt.legend(loc="upper left", title=f"< {int(alpha * 100)}% SpatialFDR", bbox_to_anchor=(1, 1), frameon=False) + plt.legend( + loc="upper left", + title=f"< {int(alpha * 100)}% SpatialFDR", + bbox_to_anchor=(1, 1), + frameon=False, + ) plt.axvline(x=0, ymin=0, ymax=1, color="black", linestyle="--") if return_fig: @@ -1326,26 +1372,30 @@ def _group_nhoods_from_adjacency( merge_discord: bool = False, overlap: int = 1, max_lfc_delta: float | None = None, - subset_nhoods=None, + subset_nhoods: list | np.ndarray | None = None, ) -> np.ndarray: - """Core neighborhood‐grouping logic (vectorized, no Python loops). - - Inputs: - - adjacency: scipy.sparse square matrix of shape (N, N), - storing neighborhood adjacency (overlap counts). - - da_res: pandas.DataFrame, length N, with columns 'SpatialFDR' and 'logFC'. - - is_da: 1‐D boolean array of length N, True where da_res.SpatialFDR < cutoff. - - merge_discord: if False, zero edges between DA‐pairs with opposite logFC sign. - - overlap: integer threshold; zero edges with weight < overlap. - - max_lfc_delta: if not None, zero edges whose |logFC[i] - logFC[j]| > max_lfc_delta. - - subset_nhoods: None or one of: - • boolean mask (length N), - • list/array of integer indices, - • list/array of string names (matching da_res.index). + """Group neighborhoods using filtered adjacency and Louvain clustering. + + Filters the neighborhood adjacency matrix based on overlap, DA agreement, + and logFC similarity, then performs Louvain clustering on the resulting graph. + + Args: + adjacency: Sparse square matrix (shape: N × N) containing overlap counts between neighborhoods. + da_res: DataFrame of shape (N,), containing columns "SpatialFDR" and "logFC". + is_da: Boolean array of length N; True where a neighborhood is differentially abundant. + merge_discord: If False, remove edges between DA neighborhoods with opposite logFC signs. + Defaults to False. + overlap: Minimum overlap count required to retain an edge. Defaults to 1. + max_lfc_delta: If set, removes edges where the absolute difference in logFC exceeds this threshold. + Defaults to None (no filtering). + subset_nhoods: Optional subsetting of neighborhoods. Can be one of: + - Boolean mask of length N + - List/array of integer indices + - List/array of neighborhood names matching `da_res.index` Returns: - - labels: NumPy array of dtype string, length = (# of neighborhoods after subsetting), - giving a Louvain cluster label for each neighborhood (in the same order as da_res). + np.ndarray: Array of string cluster labels, of length equal to the number of selected neighborhoods. + These correspond to rows of `da_res` after subsetting. """ # 1) Optional subsetting of neighborhoods --------------------------------------------------- # We allow subset_nhoods to be a boolean mask, a list of integer indices, or a list of names. @@ -1436,9 +1486,6 @@ def _group_nhoods_from_adjacency( # 8) Build an igraph from the final adjacency -------------------------------------------------------------------------------- # We can use scanpy’s utility to convert a sparse (0/1) matrix to igraph. - # Issue with dematrix after subsetting adjacency matrix: - # dematrix in sc._utils.get_igraph_from_adjacency does not convert to dense numpy matrix. - # Trying direct conversion to igraph: g = sc._utils.get_igraph_from_adjacency(pruned_adj, directed=False) # 9) Run Louvain (multilevel) clustering on the unweighted graph ---------------------------------------------------------------- @@ -1460,7 +1507,7 @@ def group_nhoods( max_lfc_delta: float | None = None, merge_discord: bool = False, subset_nhoods=None, - ) -> pd.DataFrame: + ) -> None: """Python equivalent of MiloR’s groupNhoods(), using AnnData and its `varp["nhood_connectivities"]`. Parameters @@ -1483,10 +1530,10 @@ def group_nhoods( If provided, only cluster that subset of neighborhoods. Returns: - ------- - pd.DataFrame - A copy of `adata.var`, with a new column "nhood_groups" of dtype string giving each - neighborhood’s cluster label (or `pd.NA` if it wasn’t in `subset_nhoods`). + None: The function modifies `adata` in place by adding the column + `"nhood_groups"` to `adata.var`, containing the cluster labels for + each neighborhood. Neighborhoods not included in `subset_nhoods` are + assigned `pd.NA`. Examples: @@ -1582,7 +1629,33 @@ def group_nhoods( adata.var["nhood_groups"] = out - def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_groups", subset_nhoods=None): + def _nhood_labels_to_cells_last_wins( + self, + mdata: MuData, + nhood_group_obs: str = "nhood_groups", + subset_nhoods: list | np.ndarray | None = None, + ) -> None: + """Map neighborhood group labels back to single cells (last group wins). + + Assigns a neighborhood group label to each cell based on the neighborhoods + it belongs to. If a cell belongs to multiple neighborhoods with different + labels, the first non-missing label (by category order) is used. Operates + in-place on `mdata["rna"].obs["nhood_groups"]`. + + Args: + mdata: MuData object with: + - mdata["milo"]: contains `.var[nhood_group_obs]` and neighborhood indices. + - mdata["rna"]: must have `.obsm["nhoods"]` sparse binary matrix of shape (cells × neighborhoods). + nhood_group_obs: Column name in `mdata["milo"].var` holding the neighborhood group labels. + Must be categorical or convertible to categorical. Defaults to "nhood_groups". + subset_nhoods: Optional subset of neighborhood indices to consider. Can be: + - A boolean mask, + - A list/array of integer indices, + - A list/array of string IDs matching `mdata["milo"].var.index`. + + Returns: + None: The results are written to `mdata["rna"].obs["nhood_groups"]` in place. + """ nhood_mat = mdata["rna"].obsm["nhoods"] da_res = mdata["milo"].var.copy() @@ -1647,17 +1720,52 @@ def _nhood_labels_to_cells_last_wins(self, mdata, nhood_group_obs: str = "nhood_ mdata["rna"].obs["nhood_groups"] = pd.NA mdata["rna"].obs.loc[fake_meta.CellID.to_list(), "nhood_groups"] = fake_meta.Nhood_Group.to_numpy() - def _get_cells_in_nhoods(self, adata, nhood_ids): - """Get cells in neighbourhoods of interest, store the number of neighbourhoods for each cell in adata.obs['in_nhoods'].""" + def _get_cells_in_nhoods( + self, + adata: AnnData, + nhood_ids: np.ndarray | list, + ) -> None: + """Compute number of neighborhood memberships per cell and store in `.obs`. + + For the selected neighborhoods, calculates how many of them each cell belongs to. + Stores the result in `adata.obs["in_nhoods"]`. + + Args: + adata: AnnData object with `.obsm["nhoods"]`, a binary matrix of shape (cells × neighborhoods). + nhood_ids: List or array of neighborhood indices to include in the count. + + Returns: + None: The result is stored in-place in `adata.obs["in_nhoods"]`. + """ + if not isinstance(nhood_ids, np.ndarray): + nhood_ids = np.asarray(nhood_ids, dtype=int) in_nhoods = np.array(adata.obsm["nhoods"][:, nhood_ids.astype("int")].sum(1)) adata.obs["in_nhoods"] = in_nhoods def _nhood_labels_to_cells_exclude_overlaps( self, - mdata, + mdata: MuData, nhood_group_obs: str = "nhood_groups", min_n_nhoods: int = 3, - ): + ) -> None: + """Assign cells to a dominant neighborhood group, excluding ambiguous overlaps. + + For each neighborhood group, compute how many neighborhoods each cell belongs to. + Then, assign each cell to the group with the most memberships, if that count exceeds + `min_n_nhoods`. All other cells are left unassigned (NaN). + + Args: + mdata: MuData object with: + - `mdata["milo"].var[nhood_group_obs]`: categorical group labels for neighborhoods. + - `mdata["rna"].obsm["nhoods"]`: binary matrix (cells × neighborhoods) indicating memberships. + nhood_group_obs: Name of the column in `mdata["milo"].var` containing group labels. + Defaults to "nhood_groups". + min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to + in order to be assigned. Defaults to 3. + + Returns: + None: Results are written in-place to `mdata["rna"].obs["nhood_groups"]`. + """ groups = mdata["milo"].var[nhood_group_obs].dropna().unique() for g in groups: nhoods_oi = mdata["milo"].var_names[mdata["milo"].var[nhood_group_obs] == g] @@ -1669,7 +1777,8 @@ def _nhood_labels_to_cells_exclude_overlaps( mdata["rna"].obs["nhood_groups"] = mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]].idxmax(1) ## Keep only if cell is in at least min_n_nhoods nhoods of the same group mdata["rna"].obs.loc[ - ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), "nhood_groups" + ~(mdata["rna"].obs[[f"in_nhoods_{g}" for g in groups]] > min_n_nhoods).any(axis=1), + "nhood_groups", ] = np.nan ### Remove the in_nhoods in nhood_groups columns mdata["rna"].obs["nhood_groups"] = ( @@ -1685,21 +1794,28 @@ def annotate_cells_from_nhoods( min_n_nhoods: int = 3, mode: Literal["last_wins", "exclude_overlaps"] = "last_wins", ) -> None: - """Annotate cells with neighborhood group labels. - - Parameters: - ----------- - mdata: MuData object with 'milo' modality. - nhood_group_obs: Column in `mdata["milo"].var` to use for neighborhood group labels. - subset_nhoods: List of neighborhood IDs to consider. If None, all neighborhoods are used. - min_n_nhoods: Minimum number of neighborhoods a cell must belong to in order to be annotated. Used for mode "exclude_overlaps". - mode: Mode for annotation. Options are: - - "last_wins": Last neighborhood label wins, adapted from miloR. - - "exclude_overlaps": Exclude overlaps, keeping only the most representative cells within groups. + """Assign neighborhood group labels to cells based on neighborhood membership. + + This function annotates cells in `mdata["rna"].obs` using group labels from + `mdata["milo"].var[nhood_group_obs]`. Supports two modes for resolving overlaps: + - "last_wins": Assign the last matching group label (default; mimics MiloR behavior). + - "exclude_overlaps": Assign only if the cell belongs to a minimum number of neighborhoods + from a single group. + + Args: + mdata: MuData object with: + - `mdata["milo"].var[nhood_group_obs]`: categorical group labels. + - `mdata["rna"].obsm["nhoods"]`: binary matrix of cell–neighborhood memberships. + nhood_group_obs: Column name in `mdata["milo"].var` with group labels. Defaults to "nhood_groups". + subset_nhoods: Optional list of neighborhood IDs to restrict annotation. If None, all neighborhoods are used. + min_n_nhoods: Minimum number of neighborhoods from the same group a cell must belong to in order to be assigned + (only used in mode `"exclude_overlaps"`). Defaults to 3. + mode: Strategy for resolving overlapping group assignments. One of: + - `"last_wins"`: Assign label from last matching neighborhood. + - `"exclude_overlaps"`: Assign only if group dominates cell’s memberships. Returns: - -------- - None: Modifies `mdata["rna"].obs` in place, adding a column `nhood_groups` with the assigned labels. + Updates `mdata["rna"].obs["nhood_groups"]` with the assigned labels in place. Examples: >>> import pertpy as pt @@ -1778,13 +1894,37 @@ def _run_edger_contrasts( baseline: str | None = None, subset_samples: list[str] | None = None, ) -> pd.DataFrame: - """Run edgeR QLF tests on a pseudobulk AnnData. + """Run edgeR QLF tests on pseudobulk data using specified contrasts. - If `group_to_compare` and `baseline` are both provided, performs exactly that two‐level contrast. - Otherwise, loops one‐vs‐rest over all levels of pdata.obs[nhood_group_obs]. + Performs differential expression analysis using edgeR's quasi-likelihood + F-tests on pseudobulked expression data. Supports either a user-specified + two-level contrast (`baseline` vs `group_to_compare`), or one-vs-rest testing + across all groups in `pdata.obs[nhood_group_obs]`. - Returns a pandas DataFrame with columns: - ["variable", "logFC", "PValue", "adj_PValue"] (plus "group" if one‐vs‐rest). + Args: + pdata: AnnData object with pseudobulked expression data in `.X` and + sample-level annotations in `.obs`. + nhood_group_obs: Name of the `.obs` column used to define group membership for contrast. + formula: R-style design formula (e.g., `"~ group"`). Used to generate design matrices in edgeR. + group_to_compare: Name of the group to compare (e.g., `"treated"`). + If provided along with `baseline`, a two-group test is run. + baseline: Reference group (e.g., `"control"`) for the two-group contrast. + subset_samples: Optional list of sample names to subset `pdata` before analysis. + + Returns: + pd.DataFrame: Differential expression results with columns: + - `"variable"`: gene/feature name + - `"log_fc"`: log-fold change estimate + - `"p_value"`: raw p-value + - `"adj_p_value"`: multiple-testing corrected p-value + - `"group"` (optional): group name (only present in one-vs-rest mode) + + Raises: + ValueError: If contrast groups are not present in the data or input is malformed. + + Example: + >>> de_df = milo._run_edger_contrasts(pdata, "condition", formula="~ condition", + >>> group_to_compare="treated", baseline="control") """ if not _is_counts(pdata.X): raise ValueError("`pdata.X` appears to be raw counts, but this function expects continuous expression.") @@ -1826,7 +1966,8 @@ def _run_edger_contrasts( if group_to_compare is not None and baseline is not None: # If a specific two‐level contrast was given, subset to those samples only sample_obs[nhood_group_obs] = pd.Categorical( - sample_obs[nhood_group_obs].values, categories=[baseline, group_to_compare] + sample_obs[nhood_group_obs].values, + categories=[baseline, group_to_compare], ) with localconverter(ro.default_converter + pandas2ri.converter): @@ -1897,7 +2038,13 @@ def _run_edger_contrasts( with localconverter(ro.default_converter + pandas2ri.converter): top_df_sub = pandas2ri.rpy2py(top_sub) - top_df_sub = top_df_sub.rename(columns={"FDR": "adj_p_value", "PValue": "p_value", "logFC": "log_fc"}) + top_df_sub = top_df_sub.rename( + columns={ + "FDR": "adj_p_value", + "PValue": "p_value", + "logFC": "log_fc", + } + ) top_df_sub = top_df_sub.reset_index().rename(columns={"index": "variable"}) top_df_sub["group"] = grp @@ -1918,45 +2065,47 @@ def _run_pydeseq2_contrasts( alpha: float = 0.05, quiet: bool = True, ) -> pd.DataFrame: - """Run PyDESeq2 on a pseudobulk AnnData (`pdata`) with a given neighborhood grouping, using exactly the design `formula` you supply. - - Parameters - ---------- - pdata : AnnData - Pseudobulk AnnData, where .obs[nhood_group_obs] is a categorical allowing - you to compare levels. + """Run PyDESeq2 differential testing on pseudobulked AnnData using a design formula. - nhood_group_obs : str - The column name in pdata.obs that holds the neighborhood groups. + Supports either a two-level contrast (`group_to_compare` vs `baseline`) or one-vs-rest + comparisons for all levels of a categorical column in `.obs`. Results are returned + as a tidy `DataFrame` compatible with downstream analysis. - formula : str - An R‐style design formula, e.g. "~ batch + Nhood_Group". Must include - `nhood_group_obs` as one of the terms. This is used verbatim for both the - single‐contrast and one‐vs‐rest calls. - - group_to_compare : Optional[str] - If non‐None (and `baseline` is also non‐None), run only the single contrast - [nhood_group_obs, group_to_compare, baseline] with design = `formula`. - - baseline : Optional[str] - If non‐None (and `group_to_compare` is non‐None), run only that one contrast. - If either is None, the function does a one‐vs‐rest loop over all levels of - pdata.obs[nhood_group_obs]. - - alpha : float, default=0.05 - Significance threshold passed to PyrDESeq2’s `DeseqStats`. - - quiet : bool, default=True - Whether to suppress PyDESeq2’s “DESeq2()” progress messages. + Args: + pdata: Pseudobulk `AnnData` object with expression matrix in `.X` and + covariates in `.obs`, including `nhood_group_obs`. + nhood_group_obs: Name of the `.obs` column to use for contrast groups. + formula: R-style design formula (e.g., `"~ batch + group"`), passed directly to PyDESeq2. + group_to_compare: Name of the group to test against `baseline`. If None, + one-vs-rest mode is triggered. + baseline: Name of the baseline group for contrast. Must be specified if `group_to_compare` is given. + alpha: FDR threshold passed to PyDESeq2's `DeseqStats`. Defaults to 0.05. + quiet: If True, suppresses progress messages from PyDESeq2. Defaults to True. Returns: - ------- - pd.DataFrame - If `group_to_compare` and `baseline` are provided: a DataFrame with columns - ["variable","log_fc","p_value","adj_p_value"], sorted by p_value. - - Otherwise (one‐vs‐rest): a concatenated DataFrame with those columns plus - a “group” column indicating which level was tested vs “rest.” + pd.DataFrame: If `group_to_compare` and `baseline` are specified, returns a + single contrast result with columns: + - `"variable"`: feature name + - `"log_fc"`: log2 fold change + - `"p_value"`: raw p-value + - `"adj_p_value"`: FDR-corrected p-value + + If no contrast is specified, performs one-vs-rest for each group and returns + a concatenated DataFrame with the same columns plus: + - `"group"`: the group tested against all others + + Raises: + ImportError: If `pydeseq2` is not installed. + ValueError: If only one of `group_to_compare` or `baseline` is provided. + + Example: + >>> de_df = milo._run_pydeseq2_contrasts( + ... pdata, + ... nhood_group_obs="condition", + ... formula="~ condition", + ... group_to_compare="treated", + ... baseline="control", + ... ) """ if find_spec("pydeseq2") is None: raise ImportError("pydeseq2 is required but not installed. Install with: pip install pydeseq2") @@ -2048,8 +2197,32 @@ def _run_pydeseq2_contrasts( final_df = pd.concat(all_results, ignore_index=True) return final_df - def _filter_by_expr_edger(self, pdata, formula, **kwargs): - """Filter genes in `pdata` based on expression criteria using edgeR.""" + def _filter_by_expr_edger( + self, + pdata: AnnData, + formula: str, + **kwargs, + ) -> None: + """Filter low-expressed genes from a pseudobulk AnnData object using edgeR. + + This function uses `edgeR::filterByExpr()` via rpy2 to identify and retain + genes with sufficient expression for differential testing, based on the + provided design formula and expression thresholds. + + The filtering is performed in-place by subsetting `pdata.var`. + + Args: + pdata: Pseudobulk `AnnData` object with raw counts in `.X` and + covariates in `.obs`. + formula: R-style design formula (e.g., `"~ condition + batch"`), used to + compute the design matrix in edgeR. + **kwargs: Additional keyword arguments passed to `edgeR::filterByExpr()`. + Examples include `min.count`, `min.total.count`, etc. + + Returns: + None: The function modifies `pdata` in place by subsetting `pdata.var` + to include only retained genes. + """ edger, _, rstats, rbase = self._setup_rpy2() import rpy2.robjects as ro from rpy2.robjects import numpy2ri, pandas2ri @@ -2068,7 +2241,31 @@ def _filter_by_expr_edger(self, pdata, formula, **kwargs): pdata._inplace_subset_var(keep) - def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6, **kwargs): + def _filter_highly_variable_scanpy( + self, + pdata: AnnData, + n_top_genes: int = 7500, + target_sum: float = 1e6, + **kwargs, + ) -> None: + """Filter highly variable genes from a pseudobulk AnnData using Scanpy. + + Normalizes and log-transforms raw count data if needed, then selects the + top `n_top_genes` most variable genes using `scanpy.pp.highly_variable_genes`. + Results are stored in-place by subsetting `pdata.var`. + + Args: + pdata: AnnData object with raw or normalized pseudobulk expression in `.X`. + n_top_genes: Number of top variable genes to retain. Defaults to 7500. + target_sum: Target total count for normalization (used only if `.X` is raw counts). + Defaults to 1e6. + **kwargs: Additional keyword arguments passed to `scanpy.pp.highly_variable_genes()`. + + Returns: + None: The function modifies `pdata` in place: + - Adds normalized expression to `pdata.layers["normalized"]` + - Filters `.var` to include only the top `n_top_genes` genes + """ if _is_counts(pdata.X): pdata.layers["normalized"] = pdata.X.copy() sc.pp.normalize_total( @@ -2082,7 +2279,29 @@ def _filter_highly_variable_scanpy(self, pdata, n_top_genes=7500, target_sum=1e6 sc.pp.highly_variable_genes(pdata, layer="normalized", n_top_genes=n_top_genes, subset=True, **kwargs) - def _filter_highly_variable_scran(self, pdata, n_top_genes): + def _filter_highly_variable_scran( + self, + pdata: AnnData, + n_top_genes: int, + ) -> None: + """Filter highly variable genes using R's scran and scuttle packages. + + If `pdata.X` contains raw counts, normalization is performed using + `logNormCounts()` from `scuttle`. Otherwise, the matrix is assumed + to be already log-normalized. + + The top `n_top_genes` most variable genes are selected using + `scran.modelGeneVar()` and `scran.getTopHVGs()` and used to subset + `pdata.var` in place. + + Args: + pdata: AnnData object containing pseudobulk expression matrix. + n_top_genes: Number of top highly variable genes to retain. + + Returns: + None: The function modifies `pdata` in place by subsetting `.var` + to contain only the selected HVGs. + """ scran = self._try_import_bioc_library("scran") scuttle = self._try_import_bioc_library("scuttle") singlecellexperiment = self._try_import_bioc_library("SingleCellExperiment") @@ -2135,57 +2354,49 @@ def find_nhood_group_markers( alpha: float = 0.05, use_eb: bool = False, **kwargs, - ): - """Perform differential expression analysis on neighborhood groups in a MuData object. + ) -> pd.DataFrame: + """Perform differential expression analysis on neighborhood groups in a MuData or AnnData object. - The MuData object must contain a modality with the name `key`, which is used for pseudobulk aggregation. - The column `nhood_group_obs` in `mdata[key]` must contain the neighborhood group labels, and `sample_col` must contain the sample labels. - Neighborhood group labels can be assigned to the single-cell data using ´milo.group_nhoods(...)`, or manually set in `mdata[key].obs[nhood_group_obs]`. - Neighborhood group labels must be strings or categorical values and are used for pseudobulk aggregation. - If both `group_to_compare` and `baseline` are given, runs exactly that contrast. Otherwise, runs one‐vs‐rest for every level of `nhood_group_obs`. - All NAs in mdata[key].obs[nhood_group_obs] are filtered out before running the analysis. - Therefore, if annotating nhood_group_obs manually, introducing NAs before Milo().group_nhoods(...) is can exclude unwanted neighborhoods from the analysis. + This function performs pseudobulk aggregation over neighborhood groupings and tests for differential + expression (DE) between groups using either `pydeseq2` or `edgeR`. - Parameters - ---------- - mdata : MuData - A MuData object containing the data. Must have a modality with the name `key`. - group_to_compare : Optional[str] - If provided, runs a single contrast comparing this group to `baseline`. - baseline : Optional[str] - The reference group for the contrast. Must be provided if `group_to_compare` is provided. - nhood_group_obs : str, default="nhood_groups" - The name of the column in `adata.obs` that contains the neighborhood group labels. - sample_col : str, default="sample" - The name of the column in `adata.obs` that contains the sample labels. - covariates : Collection[str] | None, default=None - A collection of additional covariates to include in the design formula. - If None, no additional covariates are used. - key : str, default="rna" - The key in `mdata` that corresponds to the modality to be used for pseudobulk aggregation. - pseudobulk_function : str, default="sum" - The function to use for pseudobulk aggregation. Can be "sum" or "mean". - layer : str | None, default=None - If provided, the layer to use for pseudobulk aggregation. If None, uses the default layer. - target_sum : float, default=1e6 - The target sum for normalization when using the "scanpy" filter method. - n_top_genes : int, default=7500 - The number of top variable genes to retain after filtering. Only used if `filter_method` is `scanpy` `scran`. - filter_method : str | None, default="scanpy" - The method to use for filtering highly variable genes. Can be "scanpy", "scran", or "filterByExpr". - If None, no filtering is applied. - var_names : Collection[str] | None, default=None - A collection of variable names to restrict the analysis to. If None, all variables are used. - de_method : Literal["pydeseq2", "statsmodels", "edgeR", "limma"], default="pydeseq2" - The method to use for differential expression analysis. Can be "pydeseq2", "statsmodels", "edgeR", or "limma". - quiet : bool, default=True - If True, suppresses output messages from pydeseq2. - alpha : float, default=0.05 - The significance threshold for differential expression analysis in pydeseq2. - use_eb : bool, default=False - If True, applies empirical Bayes moderation to the results in statsmodels. Not for serious use, but a starting point for limma-like differential testing in pure Python. - **kwargs : dict - Additional keyword arguments passed to the filtering methods or differential expression methods. + The MuData must contain a modality (default `"rna"`) used for pseudobulk aggregation. + Group labels must be stored in `nhood_group_obs`, and sample labels in `sample_col`. + + If both `group_to_compare` and `baseline` are provided, a specific two-group contrast is tested. + Otherwise, one-vs-rest DE is performed for each level in `nhood_group_obs`. + + Notes: + - All NAs in `nhood_group_obs` are removed before pseudobulk aggregation. + - If annotating neighborhood groups manually, you can introduce NAs beforehand to exclude neighborhoods. + + Args: + data: A `MuData` or `AnnData` object. + group_to_compare: The group to compare (e.g. case) in a specific contrast. Must be in `nhood_group_obs`. + baseline: The baseline group (e.g. control). Must be in `nhood_group_obs` if `group_to_compare` is given. + nhood_group_obs: Column in `.obs` with neighborhood group labels. Must be categorical or string-typed. + sample_col: Column in `.obs` specifying sample identifiers. + covariates: Optional list of covariates to include in the DE model formula. + key: Name of modality in `MuData` used for pseudobulk aggregation (default `"rna"`). + pseudobulk_function: Aggregation function used for pseudobulk (either `"sum"` or `"mean"`). + layer: Optional layer to use for aggregation. Defaults to `X` if not provided. + target_sum: Used for Scanpy-based normalization when filtering (default: `1e6`). + n_top_genes: Number of highly variable genes to retain (if filtering is applied). + filter_method: How to filter genes before DE analysis. One of `"scanpy"`, `"scran"`, or `"filterByExpr"`. + var_names: Optional list of variable (gene) names to restrict analysis to. Overrides filtering if provided. + de_method: Differential expression method: `"pydeseq2"` (default) or `"edger"`. + quiet: Whether to suppress console output from PyDESeq2 (default: True). + alpha: Significance threshold passed to DE test (used in PyDESeq2). + use_eb: If `True`, applies empirical Bayes shrinkage (not implemented yet, reserved for future limma-style methods). + **kwargs: Additional arguments passed to filtering or DE methods (e.g., `min_expr`, `min_total` for edgeR filtering). + + Returns: + pd.DataFrame: DE results with columns: + - "variable": Gene/feature name + - "log_fc": log2 fold change + - "p_value": Unadjusted p-value + - "adj_p_value": Multiple testing-corrected p-value + - "group": (only for one-vs-rest) the group being compared vs rest Examples: >>> import pertpy as pt @@ -2525,7 +2736,10 @@ def plot_heatmap_with_dot_and_colorbar( smap.set_array([]) cbar = fig.colorbar( - smap, cax=ax_cbar, orientation="vertical", ticks=np.linspace(vmin, vmax, num=cbar_tick_count) + smap, + cax=ax_cbar, + orientation="vertical", + ticks=np.linspace(vmin, vmax, num=cbar_tick_count), ) cbar.ax.tick_params(labelsize=8, length=4, width=1) cbar.ax.set_title("Mean\nExpr.", fontsize=8, pad=6) From 4789255fba23d3eb40e8f838bfc10d85c72b08d2 Mon Sep 17 00:00:00 2001 From: MaximilianNuber Date: Mon, 16 Jun 2025 09:49:27 +0200 Subject: [PATCH 08/10] Revert "Updated doc strings and common_plot_args in plot_nhood_annotation" This reverts commit 5a303075bbbf28369524768643b37eea3cbdc881. --- .../milo_nhood_annotation.png | Bin 336759 -> 0 bytes pertpy/tools/_milo.py | 584 ++++++------------ 2 files changed, 185 insertions(+), 399 deletions(-) delete mode 100644 docs/_static/docstring_previews/milo_nhood_annotation.png diff --git a/docs/_static/docstring_previews/milo_nhood_annotation.png b/docs/_static/docstring_previews/milo_nhood_annotation.png deleted file mode 100644 index eb1cdb6261783d8d2114ae9e8ba418644c1aafc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336759 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 z 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%0DG0-)@EBDI#*O;-3->`;i-RIIxpiS=p8QDJ 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