X-Set Enrichment Analysis (XSEA; c.f. ABAnnotate)

So far, we’ve been computing colocalization values between a brain map and individual reference maps — one correlation per receptor or gene. But sometimes we don’t care about individual maps; we want to know whether the brain pattern of interest is broadly associated with a group of maps — say, all serotonin receptors, or all genes expressed in excitatory neurons.

This is the idea behind X-Set Enrichment Analysis (XSEA). The concept is closely related to Gene Set Enrichment Analysis (GSEA) in transcriptomics, adapted for brain maps.

The concept of XSEA used here was first implemented in the MATLAB toolbox ABAnnotate, a predecessor of NiSpace. If you’ve used ABAnnotate, you’ll find the concepts familiar.

The idea

Given a brain map and a set of reference maps (e.g., all receptor maps for serotonin), XSEA computes:

  1. The mean colocalization between the brain map and all maps in the set.

  2. A p-value asking: is this mean colocalization higher than expected when the brain map is replaced by a spatially-constrained random map?

The result is one statistic per set, not per individual map.

A note on null models

There are two natural null hypotheses for XSEA:

  1. Permute the input map (default): generate surrogate maps of the brain map and recompute mean colocalizations. This tests whether the observed mean is higher than expected under spatial randomness.

  2. Permute the sets: randomly sample sets from a larger background population of maps and ask whether the observed set mean is higher than random sets.

Ben Fulcher et al. (2021, Nature Communications) showed that random set sampling can inflate false positives when maps within a set are highly co-expressed (correlated). NiSpace therefore defaults to map permutation, following the approach of ABAnnotate. Pass permute_sets=True to switch to set permutation if needed. However, this is currently not recommended. In the future, we will implement within-set correlation-matched set resampling, which can address this issue.

[2]:
import tqdm.notebook
tqdm.notebook.tqdm = tqdm.tqdm

import numpy as np
import pandas as pd
[3]:
from nispace.datasets import fetch_reference, fetch_example
from nispace.io import load_img
from nispace.api import NiSpace

Dataset setup

We’ll run XSEA on the pain map against mRNA gene expression data, testing whether pain-related brain activation broadly aligns with the expression of particular cell types.

The mRNA reference dataset is derived from the Allen Human Brain Atlas (AHBA) and provides mean gene expression per brain region for thousands of genes, organized into sets such as cell type markers.

[4]:
# pain map (NeuroQuery meta-analytic z-map)
pain_map = load_img("neuroquery/pain.nii.gz")

# mRNA reference: cell type marker sets (Lake et al 2016)
# parcellation: Yan100+TianS1 (low resolution to match coarse ABA data sampling)
mrna = fetch_reference(
    "mrna",
    parcellation="Yan100+TianS1",
    collection="CellTypesPsychEncodeTPM",
    print_references=False
)
print(f"mRNA data: {mrna.shape[0]} genes across {mrna.index.get_level_values('set').nunique()} sets x {mrna.shape[1]} parcels")
print(f"Set names: {list(mrna.index.get_level_values('set').unique())}")
mrna.head(3)
INFO | 20/07/26 18:25:05 | nispace.datasets: Loading mrna maps.
INFO | 20/07/26 18:25:05 | nispace.datasets: Loading integrated collection 'CellTypesPsychEncodeTPM' for dataset 'mrna'.
INFO | 20/07/26 18:25:05 | nispace.datasets: Filtering maps by collection.
INFO | 20/07/26 18:25:05 | nispace.datasets: Loading and inner-merging data parcellated with 'Yan100' and 'TianS1'
mRNA data: 465 genes across 24 sets x 116 parcels
Set names: ['Ex1 CortProject (L2/3)', 'Ex2 Granule (L3/4)', 'Ex3 Granule (L4)', 'Ex4 SubcortProject (L4)', 'Ex5 SubcortProject (L4-6)', 'Ex6 SubcortProject (L5-6)', 'Ex7 Corticothalamic', 'Ex8 Corticothalamic (L6)', 'In1 VIP+RELN+NDNF+ (L1/2)', 'In2 VIP+RELN-NDNF- (L6)', 'In3 VIP+RELN+NDNF- (L6)', 'In4 VIP-RELN+NDNF+ (L1-3)', 'In5 CCK+NOS1+CALB2+ (L2/3)', 'In6 PVALB+CRHBP+ (L4/5)', 'In7 SST+CALB1+NPY+ (L5/6)', 'In8 SST+NOS1+ (L6)', 'Astrocyte', 'Endothelial', 'Developing-quiescent', 'Developing-replicating', 'Microglia', 'Other Neurons', 'OPC', 'Oligodendrocyte']
[4]:
hemi-L_div-DefaultC_lab-PHC hemi-L_div-DefaultC_lab-pCun hemi-L_div-DefaultB_lab-IPL hemi-L_div-DefaultB_lab-PFCd+1 hemi-L_div-DefaultB_lab-PFCd+2 hemi-L_div-DefaultB_lab-PFCv+1 hemi-L_div-DefaultB_lab-PFCv+2 hemi-L_div-DefaultB_lab-Temp hemi-L_div-DefaultB_lab-TempPole hemi-L_div-DefaultA_lab-IPL ... hemi-L_lab-PUT hemi-L_lab-CAU hemi-R_lab-HIP hemi-R_lab-AMY hemi-R_lab-pTHA hemi-R_lab-aTHA hemi-R_lab-NAc hemi-R_lab-GP hemi-R_lab-PUT hemi-R_lab-CAU
set map
Ex1 CortProject (L2/3) CAMK2A 0.819938 0.805068 0.818384 0.816943 0.800985 0.814334 0.812704 0.813468 0.813343 0.819423 ... 0.452723 0.571612 0.792884 0.710187 0.414296 0.366631 0.485376 0.288345 0.537562 0.596598
CCDC88C 0.461542 0.394270 0.527073 0.469519 0.371260 0.370976 0.401998 0.479305 0.524730 0.424418 ... 0.784354 0.905244 0.417680 0.772467 0.433421 0.556930 0.916510 0.728213 0.748571 0.981271
CDH9 0.731467 0.701286 0.722710 0.718415 0.697795 0.739465 0.701239 0.731921 0.728901 0.690313 ... 0.483765 0.509307 0.638481 0.786927 0.225884 0.266731 0.684596 0.402965 0.512751 0.539964

