Source code for nispace.workflows

import numpy as np
import pandas as pd
from nilearn.plotting import plot_design_matrix
import matplotlib.pyplot as plt

import logging
lgr = logging.getLogger(__name__)
from . import NiSpace
from .utils.utils import set_log
from .core.constants import _PARC_DEFAULT, _COLOC_METHODS, _SPACE_DEFAULT_VOL
from .datasets import fetch_reference, reference_lib, _check_parcellation

_DEPR_POOLED_P = (
    "'p_from_average_y' is deprecated and will be removed in the first "
    "non-dev release. Use 'pooled_p' instead."
)
_DEPR_RETURN_TUPLE = (
    "Returning a tuple (colocs, p_values, pc_values, nsp) from workflow functions is "
    "deprecated and will be removed in the first non-dev release. "
    "Set 'return_nispace_only=True' and use 'nsp.get_colocalizations()' and "
    "'nsp.get_p_values()' to access results."
)
_DEPR_FUNC_NAME = (
    "'{old}' is deprecated and will be removed in the first non-dev release. "
    "Use '{new}()' instead."
)


def _workflow_base(x, y, z, x_collection, #x_load_nulls,
                   space,
                   data_space,
                   parcellation_space,
                   parcellation, parcellation_labels,
                   parcellation_hemi,
                   standardize,
                   colocalization_method,
                   n_proc, verbose,
                   nispace_object,
                   fetch_x_kwargs,
                   init_kwargs,
                   fit_kwargs,
                   ):
    """Base workflow for colocalization, group comparison, and GSEA.
    Will load X data, initialize NiSpace object """
    
    status = {fun: False for fun in ["init", "fit"]}
    null_maps = None

    # check colocalization method
    if isinstance(colocalization_method, (list, tuple)):
       if not all(method in _COLOC_METHODS for method in colocalization_method):
           raise lgr.critical_raise("'colocalization_method' must be one or a list of "
                                    f"{list(_COLOC_METHODS.keys())} not {colocalization_method}!",
                                    ValueError)
    else:
        raise lgr.critical_raise("'colocalization_method' must be a string or a list of strings!",
                                 TypeError)
        
    # check if nispace object provided
    if nispace_object is not None:
        lgr.info("NiSpace object provided. Validating.")
        nsp = nispace_object
        if isinstance(nispace_object, NiSpace):
            if nsp._check_fit():
                lgr.info("Fitted NiSpace object provided, ignoring 'x', 'y', and 'z'.")
                status["init"] = True
                status["fit"] = True
            else:
                lgr.info("NiSpace object provided but .fit() was not run. Running.")
                status["init"] = True
        else:
            lgr.critical_raise(f"Argument 'nispace_object' must be of type NiSpace not {type(nsp)}!")
            
    # space: data_space and parcellation_space default to the shared space arg
    data_space = space if not data_space else data_space
    parcellation_space = space if not parcellation_space else parcellation_space

    ## INIT
    if not status["init"]:

        # resolve integrated parcellation name (needed for fetch_reference below)
        parc_integrated = None
        if isinstance(parcellation, str):
            parc_integrated = _check_parcellation(parcellation, force_str=True, raise_not_found=False)

        # y
        if y is None:
            lgr.error("You must provide 'y' data: (list) of volumetric/surface or pre-parcellated data!")

        # x
        if isinstance(x, str):
            x = x.lower()
            if x in reference_lib:
                lgr.info(f"Loading integrated {x} dataset as X data.")
                if x_collection is None or not isinstance(x_collection, str):
                    x_collection = reference_lib[x].get("default_collection")
                    if x_collection is not None:
                        lgr.info(f"Using default collection '{x_collection}'.")
                fetch_x_kwargs = dict(
                    dataset=x,
                    collection=x_collection,
                    standardize_parcellated=False,
                    parcellation=parc_integrated,
                    hemi=parcellation_hemi,
                    verbose=verbose
                ) | fetch_x_kwargs
                x = fetch_reference(**fetch_x_kwargs)
                if isinstance(x, tuple):
                    x, null_maps = x
                else:
                    null_maps = None
            else:
                lgr.error(f"'x' must be one of: '{list(reference_lib.keys())}' not '{x}'!")
        else:
            null_maps = None

        # init — pass parcellation as-is; api.fit() resolves integrated names and spaces
        init_kwargs = dict(
            x=x,
            y=y,
            z=z,
            standardize=standardize,
            parcellation=parcellation,
            parcellation_labels=parcellation_labels,
            parcellation_hemi=parcellation_hemi,
            parcellation_space=parcellation_space,
            data_space=data_space,
            n_proc=n_proc,
            verbose=verbose,
            return_self=True,
        ) | init_kwargs
        nsp = NiSpace(**init_kwargs)
    
    ## FIT
    if not status["fit"]:
        nsp.fit(**fit_kwargs)
        status["fit"] = True
        
    ## RETURN status, NiSpace object, pre-loaded nulls
    return status, nsp, null_maps
       
       
