🤏 CellCell Interaction / Proximity / CoOccurance Analysis
The sm.tl.spatial_interaction
function calculates the likelihood of cell types being adjacent to each other, compared to a permuted background, and supports 3D data. This analysis is based on cell centroids, with the option to determine neighbors either by a) a radius from the cell centroid or b) a fixed number of nearest neighbors. The measurement units depend on how the X and Y coordinates are computed. I recommend setting a neighborhood radius between 50100 microns. By default, MCMCIRO stores XY coordinates in pixels, necessitating a conversion from pixels to microns, which varies based on magnification, binning, and other settings during image acquisition.
 # import packages
import scimap as sm
import anndata as ad

 # Load the data that we saved in the last tutorial (with ROIs added)
adata = ad.read_h5ad('/Users/aj/Dropbox (Partners HealthCare)/nirmal lab/resources/exemplarData/scimapExampleData/scimapExampleData.h5ad')

 adata = sm.tl.spatial_interaction (adata,
method='radius',
radius=70,
label='spatial_interaction_radius')
# if you would like to use set nearest neighbours use method = 'knn' and knn=10

Processing Image: ['exemplar001unmicst_cell']
Categories (1, object): ['exemplar001unmicst_cell']
Identifying neighbours within 70 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Let's take a look at the results
 sm.pl.spatial_interaction(adata,
spatial_interaction='spatial_interaction_radius',
linewidths=0.75, linecolor='black', figsize=(5,4))

In the depicted plot, red and blue signify the likelihood of two cell types being adjacent to each other, while grey denotes interactions that lack significance.
It's important to understand that when analyzing multiple images, the results represent an average across all the images involved. Since the demo contains only one image, to simulate multiple images, let's once again utilize the ROIs, treating them as distinct images for analysis purposes.
 # rerun the analysis with passing ROI column
adata = sm.tl.spatial_interaction(adata,
method='radius',
imageid = 'ROI',
radius=70,
label='spatial_interaction_radius_roi')

Processing Image: ['Other']
Categories (1, object): ['Other']
Identifying neighbours within 70 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['ROI3']
Categories (1, object): ['ROI3']
Identifying neighbours within 70 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['ROI1']
Categories (1, object): ['ROI1']
Identifying neighbours within 70 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['ROI2']
Categories (1, object): ['ROI2']
Identifying neighbours within 70 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
 # view the results
sm.pl.spatial_interaction(adata,
spatial_interaction='spatial_interaction_radius_roi',
linewidths=0.75, linecolor='black', figsize=(5,4))

This reflects the average across the images (in this case, ROIs), but let's now proceed to visualize the data for each image individually by adding summarize_plot=False
 sm.pl.spatial_interaction(adata,
spatial_interaction='spatial_interaction_radius_roi',
yticklabels=True, figsize=(5,10), row_cluster=True,
summarize_plot=False,
linewidths=0.75, linecolor='black')

As seen above, each image (ROIs) is represented on the xaxis, with all pairs of interactions featured on the yaxis. The data is clustered, enabling the identification of the most significant interacting pairs across the images.
You can also set subset_phenotype
and subset_neighbour_phenotype
to specifically display only cell types of interest, which is particularly useful for publications.
Lastly, let me introduce a parameter named binary_view
. When set to True
, this parameter binarizes the heatmap, omitting the zscores for simpler interpretation.
 sm.pl.spatial_interaction(adata,
spatial_interaction='spatial_interaction_radius', binary_view=True,
linewidths=0.75, linecolor='black', figsize=(5,4))

Typically, I combine this with distance plots to understand cell distribution across the tissue. Utilizing both distance and interaction plots together effectively highlights interacting cell partners in manuscripts.
 # lastly we can also visualize the interactions as a network plot:
sm.pl.spatialInteractionNetwork(adata, spatial_interaction='spatial_interaction_radius', figsize=(6,4))

/Users/aj/miniconda3/envs/scimap/lib/python3.10/sitepackages/scipy/stats/_stats_py.py:9694: RuntimeWarning:
divide by zero encountered in log
Save Results
 # Save the results
adata.write('/Users/aj/Dropbox (Partners HealthCare)/nirmal lab/resources/exemplarData/scimapExampleData/scimapExampleData.h5ad')