3 rows × 116 columns

Notice the two-level MultiIndex: the first level is the cell type group (“set”), the second is the individual gene. The set structure is what XSEA operates on.

Running XSEA step by step

XSEA is triggered by passing xsea=True (or a specific aggregation method) to colocalize(). This computes colocalization with each individual map first, then averages within sets.

[5]:
nsp = NiSpace(
    x=mrna,
    y=pain_map,
    y_labels="Pain",
    parcellation="Yan100+TianS1",
    seed=42,
    n_proc=4
)
nsp.fit()

# colocalize with XSEA aggregation
# xsea=True computes the mean colocalization within each set
nsp.colocalize("spearman", xsea=True)

# the result has one column per set (not per individual gene)
colocs = nsp.get_colocalizations()
print(f"XSEA colocalizations: {colocs.shape[1]} sets")
print(colocs.T.sort_values(by="Pain", ascending=False))
INFO | 20/07/26 18:25:05 | nispace.api: *** NiSpace.fit() - Data extraction and preparation. ***
INFO | 20/07/26 18:25:05 | nispace.core.parcellation: Building combined Parcellation 'Yan100+TianS1' from library.
INFO | 20/07/26 18:25:05 | nispace.core.parcellation:   Common MNI space(s) for combined: ['MNI152NLin2009cAsym', 'MNI152NLin6Asym'].
INFO | 20/07/26 18:25:05 | nispace.core.parcellation:   Merging 'Yan100' and 'TianS1' for space 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:06 | nispace.core.parcellation:   Merging 'Yan100' and 'TianS1' for space 'MNI152NLin6Asym'.
INFO | 20/07/26 18:25:06 | nispace.core.parcellation:   Fetching cx surface data for 'Yan100' in 'fsLR' (for spin tests).
INFO | 20/07/26 18:25:06 | nispace.core.parcellation:   Fetching cx surface data for 'Yan100' in 'fsaverage' (for spin tests).
INFO | 20/07/26 18:25:06 | nispace.core.parcellation: Combined parcellation 'Yan100+TianS1' ready. MNI space(s): ['MNI152NLin2009cAsym', 'MNI152NLin6Asym']. Cx surface space(s) for spins: ['fsLR', 'fsaverage'].
INFO | 20/07/26 18:25:06 | nispace.core.parcellation: Parcellation 'Yan100+TianS1': validation passed.
INFO | 20/07/26 18:25:06 | nispace.core.parcellation: Parcellation 'Yan100+TianS1': active space set to 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:06 | nispace.core.parcellation: Combined parcellation: cx-LH parcels = 50, cx-RH parcels = 50.
INFO | 20/07/26 18:25:06 | nispace.api: Checking input data for 'x' (should be, e.g., PET data):
INFO | 20/07/26 18:25:06 | nispace.io: Input type: DataFrame, assuming parcellated data with shape (n_files/subjects/etc, n_parcels).
INFO | 20/07/26 18:25:06 | nispace.api: Got 'x' data for 465 x 116 parcels.
INFO | 20/07/26 18:25:06 | nispace.api: Checking input data for 'y' (should be, e.g., subject data):
INFO | 20/07/26 18:25:06 | nispace.io: Input type: list, assuming imaging data.
INFO | 20/07/26 18:25:06 | nispace.io: Background (bg) handling: background_value='auto'; reporting bg-only parcels: False
INFO | 20/07/26 18:25:06 | nispace.io: Parcellating imaging data.
Parcellating (4 proc): 100%|█████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 105.17it/s]
INFO | 20/07/26 18:25:10 | nispace.api: Got 'y' data for 1 x 116 parcels.
INFO | 20/07/26 18:25:10 | nispace.api: Z-standardizing 'X' data.
INFO | 20/07/26 18:25:10 | nispace.api: *** NiSpace.colocalize() - Estimating X & Y colocalizations. ***
INFO | 20/07/26 18:25:10 | nispace.api: Running 'spearman' colocalization.
INFO | 20/07/26 18:25:10 | nispace.api: Will perform X-set enrichment analysis (XSEA).
INFO | 20/07/26 18:25:10 | nispace.api: Using 24 sets with between 2 and 68 samples. Aggregating within-set colocalizations with: mean.
INFO | 20/07/26 18:25:10 | nispace.api: Pre-ranking X and Y data.
Colocalizing (spearman, 4 proc): 100%|██████████████████████████████████████████████████| 1/1 [00:00<00:00, 2387.20it/s]
INFO | 20/07/26 18:25:13 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
XSEA colocalizations: 24 sets
                                Pain
