Skip to content

5 Simple Spatial Analysis

1
2
3
4
5
"""
Created on Mon May 16 19:00:32 2022
@author: Ajit Johnson Nirmal
SCIMAP tutorial May 2022
"""
1
2
3
4
5
# load packages
import scimap as sm
import scanpy as sc
import pandas as pd
import anndata as ad

Tutorial material

You can download the material for this tutorial from the following link:
The jupyter notebook is available here:

1
2
common_path = "/Users/aj/Dropbox (Partners HealthCare)/conferences/scimap_tutorial/may_2022_tutorial/"
#common_path = "C:/Users/ajn16/Dropbox (Partners HealthCare)/conferences/scimap_tutorial/may_2022_tutorial/"
1
2
3
4
5
6
7
# load data
#adata = sm.pp.mcmicro_to_scimap (image_path= str(common_path) + 'exemplar_001/quantification/unmicst-exemplar-001_cell.csv')
#manual_gate = pd.read_csv(str(common_path) + 'manual_gates.csv')
#adata = sm.pp.rescale (adata, gate=manual_gate)
#phenotype = pd.read_csv(str(common_path) + 'phenotype_workflow.csv')
#adata = sm.tl.phenotype_cells (adata, phenotype=phenotype, label="phenotype") 
# add user defined ROI's before proceeding
1
2
# load saved anndata object
adata = ad.read(str(common_path) + 'may2022_tutorial.h5ad')
1

Calculate distances between cell types

sm.tl.spatial_distance: The function allows users to calculate the average shortest between phenotypes or clusters of interest (3D data supported).

1
2
3
4
5
6
7
adata = sm.tl.spatial_distance (adata, 
                               x_coordinate='X_centroid', y_coordinate='Y_centroid', 
                               z_coordinate=None, 
                               phenotype='phenotype', 
                               subset=None, 
                               imageid='imageid', 
                               label='spatial_distance')
Processing Image: unmicst-exemplar-001_cell
1
adata.uns['spatial_distance']
Other Immune cells Unknown Myeloid Tumor ASMA+ cells Neutrophils Treg NK cells
unmicst-exemplar-001_cell_1 0.000000 508.809972 561.874000 547.544519 506.115689 581.323686 570.267087 1248.001853
unmicst-exemplar-001_cell_2 0.000000 25.516388 63.601485 67.024246 27.928445 157.289841 100.258654 816.837582
unmicst-exemplar-001_cell_3 0.000000 15.315383 59.503385 56.590105 34.479892 147.005355 96.374952 817.307871
unmicst-exemplar-001_cell_4 0.000000 28.482334 13.752853 51.500837 46.148651 111.763900 143.243322 746.050742
unmicst-exemplar-001_cell_5 26.357699 0.000000 45.589024 30.234937 58.354288 120.715789 96.739267 824.241184
... ... ... ... ... ... ... ... ...
unmicst-exemplar-001_cell_11166 0.000000 106.320078 70.605640 96.293073 50.637223 91.990689 43.229554 410.740868
unmicst-exemplar-001_cell_11167 0.000000 31.114913 72.531210 118.065360 54.921505 136.323479 30.072174 399.697389
unmicst-exemplar-001_cell_11168 0.000000 50.369768 70.748013 126.968337 36.065610 123.048957 40.094561 409.435592
unmicst-exemplar-001_cell_11169 0.000000 103.275795 64.057762 91.786425 64.741519 93.600860 35.697321 397.194037
unmicst-exemplar-001_cell_11170 10.165511 0.000000 88.288672 113.521913 86.006117 150.562555 23.735243 389.273701

11170 rows × 8 columns

1
2
3
4
# summary heatmap
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = [3, 1]
sm.pl.spatial_distance (adata)

png

1
2
# Heatmap without summarizing the individual images
sm.pl.spatial_distance (adata, heatmap_summarize=False)

png

1
sm.pl.spatial_distance (adata, heatmap_summarize=False, imageid='ROI_individual')

png

1
2
3
# Numeric plot of shortest distance of phenotypes 
# from tumor cells
sm.pl.spatial_distance (adata, method='numeric',distance_from='Tumor')

png

1
sm.pl.spatial_distance (adata, method='numeric',distance_from='Tumor', log=True)

png

1
2
# plot for each ROI seperately
sm.pl.spatial_distance (adata, method='numeric',distance_from='Tumor', imageid='ROI')

png

1
sm.pl.spatial_distance (adata, method='numeric',distance_from='Tumor', imageid='ROI', log=True)

png

1
2
3
# Distribution plot of shortest distance of phenotypes from Tumor cells
sm.pl.spatial_distance (adata, method='distribution',distance_from='Tumor',distance_to = 'ASMA+ cells',
    imageid='ROI_individual', log=True)

png

1

Spatial co-occurance analysis

sm.tl.spatial_interaction: The function allows users to computes how likely celltypes are found next to each another compared to random background (3D data supported).

1
2
3
4
5
# Using the radius method to identify local neighbours compute P-values
adata = sm.tl.spatial_interaction (adata, 
                                  method='radius', 
                                  radius=30, 
                                  label='spatial_interaction_radius')