[docs]def colocalization(y, x="PET", z=None, x_collection=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method=None, mc_method="meff", normalize_colocalizations=True, pooled_p=False, p_from_average_y=None, # TODO (first non-dev release): remove plot=True, combat=False, binary_y=False, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Colocalization workflow. Parameters ---------- y : array-like or pandas DataFrame or list Input Y data to colocalize with X. Can be a numpy array, pandas DataFrame, (list of) path(s) to a file(s) or list of image objects. x : str or array-like, default="PET" Input X data. Can be a string indicating a reference dataset ("PET", "mRNA", ...), or input types as listed for y. z : array-like or None, default=None Optional confound data to regress out. Can be "gm", or input types as listed for y. x_collection : str or None, default=None If x is a string reference dataset, specifies which collection to use. standardize : str, default="xz" Which data to standardize. Can contain "x", "y", and/or "z". space : str, default=_SPACE_DEFAULT_VOL ("MNI152NLin6Asym") Default template space for both the data images and the parcellation. Used to resolve ``data_space``/``parcellation_space`` when those are not given. data_space : str or None, default=None Template space of the input data images. Falls back to ``space`` if falsy. parcellation_space : str or None, default=None Template space of the parcellation. Falls back to ``space`` if falsy. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. Can be a string name or integer ID. parcellation_labels : array-like or None, default=None Optional labels for the parcellation regions. parcellation_hemi : list of str, default=["L", "R"] Hemispheres to include. Forwarded to ``NiSpace`` initialization and, if ``x`` is a reference dataset string, to :func:`~nispace.datasets.fetch_reference`. y_covariates : array-like or None, default=None Optional covariates to regress from Y data. If given, :meth:`NiSpace.clean_y` is run with ``how="between"`` before colocalization. colocalization_method : str or list, default=None Method(s) to use for colocalization. When ``None``, defaults to ``"pearson"`` if ``binary_y=True``, otherwise ``"spearman"``. See :meth:`NiSpace.colocalize` for the full list of supported methods. mc_method : str or list, default="meff" Multiple-comparisons correction method(s), forwarded to :meth:`NiSpace.correct_p`. If a list, each method is applied and stored separately. An explicit ``"mc_method"`` key inside ``correct_p_kwargs`` overrides this entirely. normalize_colocalizations : bool, default=True Whether to call :meth:`NiSpace.normalize_colocalizations` after correction (z-scores observed colocalizations against their null distribution). Failures are caught and logged as a warning rather than raised. pooled_p : str or bool, default=False How to aggregate across Y maps before computing p-values. ``False`` (default) computes one p-value per Y×X pair. ``"mean"`` or ``"median"`` averages colocalizations across Y maps first and returns one p-value per X map. ``"auto"`` uses ``False`` for a single Y map and ``"mean"`` otherwise. p_from_average_y : str or bool, optional Deprecated. Use ``pooled_p`` instead. plot : bool, default=True Whether to generate visualization plots. combat : bool, default=False Whether to apply ComBat harmonization. Only relevant if ``y_covariates`` is given. binary_y : bool, default=False Set if Y is binary (e.g. binary lesion/cluster masks). Forces ``NiSpace(binary_y=True)``, which prevents Y from being z-scored regardless of ``standardize`` and drives the ``colocalization_method=None`` dynamic default toward ``"pearson"``. Not relevant to permutation here, since this function always permutes ``what="maps"`` (the ``binary_y`` restriction on ``permute(what="groups")`` only applies to :func:`group_colocalization`). n_perm : int, default=10000 Number of permutations for null distribution. seed : int or None, default=None Random seed for reproducibility. n_proc : int, default=1 Number of processes for parallel computation. verbose : bool, default=True Whether to print progress messages. nispace_object : NiSpace or None, default=None Optional pre-initialized NiSpace object to use. fetch_x_kwargs : dict, optional Additional arguments for fetching X data. init_kwargs : dict, optional Additional arguments for NiSpace initialization. fit_kwargs : dict, optional Additional arguments for ``NiSpace.fit()``. clean_y_kwargs : dict, optional Additional arguments for Y data cleaning. colocalize_kwargs : dict, optional Additional arguments for colocalization. permute_kwargs : dict, optional Additional arguments for permutation testing. correct_p_kwargs : dict, optional Additional arguments for p-value correction. plot_kwargs : dict, optional Additional arguments for plotting. return_nispace_only : bool, default=False If True, return only the NiSpace object. Use ``nsp.get_colocalizations()`` and ``nsp.get_p_values()`` to access results. Setting False is deprecated and will be removed in the first non-dev release. Returns ------- nsp : NiSpace The NiSpace object containing all results (when ``return_nispace_only=True``). colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False`` (current default). """ verbose = set_log(lgr, verbose) # TODO (first non-dev release): remove p_from_average_y parameter if p_from_average_y is not None: lgr.warning(_DEPR_POOLED_P) pooled_p = p_from_average_y # kwarg dicts fetch_x_kwargs = {} if fetch_x_kwargs is None else fetch_x_kwargs init_kwargs = {} if init_kwargs is None else dict(init_kwargs) if binary_y: init_kwargs.setdefault("binary_y", True) if colocalization_method is None: colocalization_method = "pearson" if binary_y else "spearman" fit_kwargs = {} if fit_kwargs is None else fit_kwargs clean_y_kwargs = {} if clean_y_kwargs is None else clean_y_kwargs colocalize_kwargs = {} if colocalize_kwargs is None else colocalize_kwargs permute_kwargs = {} if permute_kwargs is None else permute_kwargs correct_p_kwargs = {} if correct_p_kwargs is None else correct_p_kwargs plot_kwargs = {} if plot_kwargs is None else plot_kwargs ## COMMON FUNCTIONS: COLOC METHOD VALIDATION, DATA LOADING, INIT, if isinstance(colocalization_method, str): colocalization_method = [colocalization_method] status, nsp, null_maps = _workflow_base( x=x, y=y, z=z, x_collection=x_collection, space=space, data_space=data_space, parcellation_space=parcellation_space, #x_load_nulls=x_load_nulls, standardize=standardize, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=colocalization_method, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs ) status = status | {fun: False for fun in ["clean_y", "colocalize", "permute", "correct_p"]} ## CLEAN Y if not status["clean_y"] and y_covariates is not None: clean_y_kwargs = dict( how="between", covariates_between=y_covariates, combat=combat, ) | clean_y_kwargs nsp.clean_y(**clean_y_kwargs) status["clean_y"] = True ## COLOCALIZE # xsea must be same for colocalization and permutation if colocalize_kwargs.get("xsea", False) or permute_kwargs.get("xsea", False): colocalize_kwargs["xsea"] = True permute_kwargs["xsea"] = True if not status["colocalize"]: for method in colocalization_method: colocalize_kwargs_curr = dict( method=method, regress_z=True, ) | colocalize_kwargs nsp.colocalize(**colocalize_kwargs_curr) status["colocalize"] = True ## PERMUTE if not status["permute"]: for method in colocalization_method: permute_kwargs_curr = dict( what="maps", maps_which="X", maps_nulls=null_maps, method=method, pooled_p=pooled_p, n_perm=n_perm, seed=seed, ) | permute_kwargs nsp.permute(**permute_kwargs_curr) permuted = nsp._get_last(perm=None) status["permute"] = True ## CORRECT # normalize mc_method to list; explicit override inside correct_p_kwargs takes precedence mc_methods = ([mc_method] if isinstance(mc_method, str) else list(mc_method)) if "mc_method" in correct_p_kwargs: mc_methods = [correct_p_kwargs.pop("mc_method")] if not status["correct_p"]: for mc_m in mc_methods: nsp.correct_p(**{"mc_method": mc_m} | correct_p_kwargs) status["correct_p"] = True ## ZSCORE if normalize_colocalizations: try: nsp.normalize_colocalizations() except Exception as e: lgr.warning(f"normalize_colocalizations() failed: {e}") ## VIZ if plot: for method in colocalization_method: plot_kwargs_curr = dict( method=method, permute_what=permuted, ) | plot_kwargs nsp.plot(**plot_kwargs_curr) ## RETURN colocs = {method: nsp.get_colocalizations(method) for method in colocalization_method} p_values = {method: nsp.get_p_values(method, permuted) for method in colocalization_method} pc_values = { mc_m: {method: nsp.get_p_values(method, permuted, mc_method=mc_m) for method in colocalization_method} for mc_m in mc_methods } if len(colocalization_method) == 1: k = colocalization_method[0] colocs, p_values = colocs[k], p_values[k] pc_values = {mc_m: pc_values[mc_m][k] for mc_m in mc_methods} if len(mc_methods) == 1: pc_values = pc_values[mc_methods[0]] # TODO (first non-dev release): remove return_nispace_only parameter; always return nsp only; # remove colocs/p_values/pc_values construction block above and the if/else here if not return_nispace_only: lgr.warning(_DEPR_RETURN_TUPLE) return colocs, p_values, pc_values, nsp return nsp
[docs]def group_colocalization(y, design, x="PET", z=None, x_collection=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], colocalization_method="spearman", comparison_method=None, mc_method="meff", normalize_colocalizations=True, pooled_p=False, p_from_average_y=None, # TODO (first non-dev release): remove paired=False, plot_design_between=True, combat=False, plot=True, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, transform_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Group-comparison colocalization workflow. Compares Y maps between two groups of individual subjects/observations (e.g. patients vs. controls), reduces the comparison to a single effect-size map via :meth:`NiSpace.transform_y`, and colocalizes that map with X while testing significance via group-label permutation. Parameters ---------- y : array-like or pandas DataFrame or list Input Y data: one map per individual subject/observation (not group-level summary maps). Passed straight through to ``NiSpace.fit``. design : list, array-like, or pandas DataFrame Group (and, if ``paired=True``, subject) labels, one row per row of ``y`` (row count must match ``len(y)``, else raises ``ValueError``). Accepted forms: - 1-D list/array/Series: dummy-coded group labels. Raises ``ValueError`` if ``paired=True`` (a 1-D input cannot carry subject IDs). - 2-D ``ndarray``: columns ``["groups"(, "subjects"), V0, V1, ...]`` (subjects column only if ``paired=True``). - ``DataFrame``: must have a ``"groups"`` column (and a ``"subjects"`` column if ``paired=True``). Any columns beyond the mandatory group(+subject) column(s) are treated as Y covariates and automatically regressed out via :meth:`NiSpace.clean_y` (see ``clean_y_kwargs`` below). x : str or array-like, default="PET" Input X data. Can be a string indicating a reference dataset ("PET", "mRNA", ...), or input types as listed for y. z : array-like or None, default=None Optional confound data to regress out. Can be "gm", or input types as listed for y. x_collection : str or None, default=None If x is a string reference dataset, specifies which collection to use. standardize : str, default="xz" Which data to standardize. Can contain "x", "y", and/or "z". space : str, default=_SPACE_DEFAULT_VOL ("MNI152NLin6Asym") Default template space for both the data images and the parcellation. Used to resolve ``data_space``/``parcellation_space`` when those are not given. data_space : str or None, default=None Template space of the input data images. Falls back to ``space`` if falsy. parcellation_space : str or None, default=None Template space of the parcellation. Falls back to ``space`` if falsy. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. Can be a string name or integer ID. parcellation_labels : array-like or None, default=None Optional labels for the parcellation regions. parcellation_hemi : list of str, default=["L", "R"] Hemispheres to include. Forwarded to ``NiSpace`` initialization and, if ``x`` is a reference dataset string, to :func:`~nispace.datasets.fetch_reference`. colocalization_method : str or list, default="spearman" Method(s) to use for colocalization. Unlike :func:`colocalization`, this is a static default (no ``binary_y``-driven dynamic default) — this function does not support binary Y, since :meth:`NiSpace.transform_y` (always run here) and group-label permutation are both incompatible with ``binary_y=True``. See :meth:`NiSpace.colocalize` for the full list of supported methods. comparison_method : str or None, default=None Formula passed to :meth:`NiSpace.transform_y` to reduce Y to a single group-comparison effect-size map. When ``None``, defaults to ``"hedges(a,b)"`` if ``paired=False``, otherwise ``"pairedcohen(a,b)"``. This transform is then reused as ``Y_transform`` for colocalization, permutation, plotting, and result retrieval. mc_method : str or list, default="meff" Multiple-comparisons correction method(s), forwarded to :meth:`NiSpace.correct_p`. If a list, each method is applied and stored separately. An explicit ``"mc_method"`` key inside ``correct_p_kwargs`` overrides this entirely. normalize_colocalizations : bool, default=True Whether to call :meth:`NiSpace.normalize_colocalizations` after correction. Failures are caught and logged as a warning rather than raised. pooled_p : str or bool, default=False Present for signature symmetry with :func:`colocalization`, but **not a free choice here**: for group-label permutation (``what="groups"``), :meth:`NiSpace.permute` always answers a group-level question and forces ``pooled_p="mean"`` regardless of what is passed (with a warning on conflict). p_from_average_y : str or bool, optional Deprecated. Use ``pooled_p`` instead. paired : bool, default=False Whether groups are paired/matched by subject (e.g. pre/post, or matched case-control pairs). Governs ``design`` parsing rules, the dynamic default of ``comparison_method``, and is passed to :meth:`NiSpace.permute` as ``groups_paired``. plot_design_between : bool, default=True Whether to plot the between-subject design matrix (diagnostic only). Only takes effect when ``design`` has covariate columns that trigger :meth:`NiSpace.clean_y`. combat : bool, default=False Whether to apply ComBat harmonization. Only relevant when ``design`` has covariate columns that trigger :meth:`NiSpace.clean_y`. plot : bool, default=True Whether to generate visualization plots. n_perm : int, default=10000 Number of permutations for null distribution. seed : int or None, default=None Random seed for reproducibility. n_proc : int, default=1 Number of processes for parallel computation. verbose : bool, default=True Whether to print progress messages. nispace_object : NiSpace or None, default=None Optional pre-initialized NiSpace object to use. fetch_x_kwargs : dict, optional Additional arguments for fetching X data. init_kwargs : dict, optional Additional arguments for NiSpace initialization. fit_kwargs : dict, optional Additional arguments for ``NiSpace.fit()``. clean_y_kwargs : dict, optional Additional arguments for Y data cleaning. Auto-triggered based on ``design`` having covariate columns beyond ``"groups"``(+``"subjects"``) — unlike :func:`colocalization`, there is no separate ``y_covariates`` flag here. transform_y_kwargs : dict, optional Additional arguments for :meth:`NiSpace.transform_y`. Always runs (no conditional gate other than a pre-fitted ``nispace_object``). colocalize_kwargs : dict, optional Additional arguments for colocalization. permute_kwargs : dict, optional Additional arguments for permutation testing. Note ``what="groups"`` is forced last in the internal merge and cannot be overridden here. correct_p_kwargs : dict, optional Additional arguments for p-value correction. plot_kwargs : dict, optional Additional arguments for plotting. return_nispace_only : bool, default=False If True, return only the NiSpace object. Use ``nsp.get_colocalizations()`` and ``nsp.get_p_values()`` to access results. Setting False is deprecated and will be removed in the first non-dev release. Returns ------- nsp : NiSpace The NiSpace object containing all results (when ``return_nispace_only=True``). colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False`` (current default). """ verbose = set_log(lgr, verbose) # TODO (first non-dev release): remove p_from_average_y parameter if p_from_average_y is not None: lgr.warning(_DEPR_POOLED_P) pooled_p = p_from_average_y # kwarg dicts fetch_x_kwargs = {} if fetch_x_kwargs is None else fetch_x_kwargs init_kwargs = {} if init_kwargs is None else init_kwargs fit_kwargs = {} if fit_kwargs is None else fit_kwargs clean_y_kwargs = {} if clean_y_kwargs is None else clean_y_kwargs transform_y_kwargs = {} if transform_y_kwargs is None else transform_y_kwargs colocalize_kwargs = {} if colocalize_kwargs is None else colocalize_kwargs permute_kwargs = {} if permute_kwargs is None else permute_kwargs correct_p_kwargs = {} if correct_p_kwargs is None else correct_p_kwargs plot_kwargs = {} if plot_kwargs is None else plot_kwargs ## COMMON FUNCTIONS: DATA LOADING, INIT, YCOLOC METHOD VALIDATION if isinstance(colocalization_method, str): colocalization_method = [colocalization_method] status, nsp, _ = _workflow_base( x=x, y=y, z=z, x_collection=x_collection, #x_load_nulls=False, space=space, data_space=data_space, parcellation_space=parcellation_space, standardize=standardize, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=colocalization_method, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs ) status = status | {fun: False for fun in ["clean_y", "transform_y", "colocalize", "permute", "correct_p"]} ## DESIGN MATRIX HANDLING # ensure dtype and format # 1d if isinstance(design, (list, tuple)) or \ (isinstance(design, (np.ndarray, pd.Series)) and design.ndim==1): if paired: lgr.critical_raise("If paired==True, design must have two columns: 'group' and 'subjects'.", ValueError) else: lgr.info("1d array provided for design. Assuming this to be dummy-coded groups!") design = pd.DataFrame( {"groups": np.array(design)}, index=nsp._y_lab ) # 2darray elif isinstance(design, np.ndarray) and design.ndim==2: if paired: lgr.info("2d array provided for design with paired==True. Assuming first column " "to be group labels, second column to be subjects, and remaining to be covariates.") design = pd.DataFrame( design, columns=["groups", "subjects"] + [f"V{i}" for i in range(design.shape[1] - 2)], index=nsp._y_lab ) else: lgr.info("2d array provided for design. Assuming first column to be group labels, " "second column to be subjects.") design = pd.DataFrame( design, columns=["groups"] + [f"V{i}" for i in range(design.shape[1] - 1)], index=nsp._y_lab ) # dataframe elif isinstance(design, pd.DataFrame): lgr.info("DataFrame provided for design. Expecting 'groups' and, if paired==True, 'subjects' columns.") if paired: if "groups" not in design.columns or "subjects" not in design.columns: lgr.critical_raise("If a DataFrame is passed for design with paired==True, " "it must have a 'groups' and a 'subjects' column.", KeyError) else: if "groups" not in design.columns: lgr.critical_raise("If a DataFrame is passed for design, it must have a 'groups' column.", KeyError) # unrecognized type else: lgr.critical_raise("'design' must be a list, ndarray, Series, or DataFrame!", TypeError) # check dimensions lgr.info(f"Design matrix of shape {design.shape}. Assuming {design.shape[0]} subjects/maps.") if design.shape[0] != len(y): lgr.critical_raise(f"The number of rows in design matrix {design.shape[0]} must equal " f"the length of the y data {len(y)}!", ValueError) ## CLEAN Y if not status["clean_y"] and \ ((not paired and design.shape[1] > 1) or (paired and design.shape[1] > 2)): if not paired: y_covariates = design.iloc[:, 1:] # exclude groups combat_protect = design[["groups"]] else: y_covariates = design.iloc[:, 2:] # exclude groups and subjects combat_protect = design[["groups", "subjects"]] clean_y_kwargs = dict( how="between", covariates_between=y_covariates, protect=combat_protect, combat=combat, combat_protect=combat_protect if combat else None, plot_design_between=plot_design_between ) | clean_y_kwargs nsp.clean_y(**clean_y_kwargs) status["clean_y"] = True ## TRANSFORM if not status["transform_y"]: if comparison_method is None and not paired: comparison_method = "hedges(a,b)" elif comparison_method is None and paired: comparison_method = "pairedcohen(a,b)" transform_y_kwargs = dict( transform=comparison_method, groups=design["groups"], subjects=design["subjects"] if paired else None, ) | transform_y_kwargs nsp.transform_y(**transform_y_kwargs) status["transform_y"] = True ## COLOCALIZE if not status["colocalize"]: for method in colocalization_method: colocalize_kwargs_curr = dict( method=method, Y_transform=comparison_method, regress_z=True, verbose=verbose, ) | colocalize_kwargs nsp.colocalize(**colocalize_kwargs_curr) status["colocalize"] = True ## PERMUTE if not status["permute"]: for method in colocalization_method: permute_kwargs_curr = dict( method=method, Y_transform=comparison_method, groups_paired=paired, groups_strategy="shuffle", pooled_p=pooled_p, n_perm=n_perm, seed=seed, verbose=verbose, ) | permute_kwargs | {"what": "groups"} nsp.permute(**permute_kwargs_curr) permute_what = "groups" status["permute"] = True ## CORRECT mc_methods = ([mc_method] if isinstance(mc_method, str) else list(mc_method)) if "mc_method" in correct_p_kwargs: mc_methods = [correct_p_kwargs.pop("mc_method")] if not status["correct_p"]: for mc_m in mc_methods: nsp.correct_p(**{"mc_method": mc_m, "verbose": verbose} | correct_p_kwargs) status["correct_p"] = True ## ZSCORE if normalize_colocalizations: try: nsp.normalize_colocalizations() except Exception as e: lgr.warning(f"normalize_colocalizations() failed: {e}") ## VIZ if plot: for method in colocalization_method: plot_kwargs_curr = dict( method=method, permute_what=permute_what, Y_transform=comparison_method, verbose=verbose, ) | plot_kwargs nsp.plot(**plot_kwargs_curr) ## RETURN colocs = {method: nsp.get_colocalizations(method, Y_transform=comparison_method) for method in colocalization_method} p_values = {method: nsp.get_p_values(method, permute_what, Y_transform=comparison_method) for method in colocalization_method} pc_values = { mc_m: {method: nsp.get_p_values(method, permute_what, Y_transform=comparison_method, mc_method=mc_m) for method in colocalization_method} for mc_m in mc_methods } if len(colocalization_method) == 1: k = colocalization_method[0] colocs, p_values = colocs[k], p_values[k] pc_values = {mc_m: pc_values[mc_m][k] for mc_m in mc_methods} if len(mc_methods) == 1: pc_values = pc_values[mc_methods[0]] # TODO (first non-dev release): remove return_nispace_only parameter; always return nsp only; # remove colocs/p_values/pc_values construction block above and the if/else here if not return_nispace_only: lgr.warning(_DEPR_RETURN_TUPLE) return colocs, p_values, pc_values, nsp return nsp
[docs]def paired_colocalization(y, x, z=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], colocalization_method="spearman", pooled_p="mean", plot=True, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, init_kwargs=None, fit_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, plot_kwargs=None): """Within-pair colocalization workflow (SPICE test). Tests whether within-pair correspondence between two brain map modalities (correlation across parcels per pair, averaged over pairs) is significantly greater than between-pair correspondence. The null distribution is built by permuting pair labels on the precomputed N×N colocalization matrix. "Pairs" can be subjects (structure vs. function per person), studies (one map per study in a meta-analytic context), neurochemical targets (tracers grouped by target), or any other unit for which matched maps exist in both modalities. Reference: :cite:`weinstein2021`. Parameters ---------- y : array-like, DataFrame, or list Modality A — N brain maps, one per pair. Same ordering as ``x`` is required; matching is done positionally. x : array-like, DataFrame, or list Modality B — N brain maps in the same pair order as ``y``. Unlike other workflow functions, ``x`` is expected to be individual-level data, not a reference dataset string — this is a usage contract (there is no ``x_collection`` parameter here and no dedicated runtime check forbidding a string), not an enforced validation. z : array-like, DataFrame, or list, optional Covariate maps to partial out. Required for partial correlation methods (``"partialspearman"``, ``"partialpearson"``); ignored otherwise. standardize : str, default="xz" Which data to z-standardize (parcels). Can contain "x", "y", "z". space : str Image space for parcellation and data loading. data_space : str or None Override for the data image space. parcellation_space : str or None Override for the parcellation space. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. parcellation_labels : array-like or None Optional subset of parcellation region labels. parcellation_hemi : list, default=["L", "R"] Hemispheres to include. colocalization_method : str, default="spearman" Colocalization method. Produces an N×N correlation matrix. pooled_p : str, default="mean" Aggregation used for the within-pair statistic: ``"mean"`` or ``"median"`` of the N diagonal entries. ``"auto"`` resolves to ``"mean"``. ``False`` is not supported and falls back to ``"mean"``. plot : bool, default=True Whether to generate a plot after permutation, via ``nsp.plot(permute_what="pairs")`` (relies on :meth:`NiSpace.plot`'s own ``kind="categorical"`` default — not passed explicitly here). n_perm : int, default=10000 Number of subject-label permutations for the null distribution. seed : int or None Random seed for reproducibility. n_proc : int, default=1 Parallel workers (passed to NiSpace init; not used by the fast vectorised pair permutation itself). verbose : bool, default=True Whether to print progress messages. nispace_object : NiSpace or None Pre-fitted NiSpace object to reuse; skips init/fit when provided. init_kwargs : dict, optional Extra keyword arguments for :class:`NiSpace` initialisation. fit_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.fit`. colocalize_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.colocalize`. permute_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.permute`. plot_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.plot`. Returns ------- nsp : NiSpace Fitted NiSpace object. Use :meth:`~NiSpace.get_colocalizations` to retrieve the N×N pairwise matrix, :meth:`~NiSpace.get_p_values` for the within-pair vs. between-pair p-value (shape 1×1), and :meth:`~NiSpace.plot` to re-draw the visualization. """ verbose = set_log(lgr, verbose) init_kwargs = {} if init_kwargs is None else dict(init_kwargs) fit_kwargs = {} if fit_kwargs is None else fit_kwargs colocalize_kwargs = {} if colocalize_kwargs is None else colocalize_kwargs permute_kwargs = {} if permute_kwargs is None else permute_kwargs plot_kwargs = {} if plot_kwargs is None else plot_kwargs if isinstance(colocalization_method, str): colocalization_method = [colocalization_method] status, nsp, _ = _workflow_base( x=x, y=y, z=z, x_collection=None, space=space, data_space=data_space, parcellation_space=parcellation_space, standardize=standardize, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=colocalization_method, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs={}, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, ) status = status | {fun: False for fun in ["colocalize", "permute"]} ## COLOCALIZE if not status["colocalize"]: for method in colocalization_method: nsp.colocalize(**dict(method=method) | colocalize_kwargs) status["colocalize"] = True ## PERMUTE (SPICE — operates on the precomputed N×N matrix, no re-colocalization) if not status["permute"]: for method in colocalization_method: permute_kwargs_curr = dict( what="pairs", method=method, pooled_p=pooled_p, n_perm=n_perm, seed=seed, ) | permute_kwargs nsp.permute(**permute_kwargs_curr) status["permute"] = True ## VIZ if plot: for method in colocalization_method: plot_kwargs_curr = dict( method=method, permute_what="pairs", ) | plot_kwargs nsp.plot(**plot_kwargs_curr) return nsp
def correlate_within_region(x, y, standardize=False, space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], method="pearson", n_perm=1000, seed=None, n_proc=1, verbose=True, nispace_object=None, init_kwargs=None, fit_kwargs=None, correlate_kwargs=None): """Per-parcel, across-subject correlation workflow. For each parcel independently, tests whether maps with a higher X value at that parcel also have a higher Y value at that parcel, across the set of X/Y maps (e.g. subjects) -- the transpose of :func:`colocalization` (which correlates across parcels, within a map). One of ``x``/``y`` may be a 1D, subject-length vector (or an equivalent single-column DataFrame/(n_subjects, 1) array) instead of full brain-map data (e.g. an external covariate like age) -- it is broadcast against every parcel of the other (2D) side, exactly like :meth:`NiSpace.correlate_within_region`'s own ``X=``/``Y=`` override contract. Internally, :meth:`NiSpace.fit` needs real 2D map data (it has no notion of "this is a subject-length covariate, not a map"; a bare 1D vector passed to ``fit()`` directly would be mis-parsed as a single already-parcellated map and fail on a parcel-count mismatch) -- so the 2D side is used to fit the object, and the 1D side is passed through as a direct override afterward. This is transparent to the caller; both ``x``/``y`` can simply be passed as given. At least one of ``x``/``y`` must be 2D. The null distribution is built by permuting map identity (not a spatial/ spin null); the same permutation is applied consistently across all parcels within one iteration. Parameters ---------- x : array-like or DataFrame Modality A -- N brain maps (N x n_parcels), or a length-N 1D subject covariate if ``y`` is 2D (see above). Same ordering as ``y`` is required; matching is done positionally. Unlike other workflow functions, ``x`` is expected to be individual-level data here, not a reference dataset string. y : array-like, DataFrame, or list Modality B, in the same map order as ``x`` -- or a length-N 1D subject covariate if ``x`` is 2D (see above). standardize : str or bool, default=False Which data to z-standardize (parcels). Can contain "x", "y". Defaults to ``False``: this z-scores each *map* across its own parcels, which distorts the across-map axis this function actually correlates (see :meth:`NiSpace.correlate_within_region`). space : str Image space for parcellation and data loading. data_space : str or None Override for the data image space. parcellation_space : str or None Override for the parcellation space. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. parcellation_labels : array-like or None Optional subset of parcellation region labels. parcellation_hemi : list, default=["L", "R"] Hemispheres to include. method : {"pearson", "spearman"}, default "pearson" n_perm : int, default 1000 Number of map-identity permutations for the null distribution. seed : int or None Random seed for reproducibility. n_proc : int, default 1 Parallel workers (passed to NiSpace init). verbose : bool, default True Whether to print progress messages. nispace_object : NiSpace or None Pre-fitted NiSpace object to reuse; skips init/fit when provided. init_kwargs : dict, optional Extra keyword arguments for :class:`NiSpace` initialisation. fit_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.fit`. correlate_kwargs : dict, optional Extra keyword arguments for :meth:`NiSpace.correlate_within_region`. Returns ------- nsp : NiSpace Fitted NiSpace object. Use :meth:`~NiSpace.get_within_region_correlations` to retrieve the per-parcel correlation, p-values, and (optionally corrected) results, or :meth:`~NiSpace.get_within_region_correlations_omnibus` for a single global test across all parcels instead. """ verbose = set_log(lgr, verbose) init_kwargs = {} if init_kwargs is None else dict(init_kwargs) fit_kwargs = {} if fit_kwargs is None else fit_kwargs correlate_kwargs = {} if correlate_kwargs is None else correlate_kwargs # 1D-covariate detection: a Series/1D array/list, or a single-column DataFrame/ # (n_subjects, 1) array, is a subject-length covariate, never a single brain map # (this function always needs an across-subject axis, which a lone map doesn't # have) -- so this is unambiguous, not a heuristic guess def _is_1d(v): if isinstance(v, pd.DataFrame): return v.shape[1] == 1 arr = v.values if isinstance(v, pd.Series) else np.asarray(v) return arr.ndim == 1 or (arr.ndim == 2 and arr.shape[1] == 1) def _squeeze_1d(v): """(n_subjects, 1) DataFrame/array -> true 1D, matching correlate_within_region_core.""" if isinstance(v, pd.DataFrame): return v.iloc[:, 0] if isinstance(v, pd.Series): return v arr = np.asarray(v) return arr[:, 0] if arr.ndim == 2 else arr x_is_1d, y_is_1d = _is_1d(x), _is_1d(y) if x_is_1d and y_is_1d: lgr.critical_raise("At least one of 'x'/'y' must be full brain-map data " "(N maps x n_parcels) -- both were given as 1D vectors.", ValueError) # fit() needs real 2D map data to build parcellation metadata from; when one side # is a 1D covariate, fit on the 2D side for both x and y, then pass the covariate # through as a direct correlate_within_region(X=/Y=) override below (bypassing # fit()/get_x()/get_y() entirely for that side, same as the object-level method) fit_x, fit_y = x, y if y_is_1d: fit_y = x elif x_is_1d: fit_x = y status, nsp, _ = _workflow_base( x=fit_x, y=fit_y, z=None, x_collection=None, space=space, data_space=data_space, parcellation_space=parcellation_space, standardize=standardize, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=[method], n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs={}, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, ) status = status | {"correlate_within_region": False} ## CORRELATE WITHIN REGION if not status["correlate_within_region"]: overrides = {} if x_is_1d: overrides["X"] = _squeeze_1d(x) if y_is_1d: overrides["Y"] = _squeeze_1d(y) nsp.correlate_within_region( **dict(method=method, n_perm=n_perm, seed=seed) | overrides | correlate_kwargs ) status["correlate_within_region"] = True return nsp
[docs]def xsea(y, x="mRNA", z=None, x_collection=None, x_background=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method=None, mc_method="meff", normalize_colocalizations=True, xsea_aggregation_method="mean", permute_sets=False, pooled_p=False, p_from_average_y=None, # TODO (first non-dev release): remove plot=True, combat=False, binary_y=False, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Set enrichment analysis (XSEA) workflow for group-level map(s). Equivalent to :func:`colocalization` with X treated as sets (e.g. gene sets) rather than individual maps: colocalizations are computed per set (aggregated via ``xsea_aggregation_method``) and Y is permuted to build the null distribution, unless ``permute_sets=True`` (see below). All parameters not listed below behave exactly as in :func:`colocalization`. Parameters ---------- y : array-like or pandas DataFrame or list Input Y data to test for set enrichment. Can be a numpy array, pandas DataFrame, (list of) path(s) to a file(s) or list of image objects. x : str or array-like, default="mRNA" Input X data, expected to carry set membership (e.g. a "set"/gene-set MultiIndex level). Can be a string reference dataset name or input types as listed for y. z : array-like or None, default=None Optional confound data to regress out. Can be "gm", or input types as listed for y. x_collection : str or None, default=None If x is a string reference dataset, specifies which collection to use. x_background : array-like or None, default=None Pool of "background" X maps used as the null when ``permute_sets=True`` (X-set-membership permutation). If ``None`` and ``x`` is a reference dataset string, an attempt is made to auto-fetch the full reference collection as the background (silently falls back to ``None`` with a warning on failure). Ignored if ``permute_sets=False``. standardize : str, default="xz" Which data to standardize. Can contain "x", "y", and/or "z". space : str, default=_SPACE_DEFAULT_VOL ("MNI152NLin6Asym") Default template space for both the data images and the parcellation. Used to resolve ``data_space``/``parcellation_space`` when those are not given. data_space : str or None, default=None Template space of the input data images. Falls back to ``space`` if falsy. parcellation_space : str or None, default=None Template space of the parcellation. Falls back to ``space`` if falsy. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. Can be a string name or integer ID. parcellation_labels : array-like or None, default=None Optional labels for the parcellation regions. parcellation_hemi : list of str, default=["L", "R"] Hemispheres to include. Forwarded to ``NiSpace`` initialization and, if ``x`` is a reference dataset string, to :func:`~nispace.datasets.fetch_reference`. y_covariates : array-like or None, default=None Optional covariates to regress from Y data. If given, :meth:`NiSpace.clean_y` is run with ``how="between"`` before colocalization. colocalization_method : str or list, default=None Method(s) to use for colocalization. When ``None``, defaults to ``"pearson"`` if ``binary_y=True``, otherwise ``"spearman"``. mc_method : str or list, default="meff" Multiple-comparisons correction method(s), forwarded to :meth:`NiSpace.correct_p`. An explicit ``"mc_method"`` key inside ``correct_p_kwargs`` overrides this entirely. normalize_colocalizations : bool, default=True Whether to call :meth:`NiSpace.normalize_colocalizations` after correction. Failures are caught and logged as a warning rather than raised. xsea_aggregation_method : str, default="mean" How to aggregate individual X maps within each set before colocalization. One of ``"mean"``, ``"median"``, ``"absmean"``, ``"absmedian"``, ``"weightedmean"``, ``"weightedabsmean"`` (weighted variants require a ``"weight"`` MultiIndex level on X). See :meth:`NiSpace.colocalize`. permute_sets : bool, default=False If ``True``, switches the permutation null from ``what="maps"`` (permuting Y, the default) to ``what="sets"`` (X-set-membership permutation using ``x_background`` as the pool of maps to reassign to sets). pooled_p : str or bool, default=False How to aggregate across Y maps before computing p-values. Same semantics as in :func:`colocalization` (fully relevant here). p_from_average_y : str or bool, optional Deprecated. Use ``pooled_p`` instead. plot : bool, default=True Whether to generate visualization plots. combat : bool, default=False Whether to apply ComBat harmonization. Only relevant if ``y_covariates`` is given. binary_y : bool, default=False Set if Y is binary. Forces ``NiSpace(binary_y=True)`` and drives the ``colocalization_method=None`` dynamic default toward ``"pearson"``. See :func:`colocalization` for the full behavior. n_perm : int, default=10000 Number of permutations for null distribution. seed : int or None, default=None Random seed for reproducibility. n_proc : int, default=1 Number of processes for parallel computation. verbose : bool, default=True Whether to print progress messages. nispace_object : NiSpace or None, default=None Optional pre-initialized NiSpace object to use. fetch_x_kwargs : dict, optional Additional arguments for fetching X data. init_kwargs : dict, optional Additional arguments for NiSpace initialization. fit_kwargs : dict, optional Additional arguments for ``NiSpace.fit()``. clean_y_kwargs : dict, optional Additional arguments for Y data cleaning. colocalize_kwargs : dict, optional Additional arguments for colocalization. Pre-seeded with ``xsea=True``/``xsea_aggregation_method``; explicit caller keys override. permute_kwargs : dict, optional Additional arguments for permutation testing. Pre-seeded with ``what``, ``maps_which="Y"``, ``sets_X_background``; explicit caller keys override. correct_p_kwargs : dict, optional Additional arguments for p-value correction. plot_kwargs : dict, optional Additional arguments for plotting. return_nispace_only : bool, default=False If True, return only the NiSpace object. Use ``nsp.get_colocalizations()`` and ``nsp.get_p_values()`` to access results. Setting False is deprecated and will be removed in the first non-dev release. Returns ------- nsp : NiSpace The NiSpace object containing all results (when ``return_nispace_only=True``). colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False`` (current default). """ verbose = set_log(lgr, verbose) # TODO (first non-dev release): remove p_from_average_y parameter if p_from_average_y is not None: lgr.warning(_DEPR_POOLED_P) pooled_p = p_from_average_y # kwarg dicts fetch_x_kwargs = {} if fetch_x_kwargs is None else fetch_x_kwargs init_kwargs = {} if init_kwargs is None else dict(init_kwargs) if binary_y: init_kwargs.setdefault("binary_y", True) if colocalization_method is None: colocalization_method = "pearson" if binary_y else "spearman" fit_kwargs = {} if fit_kwargs is None else fit_kwargs clean_y_kwargs = {} if clean_y_kwargs is None else clean_y_kwargs colocalize_kwargs = {} if colocalize_kwargs is None else colocalize_kwargs permute_kwargs = {} if permute_kwargs is None else permute_kwargs correct_p_kwargs = {} if correct_p_kwargs is None else correct_p_kwargs plot_kwargs = {} if plot_kwargs is None else plot_kwargs # GET THE BACKGROUND if permute_sets: if x_background is None and isinstance(x, str): lgr.info("Trying to fetch background X dataset.") if x.lower() in reference_lib: try: x_background = fetch_reference(x.lower(), parcellation=parcellation, hemi=parcellation_hemi, print_references=False) except: x_background = None if x_background is None: lgr.warning(f"Could not fetch background dataset for input x!") return colocalization( y=y, x=x, z=z, x_collection=x_collection, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, y_covariates=y_covariates, colocalization_method=colocalization_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, pooled_p=pooled_p, plot=plot, combat=combat, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, colocalize_kwargs={ "xsea_aggregation_method": xsea_aggregation_method, "xsea": True } | colocalize_kwargs, permute_kwargs={ "what": "maps" if not permute_sets else "sets", "maps_which": "Y", "sets_X_background": x_background if permute_sets else None, } | permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
[docs]def group_xsea(y, design, x="mRNA", z=None, x_collection=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], colocalization_method="spearman", comparison_method=None, mc_method="meff", normalize_colocalizations=True, xsea_aggregation_method="mean", pooled_p=False, paired=False, plot_design_between=True, combat=False, plot=True, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, transform_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Group-comparison set enrichment analysis (XSEA) workflow. Equivalent to :func:`group_colocalization` with X treated as sets (e.g. gene sets): Y is reduced to a single group-comparison effect-size map via :meth:`NiSpace.transform_y`, then colocalized with X sets (aggregated via ``xsea_aggregation_method``), with group-label permutation for p-values. All parameters not listed below behave exactly as in :func:`group_colocalization` (this function is a thin wrapper that injects ``xsea=True`` into ``colocalize_kwargs`` and forwards everything else unchanged). Parameters ---------- y : array-like or pandas DataFrame or list Input Y data: one map per individual subject/observation. design : list, array-like, or pandas DataFrame Group (and, if ``paired=True``, subject) labels. See :func:`group_colocalization` for the full accepted forms and validation rules. x : str or array-like, default="mRNA" Input X data, expected to carry set membership (e.g. a "set"/gene-set MultiIndex level). Can be a string reference dataset name or input types as listed for y. z : array-like or None, default=None Optional confound data to regress out. Can be "gm", or input types as listed for y. x_collection : str or None, default=None If x is a string reference dataset, specifies which collection to use. standardize : str, default="xz" Which data to standardize. Can contain "x", "y", and/or "z". space : str, default=_SPACE_DEFAULT_VOL ("MNI152NLin6Asym") Default template space for both the data images and the parcellation. Used to resolve ``data_space``/``parcellation_space`` when those are not given. data_space : str or None, default=None Template space of the input data images. Falls back to ``space`` if falsy. parcellation_space : str or None, default=None Template space of the parcellation. Falls back to ``space`` if falsy. parcellation : str or int, default=_PARC_DEFAULT Brain parcellation to use. Can be a string name or integer ID. parcellation_labels : array-like or None, default=None Optional labels for the parcellation regions. parcellation_hemi : list of str, default=["L", "R"] Hemispheres to include. colocalization_method : str or list, default="spearman" Method(s) to use for colocalization. Static default — no ``binary_y`` support here, same reasoning as :func:`group_colocalization`. comparison_method : str or None, default=None Formula passed to :meth:`NiSpace.transform_y` to reduce Y to a single group-comparison effect-size map. Defaults to ``"hedges(a,b)"`` (unpaired) or ``"pairedcohen(a,b)"`` (paired). mc_method : str or list, default="meff" Multiple-comparisons correction method(s), forwarded to :meth:`NiSpace.correct_p`. normalize_colocalizations : bool, default=True Whether to call :meth:`NiSpace.normalize_colocalizations` after correction. xsea_aggregation_method : str, default="mean" How to aggregate individual X maps within each set before colocalization. One of ``"mean"``, ``"median"``, ``"absmean"``, ``"absmedian"``, ``"weightedmean"``, ``"weightedabsmean"``. This is the only parameter this function adds beyond :func:`group_colocalization`'s own signature, injected into ``colocalize_kwargs`` together with ``xsea=True``. pooled_p : str or bool, default=False Present for signature symmetry, but not a free choice: group-label permutation always forces ``pooled_p="mean"``, same as :func:`group_colocalization`. Unlike :func:`xsea`, this function does not inject anything into ``permute_kwargs`` — XSEA-ness is inherited automatically inside :meth:`NiSpace.permute` from ``colocalize_kwargs["xsea"]``, since there is no maps/sets axis to choose for group-label permutation. paired : bool, default=False Whether groups are paired/matched by subject. plot_design_between : bool, default=True Whether to plot the between-subject design matrix (diagnostic only). combat : bool, default=False Whether to apply ComBat harmonization. plot : bool, default=True Whether to generate visualization plots. n_perm : int, default=10000 Number of permutations for null distribution. seed : int or None, default=None Random seed for reproducibility. n_proc : int, default=1 Number of processes for parallel computation. verbose : bool, default=True Whether to print progress messages. nispace_object : NiSpace or None, default=None Optional pre-initialized NiSpace object to use. fetch_x_kwargs : dict, optional Additional arguments for fetching X data. init_kwargs : dict, optional Additional arguments for NiSpace initialization. fit_kwargs : dict, optional Additional arguments for ``NiSpace.fit()``. clean_y_kwargs : dict, optional Additional arguments for Y data cleaning. Auto-triggered based on ``design`` having covariate columns. transform_y_kwargs : dict, optional Additional arguments for :meth:`NiSpace.transform_y`. colocalize_kwargs : dict, optional Additional arguments for colocalization. Pre-seeded with ``xsea=True``/``xsea_aggregation_method``; explicit caller keys override. permute_kwargs : dict, optional Additional arguments for permutation testing (unmodified by this function; ``what="groups"`` is forced by :func:`group_colocalization`). correct_p_kwargs : dict, optional Additional arguments for p-value correction. plot_kwargs : dict, optional Additional arguments for plotting. return_nispace_only : bool, default=False If True, return only the NiSpace object. Setting False is deprecated and will be removed in the first non-dev release. Returns ------- nsp : NiSpace The NiSpace object containing all results (when ``return_nispace_only=True``). colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False`` (current default). Notes ----- There is no ``binary_y`` parameter here, consistent with :func:`group_colocalization`: :meth:`NiSpace.transform_y` (always run internally) is incompatible with binary Y, and group-label permutation raises for ``binary_y=True``. """ return group_colocalization( y=y, design=design, x=x, z=z, x_collection=x_collection, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=colocalization_method, comparison_method=comparison_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, pooled_p=pooled_p, paired=paired, plot_design_between=plot_design_between, combat=combat, plot=plot, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, transform_y_kwargs=transform_y_kwargs, colocalize_kwargs={"xsea": True, "xsea_aggregation_method": xsea_aggregation_method} | (colocalize_kwargs or {}), permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
[docs]def nimare_colocalization(y, x="PET", z=None, x_collection=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method=None, mc_method="meff", normalize_colocalizations=True, pooled_p=False, plot=True, binary_y=False, nimare_nulls=None, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """NiMARE colocalization workflow. Convenience wrapper around :func:`colocalization` for Y maps derived from NiMARE meta-analyses (continuous ALE stat maps or binary cluster-coverage maps from :func:`~nispace.helpers.get_binary_cluster_map`). Sets the following defaults relative to :func:`colocalization`: * ``background_value={"y": False}`` in ``fit_kwargs`` — zero-valued voxels in ALE maps are meaningful (no activation there), not missing data. Scoped to Y only: X (and Z, if given) keep the normal ``'auto'`` background handling, since only Y is guaranteed to be an ALE/cluster-coverage map here. * ``maps_which="Y"`` in ``permute_kwargs`` when ``nimare_nulls`` is provided, so Y is permuted with coordinate-sampling null maps; otherwise ``"X"`` For binary cluster maps also pass ``binary_y=True`` and ``colocalization_method="pearson"``. Parameters ---------- y : NIfTI image, array-like, or list ALE stat map (``result.get_map("stat")``) or binary cluster-coverage map (from :func:`~nispace.helpers.get_binary_cluster_map`). x : str or array-like, default="PET" Reference X maps. Same as :func:`colocalization`. colocalization_method : str or list, default=None Colocalization method. When ``None``, defaults to ``"pearson"`` if ``binary_y=True`` (approximate point-biserial), otherwise ``"spearman"``. binary_y : bool, default=False Set ``True`` when Y is a binary or fractional cluster-coverage map. Prevents z-scoring of Y and raises warnings for ranked methods or group permutation. See :class:`~nispace.NiSpace` for details. nimare_nulls : dict or None, default=None Coordinate-sampling null maps from :func:`~nispace.helpers.null_maps_from_nimare`. When provided, sets ``maps_nulls=nimare_nulls`` and ``maps_which="Y"`` in ``permute_kwargs`` so Y is permuted with the NiMARE null distribution. Explicit entries in ``permute_kwargs`` take precedence. Returns ------- nsp : NiSpace (when ``return_nispace_only=True``) colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False``. Notes ----- All other parameters are identical to :func:`colocalization`. """ init_kwargs = {} if init_kwargs is None else dict(init_kwargs) if binary_y: init_kwargs.setdefault("binary_y", True) if colocalization_method is None: colocalization_method = "pearson" if binary_y else "spearman" fit_kwargs = {} if fit_kwargs is None else dict(fit_kwargs) fit_kwargs.setdefault("background_value", {"y": False}) permute_kwargs = {} if permute_kwargs is None else dict(permute_kwargs) if nimare_nulls is not None: permute_kwargs.setdefault("maps_nulls", nimare_nulls) permute_kwargs.setdefault("maps_which", "Y") else: permute_kwargs.setdefault("maps_which", "X") return colocalization( y=y, x=x, z=z, x_collection=x_collection, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, y_covariates=y_covariates, colocalization_method=colocalization_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, pooled_p=pooled_p, plot=plot, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, colocalize_kwargs=colocalize_kwargs, permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
[docs]def nimare_xsea(y, x="mRNA", z=None, x_collection=None, x_background=None, standardize="xz", space=_SPACE_DEFAULT_VOL, data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method=None, mc_method="meff", normalize_colocalizations=True, xsea_aggregation_method="mean", permute_sets=False, pooled_p=False, plot=True, binary_y=False, nimare_nulls=None, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """NiMARE X-set enrichment analysis (XSEA) workflow. Convenience wrapper around :func:`xsea` for Y maps derived from NiMARE meta-analyses. Equivalent to :func:`nimare_colocalization` with XSEA enabled. Sets ``background_value={"y": False}`` in ``fit_kwargs`` (scoped to Y only -- X/Z keep normal ``'auto'`` background handling) and routes ``nimare_nulls`` into ``permute_kwargs``. See :func:`nimare_colocalization` for full details on NiMARE-specific parameters. Parameters ---------- y : NIfTI image, array-like, or list ALE stat map or binary cluster-coverage map. x : str or array-like, default="mRNA" Reference X maps (gene-set collections for XSEA). binary_y : bool, default=False Set ``True`` for binary or fractional cluster-coverage Y maps. nimare_nulls : dict or None, default=None Coordinate-sampling null maps from :func:`~nispace.helpers.null_maps_from_nimare`. When provided, sets ``maps_nulls=nimare_nulls`` in ``permute_kwargs``. Returns ------- nsp : NiSpace (when ``return_nispace_only=True``) colocs, p_values, pc_values, nsp : tuple Deprecated. Returned when ``return_nispace_only=False``. Notes ----- All other parameters are identical to :func:`xsea`. Unlike :func:`nimare_colocalization`, this function never touches ``maps_which`` — :func:`xsea` always permutes ``maps_which="Y"`` regardless of ``nimare_nulls``, since X is a fixed reference gene-set collection in XSEA, not something meaningfully permuted map-by-map. So ``nimare_nulls=None`` here does **not** fall back to X-permutation the way :func:`nimare_colocalization` does — Y is still permuted, just with freshly generated standard spatial nulls (typically Moran) instead of NiMARE coordinate-sampling nulls, which is functionally equivalent to a plain :func:`xsea` call. """ init_kwargs = {} if init_kwargs is None else dict(init_kwargs) if binary_y: init_kwargs.setdefault("binary_y", True) if colocalization_method is None: colocalization_method = "pearson" if binary_y else "spearman" fit_kwargs = {} if fit_kwargs is None else dict(fit_kwargs) fit_kwargs.setdefault("background_value", {"y": False}) permute_kwargs = {} if permute_kwargs is None else dict(permute_kwargs) if nimare_nulls is not None: permute_kwargs.setdefault("maps_nulls", nimare_nulls) return xsea( y=y, x=x, z=z, x_collection=x_collection, x_background=x_background, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, y_covariates=y_covariates, colocalization_method=colocalization_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, xsea_aggregation_method=xsea_aggregation_method, permute_sets=permute_sets, pooled_p=pooled_p, plot=plot, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, colocalize_kwargs=colocalize_kwargs, permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
# ============================================================================== # DEPRECATION WRAPPERS — old function names kept for backward compatibility # TODO (first non-dev release): remove these wrappers # ==============================================================================
[docs]def simple_colocalization(y, x="PET", z=None, x_collection=None, standardize="xz", space="MNI152NLin2009cAsym", data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method="spearman", mc_method="meff", normalize_colocalizations=True, p_from_average_y=False, plot=True, combat=False, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Deprecated wrapper for :func:`colocalization`. .. deprecated:: dev Use :func:`colocalization` instead. Will be removed in the first non-dev release. """ lgr.warning(_DEPR_FUNC_NAME.format(old="simple_colocalization", new="colocalization")) return colocalization( y=y, x=x, z=z, x_collection=x_collection, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, y_covariates=y_covariates, colocalization_method=colocalization_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, pooled_p=p_from_average_y, plot=plot, combat=combat, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, colocalize_kwargs=colocalize_kwargs, permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
[docs]def group_comparison(y, design, x="PET", z=None, x_collection=None, standardize="xz", space="MNI152NLin2009cAsym", data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], colocalization_method="spearman", comparison_method=None, mc_method="meff", normalize_colocalizations=True, p_from_average_y=True, paired=False, plot_design_between=True, combat=False, plot=True, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, transform_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Deprecated wrapper for :func:`group_colocalization`. .. deprecated:: dev Use :func:`group_colocalization` instead. Will be removed in the first non-dev release. """ lgr.warning(_DEPR_FUNC_NAME.format(old="group_comparison", new="group_colocalization")) return group_colocalization( y=y, design=design, x=x, z=z, x_collection=x_collection, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, colocalization_method=colocalization_method, comparison_method=comparison_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, pooled_p=p_from_average_y, paired=paired, plot_design_between=plot_design_between, combat=combat, plot=plot, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, transform_y_kwargs=transform_y_kwargs, colocalize_kwargs=colocalize_kwargs, permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )
[docs]def simple_xsea(y, x="mRNA", z=None, x_collection=None, x_background=None, standardize="xz", space="MNI152NLin2009cAsym", data_space=None, parcellation_space=None, parcellation=_PARC_DEFAULT, parcellation_labels=None, parcellation_hemi=["L", "R"], y_covariates=None, colocalization_method="spearman", mc_method="meff", normalize_colocalizations=True, xsea_aggregation_method="mean", permute_sets=False, p_from_average_y=False, plot=True, combat=False, n_perm=10000, seed=None, n_proc=1, verbose=True, nispace_object=None, fetch_x_kwargs=None, init_kwargs=None, fit_kwargs=None, clean_y_kwargs=None, colocalize_kwargs=None, permute_kwargs=None, correct_p_kwargs=None, plot_kwargs=None, return_nispace_only=False): """Deprecated wrapper for :func:`xsea`. .. deprecated:: dev Use :func:`xsea` instead. Will be removed in the first non-dev release. """ lgr.warning(_DEPR_FUNC_NAME.format(old="simple_xsea", new="xsea")) return xsea( y=y, x=x, z=z, x_collection=x_collection, x_background=x_background, standardize=standardize, space=space, data_space=data_space, parcellation_space=parcellation_space, parcellation=parcellation, parcellation_labels=parcellation_labels, parcellation_hemi=parcellation_hemi, y_covariates=y_covariates, colocalization_method=colocalization_method, mc_method=mc_method, normalize_colocalizations=normalize_colocalizations, xsea_aggregation_method=xsea_aggregation_method, permute_sets=permute_sets, pooled_p=p_from_average_y, plot=plot, combat=combat, n_perm=n_perm, seed=seed, n_proc=n_proc, verbose=verbose, nispace_object=nispace_object, fetch_x_kwargs=fetch_x_kwargs, init_kwargs=init_kwargs, fit_kwargs=fit_kwargs, clean_y_kwargs=clean_y_kwargs, colocalize_kwargs=colocalize_kwargs, permute_kwargs=permute_kwargs, correct_p_kwargs=correct_p_kwargs, plot_kwargs=plot_kwargs, return_nispace_only=return_nispace_only, )