Microglia                   0.237071
Astrocyte                   0.193244
OPC                         0.168680
Endothelial                 0.167029
Oligodendrocyte             0.153288
Ex8 Corticothalamic (L6)    0.144509
In1 VIP+RELN+NDNF+ (L1/2)   0.135319
Ex6 SubcortProject (L5-6)   0.134973
Developing-replicating      0.098871
Ex7 Corticothalamic         0.089922
Developing-quiescent        0.057061
In2 VIP+RELN-NDNF- (L6)     0.041979
Other Neurons               0.008044
Ex1 CortProject (L2/3)      0.007910
In3 VIP+RELN+NDNF- (L6)     0.006335
In4 VIP-RELN+NDNF+ (L1-3)   0.006012
In6 PVALB+CRHBP+ (L4/5)    -0.004182
In7 SST+CALB1+NPY+ (L5/6)  -0.015132
In8 SST+NOS1+ (L6)         -0.023580
Ex2 Granule (L3/4)         -0.024996
Ex5 SubcortProject (L4-6)  -0.030492
In5 CCK+NOS1+CALB2+ (L2/3) -0.043055
Ex4 SubcortProject (L4)    -0.044900
Ex3 Granule (L4)           -0.190710

Permutation testing for XSEA

Permutation testing works the same way as for individual maps: we call permute("maps"), but now the null maps are used to compute null set-level colocalizations (after within-set averaging). The resulting p-value answers: is the observed set mean higher than expected under spatial randomness?

[6]:
# permute the input map (default for XSEA)
nsp.permute(
    "maps",
    maps_which="Y", # that's the input map
    n_perm=1000,
    p_tails="two",  # two-tailed: no directional hypothesis for cell types
    n_proc=-1
)

# correct p values
nsp.correct_p()

# compute normalized colocalization values (here, only for plotting)
nsp.normalize_colocalizations()

# get results
p_values = nsp.get_p_values()
pc_values = nsp.get_corrected_p_values()

# show results sorted by p-value
xsea_results = pd.DataFrame({
    "mean_rho": colocs.T["Pain"],
    "p": p_values.T["Pain"],
    "p_corrected": pc_values.T["Pain"]
}).sort_values("p")

xsea_results
INFO | 20/07/26 18:25:13 | nispace.api: *** NiSpace.permute() - Estimate exact non-parametric p values. ***
INFO | 20/07/26 18:25:13 | nispace.api: Permutation of: Y maps.
INFO | 20/07/26 18:25:13 | nispace.api: Using default split null method (cx='moran', sc='moran') (cx space: 'MNI152NLin6Asym', sc space: 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:13 | nispace.api: Loading observed colocalizations (method = 'spearman').
INFO | 20/07/26 18:25:13 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:13 | nispace.api: Generating permuted Y maps.
INFO | 20/07/26 18:25:13 | nispace.core.permute: Generating null maps (n = 1000, null_method = 'moran+moran').
INFO | 20/07/26 18:25:13 | nispace.core.parcellation: Lazy-loading sc dist mat for 'TianS1' (space 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:13 | nispace.core.parcellation: Lazy-loading cx dist mat for 'Yan100' (space 'fsLR').
INFO | 20/07/26 18:25:14 | nispace.nulls: Split null method: cx='moran' (100 parcels), sc='moran' (16 parcels).
INFO | 20/07/26 18:25:14 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 100 parcels.
INFO | 20/07/26 18:25:14 | nispace.nulls: Using provided distance matrix/matrices.
Moran null maps (-1 proc): 100%|██████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  3.39it/s]
INFO | 20/07/26 18:25:17 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:17 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 16 parcels.
INFO | 20/07/26 18:25:17 | nispace.nulls: Using provided distance matrix/matrices.
Moran null maps (-1 proc): 100%|████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1156.09it/s]
INFO | 20/07/26 18:25:20 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:20 | nispace.api: Running X Set Enrichment Analysis (XSEA) without set permutation.
INFO | 20/07/26 18:25:20 | nispace.api: Pre-ranking X and Y (null) data.
Processing null arrays (-1 proc): 100%|████████████████████████████████████████████| 1000/1000 [00:01<00:00, 523.65it/s]
INFO | 20/07/26 18:25:25 | nispace.api: Using precomputed per-gene statistics for XSEA null aggregation.
Null colocalizations (spearman, precomputed): 100%|███████████████████████████████| 1000/1000 [00:00<00:00, 1180.52it/s]
INFO | 20/07/26 18:25:26 | nispace.core.permute: Calculating exact p-values (tails = {'rho': 'two'}).
INFO | 20/07/26 18:25:26 | nispace.api: *** NiSpace.correct_p() - Correct p values for multiple comparisons. ***
INFO | 20/07/26 18:25:26 | nispace.api: Correction method: 'meff_galwey', alpha: 0.05, dimension: 'array'.
INFO | 20/07/26 18:25:26 | nispace.api: Returning X dataframe:
| X_REDUCTION |
| False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Meff_X (galwey) = 10.41 (from 24 maps).
INFO | 20/07/26 18:25:26 | nispace.api: *** NiSpace.normalize_colocalizations() - Normalize colocalizations against null distribution. ***
INFO | 20/07/26 18:25:26 | nispace.api: Z-score method: robust (median/MAD).
INFO | 20/07/26 18:25:26 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Stored normalized colocalizations: xdimred-false_ytrans-false_coloc-spearman_stat-rho_xsea-true_perm-ymaps
INFO | 20/07/26 18:25:26 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 