Processing Image: ['unmicst-exemplar-001_cell']
Categories (1, object): ['unmicst-exemplar-001_cell']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
1
2
3
4
5
# Using the KNN method to identify local neighbours 
adata = sm.tl.spatial_interaction(adata, 
                                  method='knn', 
                                  knn=10, 
                                  label='spatial_interaction_knn')
Processing Image: ['unmicst-exemplar-001_cell']
Categories (1, object): ['unmicst-exemplar-001_cell']
Identifying the 10 nearest neighbours for every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
1
2
3
4
5
6
7
# view results
# spatial_interaction heatmap for a single image
sm.pl.spatial_interaction(adata, 
                          summarize_plot=True, 
                          binary_view=True,
                          spatial_interaction='spatial_interaction_radius',
                          row_cluster=False, linewidths=0.75, linecolor='black')

png

1
2
3
4
5
6
# spatial_interaction heatmap for a single image
sm.pl.spatial_interaction(adata, 
                          summarize_plot=True, 
                          binary_view=True,
                          spatial_interaction='spatial_interaction_knn',
                          row_cluster=False, linewidths=0.75, linecolor='black')

png

1
2
3
4
5
6
# Pass the ROI's as different images
adata = sm.tl.spatial_interaction(adata, 
                                  method='radius', 
                                  imageid = 'ROI_individual',
                                  radius=30, 
                                  label='spatial_interaction_radius_roi')
Processing Image: ['Other']
Categories (1, object): ['Other']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['artifacts']
Categories (1, object): ['artifacts']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-low-1']
Categories (1, object): ['CD57-low-1']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-low-3']
Categories (1, object): ['CD57-low-3']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-low-2']
Categories (1, object): ['CD57-low-2']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-high-3']
Categories (1, object): ['CD57-high-3']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-high-1']
Categories (1, object): ['CD57-high-1']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
Processing Image: ['CD57-high-2']
Categories (1, object): ['CD57-high-2']
Identifying neighbours within 30 pixels of every cell
Mapping phenotype to neighbors
Performing 1000 permutations
Consolidating the permutation results
1
2
3
4
5
# spatial_interaction heatmap
sm.pl.spatial_interaction(adata, 
                          summarize_plot=True, 
                          spatial_interaction='spatial_interaction_radius_roi',
                          row_cluster=True, linewidths=0.75, linecolor='black')

png

1
2
3
4
5
6
# spatial_interaction heatmap
sm.pl.spatial_interaction(adata, 
                          summarize_plot=False, 
                          spatial_interaction='spatial_interaction_radius_roi',
                          yticklabels=True,
                          row_cluster=True, linewidths=0.75, linecolor='black')

png

1

Quantifying the proximity score

sm.tl.spatial_pscore: A scoring system to evaluate user defined proximity between cell types.

The function generates two scores and saved at adata.uns:
- Proximity Density: Total number of interactions identified divided by the total number of cells of the cell-types that were used for interaction analysis.
- Proximity Volume: Total number of interactions identified divided by the total number of all cells in the data. The interaction sites are also recorded and saved in adata.obs

1
2
3
4
5
6
7
8
# Calculate the score for proximity between `Tumor CD30+` cells and `M2 Macrophages`
adata =  sm.tl.spatial_pscore (adata,proximity= ['Tumor', 'NK cells'],
                               score_by = 'ROI_individual',
                               phenotype='phenotype',
                               method='radius',
                               radius=20,
                               subset=None, 
                               label='spatial_pscore')
Identifying neighbours within 20 pixels of every cell
Finding neighbourhoods with Tumor
Finding neighbourhoods with NK cells
Please check:
adata.obs['spatial_pscore'] &
adata.uns['spatial_pscore'] for results
1
2
3
# Plot only `Proximity Volume` scores
plt.figure(figsize=(10, 5))
sm.pl.spatial_pscore (adata, color='Black', plot_score='Proximity Volume')
/opt/anaconda3/envs/scimap/lib/python3.9/site-packages/seaborn/_decorators.py:36: FutureWarning:

Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.

png

1
2
3
# Plot only `Proximity Density` scores
plt.figure(figsize=(10, 5))
sm.pl.spatial_pscore (adata, color='Black', plot_score='Proximity Density')
/opt/anaconda3/envs/scimap/lib/python3.9/site-packages/seaborn/_decorators.py:36: FutureWarning:

Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.

png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# voronoi plot
plt.rcParams['figure.figsize'] = [15, 10]
sm.pl.voronoi(adata, color_by='spatial_pscore', 
                 voronoi_edge_color = 'black',
                 voronoi_line_width = 0.3, 
                 voronoi_alpha = 0.8, 
                 size_max=5000,
                 overlay_points=None, 
                 plot_legend=True, 
                 legend_size=6)

png

1
2
# save adata
adata.write(str(common_path) + 'may2022_tutorial.h5ad')
/opt/anaconda3/envs/scimap/lib/python3.9/site-packages/anndata/_core/anndata.py:1228: FutureWarning:

The `inplace` parameter in pandas.Categorical.reorder_categories is deprecated and will be removed in a future version. Reordering categories will always return a new Categorical object.

... storing 'spatial_pscore' as categorical

This concludes this tutorial