[6]:
mean_rho p p_corrected
Ex8 Corticothalamic (L6) 0.144509 0.012 0.118072
Microglia 0.237071 0.074 0.550731
OPC 0.168680 0.082 0.589523
Developing-replicating 0.098871 0.142 0.796870
Endothelial 0.167029 0.194 0.894028
Ex7 Corticothalamic 0.089922 0.198 0.899376
Ex6 SubcortProject (L5-6) 0.134973 0.230 0.934134
Oligodendrocyte 0.153288 0.274 0.964297
Astrocyte 0.193244 0.276 0.965307
Ex3 Granule (L4) -0.190710 0.358 0.990070
Developing-quiescent 0.057061 0.368 0.991567
In5 CCK+NOS1+CALB2+ (L2/3) -0.043055 0.380 0.993092
Other Neurons 0.008044 0.414 0.996159
In7 SST+CALB1+NPY+ (L5/6) -0.015132 0.448 0.997938
In2 VIP+RELN-NDNF- (L6) 0.041979 0.460 0.998360
In6 PVALB+CRHBP+ (L4/5) -0.004182 0.578 0.999874
Ex5 SubcortProject (L4-6) -0.030492 0.612 0.999947
In1 VIP+RELN+NDNF+ (L1/2) 0.135319 0.620 0.999958
Ex4 SubcortProject (L4) -0.044900 0.648 0.999981
In4 VIP-RELN+NDNF+ (L1-3) 0.006012 0.708 0.999997
In3 VIP+RELN+NDNF- (L6) 0.006335 0.710 0.999997
In8 SST+NOS1+ (L6) -0.023580 0.722 0.999998
Ex1 CortProject (L2/3) 0.007910 0.808 1.000000
Ex2 Granule (L3/4) -0.024996 0.852 1.000000
[7]:
nsp.plot(sort_by="z")
INFO | 20/07/26 18:25:26 | nispace.api: *** NiSpace.plot() - Plot colocalization results. ***
INFO | 20/07/26 18:25:26 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 
INFO | 20/07/26 18:25:26 | nispace.api: Creating categorical plot for method spearman, colocalization stat rho.
INFO | 20/07/26 18:25:26 | nispace.api: Returning z-scored colocalizations.
INFO | 20/07/26 18:25:26 | nispace.plotting: Significance annotation: 1/24 p_uncorrected < 0.05, 0/24 p_meffgalwey < 0.05
../_images/nb_introduction_intro10_xsea_9_1.png
[7]:
(<Figure size 500x630 with 1 Axes>,
 <Axes: title={'center': "$Spearman's\\ Rho$ colocalization\n(permutation of $Y\\ maps$)"}, xlabel='$Rho$'>,
 <seaborn._core.plot.Plotter at 0x16e25ddc0>)

XSEA with PET receptor sets

XSEA isn’t limited to gene expression — you can use any reference dataset with a set structure. The PET dataset, for example, has neurotransmitter systems as sets. Running XSEA on it asks: does the pain map align more with the overall serotonin system than with the overall dopamine system, beyond what spatial autocorrelation can explain?

[8]:
# For XSEA with PET, we need a collection with the set structure (neurotransmitter
# systems as sets). UniqueTracers is a JSON-format collection that gives a two-level
# ['set', 'map'] MultiIndex — exactly what XSEA needs to aggregate by system.
pet_unique = fetch_reference(
    "pet", parcellation="Yan200+TianS1", collection="UniqueTracers", print_references=False,
    set_size_range=(3, None) # when fetching set-based collections, some more parameters can be adjusted
)

nsp_pet = NiSpace(
    x=pet_unique,
    y=pain_map,
    y_labels="Pain",
    parcellation="Yan200+TianS1",
    seed=42,
    n_proc=4
)
nsp_pet.fit()
nsp_pet.colocalize("spearman", xsea=True)
nsp_pet.permute("maps", maps_which="Y", n_perm=1000, p_tails="upper")
nsp_pet.correct_p()

nsp_pet.plot()
INFO | 20/07/26 18:25:26 | nispace.datasets: Loading pet maps.
INFO | 20/07/26 18:25:26 | nispace.datasets: Loading integrated collection 'UniqueTracers' for dataset 'pet'.
INFO | 20/07/26 18:25:26 | nispace.datasets: Filtering maps by collection.
INFO | 20/07/26 18:25:26 | nispace.datasets: Filtered to 5 collection sets with between 3 and inf maps.
INFO | 20/07/26 18:25:26 | nispace.datasets: Loading and inner-merging data parcellated with 'Yan200' and 'TianS1'
INFO | 20/07/26 18:25:26 | nispace.api: *** NiSpace.fit() - Data extraction and preparation. ***
INFO | 20/07/26 18:25:26 | nispace.core.parcellation: Building combined Parcellation 'Yan200+TianS1' from library.
INFO | 20/07/26 18:25:26 | nispace.core.parcellation:   Common MNI space(s) for combined: ['MNI152NLin2009cAsym', 'MNI152NLin6Asym'].
INFO | 20/07/26 18:25:26 | nispace.core.parcellation:   Merging 'Yan200' and 'TianS1' for space 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:27 | nispace.core.parcellation:   Merging 'Yan200' and 'TianS1' for space 'MNI152NLin6Asym'.
INFO | 20/07/26 18:25:27 | nispace.core.parcellation:   Fetching cx surface data for 'Yan200' in 'fsLR' (for spin tests).
INFO | 20/07/26 18:25:27 | nispace.core.parcellation:   Fetching cx surface data for 'Yan200' in 'fsaverage' (for spin tests).
INFO | 20/07/26 18:25:28 | nispace.core.parcellation: Combined parcellation 'Yan200+TianS1' ready. MNI space(s): ['MNI152NLin2009cAsym', 'MNI152NLin6Asym']. Cx surface space(s) for spins: ['fsLR', 'fsaverage'].
INFO | 20/07/26 18:25:28 | nispace.core.parcellation: Parcellation 'Yan200+TianS1': validation passed.
INFO | 20/07/26 18:25:28 | nispace.core.parcellation: Parcellation 'Yan200+TianS1': active space set to 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:28 | nispace.core.parcellation: Combined parcellation: cx-LH parcels = 100, cx-RH parcels = 100.
INFO | 20/07/26 18:25:28 | nispace.api: Checking input data for 'x' (should be, e.g., PET data):
INFO | 20/07/26 18:25:28 | nispace.io: Input type: DataFrame, assuming parcellated data with shape (n_files/subjects/etc, n_parcels).
WARNING | 20/07/26 18:25:28 | nispace.io: Parcellated data contains nan values!
INFO | 20/07/26 18:25:28 | nispace.api: Got 'x' data for 22 x 216 parcels.
INFO | 20/07/26 18:25:28 | nispace.api: Checking input data for 'y' (should be, e.g., subject data):
INFO | 20/07/26 18:25:28 | nispace.io: Input type: list, assuming imaging data.
INFO | 20/07/26 18:25:28 | nispace.io: Background (bg) handling: background_value='auto'; reporting bg-only parcels: False
INFO | 20/07/26 18:25:28 | nispace.io: Parcellating imaging data.
Parcellating (4 proc): 100%|██████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  1.54it/s]
INFO | 20/07/26 18:25:32 | nispace.api: Got 'y' data for 1 x 216 parcels.
INFO | 20/07/26 18:25:32 | nispace.api: Z-standardizing 'X' data.
INFO | 20/07/26 18:25:32 | nispace.api: *** NiSpace.colocalize() - Estimating X & Y colocalizations. ***
INFO | 20/07/26 18:25:32 | nispace.api: Running 'spearman' colocalization.
INFO | 20/07/26 18:25:32 | nispace.api: Will perform X-set enrichment analysis (XSEA).
INFO | 20/07/26 18:25:32 | nispace.api: Using 5 sets with between 3 and 6 samples. Aggregating within-set colocalizations with: mean.
INFO | 20/07/26 18:25:32 | nispace.api: Pre-ranking X and Y data.
Colocalizing (spearman, 4 proc): 100%|██████████████████████████████████████████████████| 1/1 [00:00<00:00, 1785.57it/s]
INFO | 20/07/26 18:25:35 | nispace.api: *** NiSpace.permute() - Estimate exact non-parametric p values. ***
INFO | 20/07/26 18:25:35 | nispace.api: Permutation of: Y maps.
INFO | 20/07/26 18:25:35 | nispace.api: Using default split null method (cx='moran', sc='moran') (cx space: 'MNI152NLin6Asym', sc space: 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:36 | nispace.api: Loading observed colocalizations (method = 'spearman').
INFO | 20/07/26 18:25:36 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:36 | nispace.api: Generating permuted Y maps.
INFO | 20/07/26 18:25:36 | nispace.core.permute: Generating null maps (n = 1000, null_method = 'moran+moran').
INFO | 20/07/26 18:25:36 | nispace.core.parcellation: Lazy-loading sc dist mat for 'TianS1' (space 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:36 | nispace.core.parcellation: Lazy-loading cx dist mat for 'Yan200' (space 'fsLR').
INFO | 20/07/26 18:25:36 | nispace.nulls: Split null method: cx='moran' (200 parcels), sc='moran' (16 parcels).
INFO | 20/07/26 18:25:36 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 200 parcels.
INFO | 20/07/26 18:25:36 | nispace.nulls: Using provided distance matrix/matrices.
Moran null maps (4 proc): 100%|██████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 802.58it/s]
INFO | 20/07/26 18:25:36 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:36 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 16 parcels.
INFO | 20/07/26 18:25:36 | nispace.nulls: Using provided distance matrix/matrices.

Moran null maps (4 proc): 100%|█████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1096.26it/s]
INFO | 20/07/26 18:25:38 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:38 | nispace.api: Running X Set Enrichment Analysis (XSEA) without set permutation.
INFO | 20/07/26 18:25:38 | nispace.api: Pre-ranking X and Y (null) data.
Processing null arrays (4 proc): 100%|█████████████████████████████████████████████| 1000/1000 [00:01<00:00, 969.61it/s]
INFO | 20/07/26 18:25:42 | nispace.api: Using precomputed per-gene statistics for XSEA null aggregation.
Null colocalizations (spearman, precomputed): 100%|██████████████████████████████| 1000/1000 [00:00<00:00, 12524.57it/s]
INFO | 20/07/26 18:25:42 | nispace.core.permute: Calculating exact p-values (tails = {'rho': 'upper'}).
INFO | 20/07/26 18:25:42 | nispace.api: *** NiSpace.correct_p() - Correct p values for multiple comparisons. ***
INFO | 20/07/26 18:25:42 | nispace.api: Correction method: 'meff_galwey', alpha: 0.05, dimension: 'array'.
INFO | 20/07/26 18:25:42 | nispace.api: Returning X dataframe:
| X_REDUCTION |
| False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Meff_X (galwey) = 3.99 (from 5 maps).
INFO | 20/07/26 18:25:42 | nispace.api: *** NiSpace.plot() - Plot colocalization results. ***
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Creating categorical plot for method spearman, colocalization stat rho.
INFO | 20/07/26 18:25:42 | nispace.plotting: Significance annotation: 0/5 p_uncorrected < 0.05, 0/5 p_meffgalwey < 0.05

../_images/nb_introduction_intro10_xsea_11_14.png
[8]:
(<Figure size 500x250 with 1 Axes>,
 <Axes: title={'center': "$Spearman's\\ Rho$ colocalization\n(permutation of $Y\\ maps$)"}, xlabel='$Rho$'>,
 <seaborn._core.plot.Plotter at 0x177f30f70>)

The xsea_aggregation_method parameter

By default, XSEA aggregates individual map correlations by taking the mean. Alternatively, you can use "median" or "absmean"/"absmedian", or even "weightedmean". The latter only works when the input dataset does have a 3-level index with set, map, and weight as levels.

In practice, "mean" is the most common and interpretable choice, but "absmean" (absolute mean) can be reasonable based on the context.

[9]:
# absmean aggregation
nsp_pet.colocalize("spearman", xsea=True, xsea_aggregation_method="absmean")
nsp_pet.permute("maps", maps_which="Y", n_perm=1000, p_tails="upper") # one-tailed p value in this case
nsp_pet.plot()
INFO | 20/07/26 18:25:42 | nispace.api: *** NiSpace.colocalize() - Estimating X & Y colocalizations. ***
INFO | 20/07/26 18:25:42 | nispace.api: Running 'spearman' colocalization.
INFO | 20/07/26 18:25:42 | nispace.api: Will perform X-set enrichment analysis (XSEA).
INFO | 20/07/26 18:25:42 | nispace.api: Using 5 sets with between 3 and 6 samples. Aggregating within-set colocalizations with: absmean.
INFO | 20/07/26 18:25:42 | nispace.api: Pre-ranking X and Y data.
Colocalizing (spearman, 4 proc): 100%|██████████████████████████████████████████████████| 1/1 [00:00<00:00, 2066.16it/s]
INFO | 20/07/26 18:25:42 | nispace.api: *** NiSpace.permute() - Estimate exact non-parametric p values. ***
INFO | 20/07/26 18:25:42 | nispace.api: Permutation of: Y maps.
INFO | 20/07/26 18:25:42 | nispace.api: Using default split null method (cx='moran', sc='moran') (cx space: 'MNI152NLin6Asym', sc space: 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:42 | nispace.api: Loading observed colocalizations (method = 'spearman').
INFO | 20/07/26 18:25:42 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Generating permuted Y maps.
INFO | 20/07/26 18:25:42 | nispace.core.permute: Found existing null maps.
INFO | 20/07/26 18:25:42 | nispace.api: Running X Set Enrichment Analysis (XSEA) without set permutation.
INFO | 20/07/26 18:25:42 | nispace.api: Pre-ranking X and Y (null) data.

Processing null arrays (4 proc): 100%|████████████████████████████████████████████| 1000/1000 [00:00<00:00, 9006.18it/s]
INFO | 20/07/26 18:25:42 | nispace.api: Using precomputed per-gene statistics for XSEA null aggregation.
Null colocalizations (spearman, precomputed): 100%|██████████████████████████████| 1000/1000 [00:00<00:00, 12109.74it/s]
INFO | 20/07/26 18:25:42 | nispace.core.permute: Calculating exact p-values (tails = {'rho': 'upper'}).
INFO | 20/07/26 18:25:42 | nispace.api: *** NiSpace.plot() - Plot colocalization results. ***
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 
INFO | 20/07/26 18:25:42 | nispace.api: Creating categorical plot for method spearman, colocalization stat rho.
INFO | 20/07/26 18:25:42 | nispace.plotting: Significance annotation: 0/5 p_uncorrected < 0.05, 0/5 p_meffgalwey < 0.05

../_images/nb_introduction_intro10_xsea_13_8.png
[9]:
(<Figure size 500x250 with 1 Axes>,
 <Axes: title={'center': "$Spearman's\\ Rho$ colocalization\n(permutation of $Y\\ maps$)"}, xlabel='$Rho$'>,
 <seaborn._core.plot.Plotter at 0x16de2ac10>)

XSEA via the workflow

For a one-liner version:

[10]:
from nispace.workflows import xsea

nsp_wf = xsea(
    y={"Pain": pain_map},
    x="mrna",
    x_collection="CellTypesPsychEncodeTPM",
    parcellation="Yan100+TianS1",
    colocalization_method="spearman",
    n_perm=1000,
    seed=42,
    n_proc=4,
    return_nispace_only=True,
)
INFO | 20/07/26 18:25:42 | nispace.workflows: Loading integrated mrna dataset as X data.
INFO | 20/07/26 18:25:42 | nispace.datasets: Loading mrna maps.
INFO | 20/07/26 18:25:43 | nispace.datasets: Loading integrated collection 'CellTypesPsychEncodeTPM' for dataset 'mrna'.
INFO | 20/07/26 18:25:43 | nispace.datasets: Filtering maps by collection.
INFO | 20/07/26 18:25:43 | nispace.datasets: Loading and inner-merging data parcellated with 'Yan100' and 'TianS1'
The NiSpace "mRNA" dataset contains whole-brain gene expression maps for > 10,000 genes based on
parcel-wise mapping. The dataset consists of Allen Brain Atlas mRNA expression data from postmortem
brain tissue of six donors (Hawrylycz et al., 2012), mapped onto MNI or fsaverage parcels using the
abagen toolbox (Markello et al., 2021; abagen.get_expression_data(..., lr_mirror="bidirectional",
norm_matched=False)). Gene stability was assessed using a voxel-level atlas at 8mm isotropic
resolution; genes were retained if their mean donor-to-donor Spearman rank correlation exceeded 0.2.
Please cite the source publications, as well as publications associated with gene set collections as
appropriate.
  - Hawrylycz et al., 2012  https://doi.org/10.1038/nature11405
  - Markello et al., 2021  https://doi.org/10.7554/eLife.72129
To ensure reproducibility, note the NiSpace version: 0.0.2b2.dev48+g51f21588b.d20260717 (commit: g51f21588b).

  [CellTypesPsychEncodeTPM] Lake et al., 2016  https://doi.org/10.1126/science.aaf1204
  [CellTypesPsychEncodeTPM] Darmanis et al., 2015  https://doi.org/10.1073/pnas.1507125112
  [CellTypesPsychEncodeTPM] Wang et al., 2018  https://doi.org/10.1126/science.aat8464
INFO | 20/07/26 18:25:43 | nispace.api: *** NiSpace.fit() - Data extraction and preparation. ***
INFO | 20/07/26 18:25:43 | nispace.core.parcellation: Building combined Parcellation 'Yan100+TianS1' from library.
INFO | 20/07/26 18:25:43 | nispace.core.parcellation:   Common MNI space(s) for combined: ['MNI152NLin2009cAsym', 'MNI152NLin6Asym'].
INFO | 20/07/26 18:25:43 | nispace.core.parcellation:   Merging 'Yan100' and 'TianS1' for space 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:43 | nispace.core.parcellation:   Merging 'Yan100' and 'TianS1' for space 'MNI152NLin6Asym'.
INFO | 20/07/26 18:25:43 | nispace.core.parcellation:   Fetching cx surface data for 'Yan100' in 'fsLR' (for spin tests).
INFO | 20/07/26 18:25:43 | nispace.core.parcellation:   Fetching cx surface data for 'Yan100' in 'fsaverage' (for spin tests).
INFO | 20/07/26 18:25:43 | nispace.core.parcellation: Combined parcellation 'Yan100+TianS1' ready. MNI space(s): ['MNI152NLin2009cAsym', 'MNI152NLin6Asym']. Cx surface space(s) for spins: ['fsLR', 'fsaverage'].
INFO | 20/07/26 18:25:43 | nispace.core.parcellation: Parcellation 'Yan100+TianS1': validation passed.
INFO | 20/07/26 18:25:44 | nispace.core.parcellation: Parcellation 'Yan100+TianS1': active space set to 'MNI152NLin2009cAsym'.
INFO | 20/07/26 18:25:44 | nispace.core.parcellation: Combined parcellation: cx-LH parcels = 50, cx-RH parcels = 50.
INFO | 20/07/26 18:25:44 | nispace.api: Checking input data for 'x' (should be, e.g., PET data):
INFO | 20/07/26 18:25:44 | nispace.io: Input type: DataFrame, assuming parcellated data with shape (n_files/subjects/etc, n_parcels).
INFO | 20/07/26 18:25:44 | nispace.api: Got 'x' data for 465 x 116 parcels.
INFO | 20/07/26 18:25:44 | nispace.api: Checking input data for 'y' (should be, e.g., subject data):
INFO | 20/07/26 18:25:44 | nispace.io: Input type: dict, assuming (img_name, img) pairs for imaging data.
INFO | 20/07/26 18:25:44 | nispace.io: Background (bg) handling: background_value='auto'; reporting bg-only parcels: False
INFO | 20/07/26 18:25:44 | nispace.io: Parcellating imaging data.
Parcellating (4 proc): 100%|████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2122.62it/s]
INFO | 20/07/26 18:25:44 | nispace.api: Got 'y' data for 1 x 116 parcels.
INFO | 20/07/26 18:25:44 | nispace.api: Z-standardizing 'X' data.
INFO | 20/07/26 18:25:44 | nispace.api: *** NiSpace.colocalize() - Estimating X & Y colocalizations. ***
INFO | 20/07/26 18:25:44 | nispace.api: Running 'spearman' colocalization.
INFO | 20/07/26 18:25:44 | nispace.api: Will perform X-set enrichment analysis (XSEA).
INFO | 20/07/26 18:25:44 | nispace.api: Using 24 sets with between 2 and 68 samples. Aggregating within-set colocalizations with: mean.
INFO | 20/07/26 18:25:44 | nispace.api: Pre-ranking X and Y data.
Colocalizing (spearman, 4 proc): 100%|██████████████████████████████████████████████████| 1/1 [00:00<00:00, 1821.23it/s]
INFO | 20/07/26 18:25:44 | nispace.api: *** NiSpace.permute() - Estimate exact non-parametric p values. ***
INFO | 20/07/26 18:25:44 | nispace.api: Permutation of: Y maps.
INFO | 20/07/26 18:25:44 | nispace.api: Using default split null method (cx='moran', sc='moran') (cx space: 'MNI152NLin6Asym', sc space: 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:45 | nispace.api: Loading observed colocalizations (method = 'spearman').
INFO | 20/07/26 18:25:45 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:45 | nispace.api: Generating permuted Y maps.
INFO | 20/07/26 18:25:45 | nispace.core.permute: Generating null maps (n = 1000, null_method = 'moran+moran').
INFO | 20/07/26 18:25:45 | nispace.core.parcellation: Lazy-loading sc dist mat for 'TianS1' (space 'MNI152NLin6Asym').
INFO | 20/07/26 18:25:45 | nispace.core.parcellation: Lazy-loading cx dist mat for 'Yan100' (space 'fsLR').
INFO | 20/07/26 18:25:45 | nispace.nulls: Split null method: cx='moran' (100 parcels), sc='moran' (16 parcels).
INFO | 20/07/26 18:25:45 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 100 parcels.
INFO | 20/07/26 18:25:45 | nispace.nulls: Using provided distance matrix/matrices.
Moran null maps (4 proc): 100%|█████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1831.57it/s]
INFO | 20/07/26 18:25:45 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:45 | nispace.nulls: Null map generation: Assuming n = 1 data vector(s) for n = 16 parcels.
INFO | 20/07/26 18:25:45 | nispace.nulls: Using provided distance matrix/matrices.

Moran null maps (4 proc): 100%|█████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1769.75it/s]
INFO | 20/07/26 18:25:45 | nispace.nulls: Null data generation finished.
INFO | 20/07/26 18:25:45 | nispace.api: Running X Set Enrichment Analysis (XSEA) without set permutation.
INFO | 20/07/26 18:25:45 | nispace.api: Pre-ranking X and Y (null) data.

Processing null arrays (4 proc): 100%|████████████████████████████████████████████| 1000/1000 [00:00<00:00, 8633.35it/s]
INFO | 20/07/26 18:25:45 | nispace.api: Using precomputed per-gene statistics for XSEA null aggregation.
Null colocalizations (spearman, precomputed): 100%|███████████████████████████████| 1000/1000 [00:00<00:00, 1211.65it/s]
INFO | 20/07/26 18:25:46 | nispace.core.permute: Calculating exact p-values (tails = {'rho': 'two'}).
INFO | 20/07/26 18:25:46 | nispace.api: *** NiSpace.correct_p() - Correct p values for multiple comparisons. ***
INFO | 20/07/26 18:25:46 | nispace.api: Correction method: 'meff_galwey', alpha: 0.05, dimension: 'array'.
INFO | 20/07/26 18:25:46 | nispace.api: Returning X dataframe:
| X_REDUCTION |
| False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Meff_X (galwey) = 10.41 (from 24 maps).
INFO | 20/07/26 18:25:46 | nispace.api: *** NiSpace.normalize_colocalizations() - Normalize colocalizations against null distribution. ***
INFO | 20/07/26 18:25:46 | nispace.api: Z-score method: robust (median/MAD).
INFO | 20/07/26 18:25:46 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Stored normalized colocalizations: xdimred-false_ytrans-false_coloc-spearman_stat-rho_xsea-true_perm-ymaps
INFO | 20/07/26 18:25:46 | nispace.api: *** NiSpace.plot() - Plot colocalization results. ***
INFO | 20/07/26 18:25:46 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Creating categorical plot for method spearman, colocalization stat rho.
INFO | 20/07/26 18:25:46 | nispace.plotting: Significance annotation: 1/24 p_uncorrected < 0.05, 0/24 p_meffgalwey < 0.05

../_images/nb_introduction_intro10_xsea_15_14.png
INFO | 20/07/26 18:25:46 | nispace.api: Returning colocalizations:
| METHOD   | XSEA | X_REDUCTION | Y_TRANSFORM |
| spearman | True | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | None      | False       | False       | 
INFO | 20/07/26 18:25:46 | nispace.api: Returning p values:
| METHOD   | PERMUTE_WHAT | XSEA | MC_METHOD  | X_REDUCTION | Y_TRANSFORM |
| spearman | ymaps        | True | meffgalwey | False       | False       | 
[11]:
# Save the main NiSpace object (with XSEA colocalization + permutation results)
# for use in the Regional Influence notebook (intro15)
nsp.to_pickle("intro10_nsp.pkl.blosc")

Summary

  • XSEA aggregates individual map colocalizations within predefined sets and tests the set-level mean.

  • Enable it by passing xsea="mean" (or "median") to colocalize().

  • Permutation testing works the same as for individual maps: permute("maps").

  • The default null model (map permutation) avoids inflation from within-set co-expression, following Fulcher et al. (2021).

  • ABAnnotate (the predecessor toolbox) used the same approach — XSEA in NiSpace is the generalized, multi-dataset version.

  • For the workflow version: xsea().

Next: Notebook 11 covers advanced topics: dimensionality reduction, multi-modal parcellations, alternative colocalization methods, and individual-level analyses.

To explore which brain regions drive the XSEA results computed here, see the Regional Influence notebook.