Example notebook demonstrating how to use the sq.gr.calculate_niche() method

import squidpy as sq
import scanpy as sc
import pandas as pd
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings("ignore")
%load_ext autoreload
%autoreload 2
%matplotlib inline

Example notebook demonstrating how to use the sq.gr.calculate_niche() method#

Let’s first get get some data#

load example data with cell type annotation:

adata = sq.datasets.merfish()

# the dataset contains multiple slides, we only use one for now
adata = adata[adata.obs.Bregma == -9]

# we'll use this later for plotting
sc.pp.neighbors(adata)
sc.tl.umap(adata)

adata
# the `Cell_class` column is the cell type annotation
AnnData object with n_obs × n_vars = 6185 × 161
    obs: 'Cell_ID', 'Animal_ID', 'Animal_sex', 'Behavior', 'Bregma', 'Centroid_X', 'Centroid_Y', 'Cell_class', 'Neuron_cluster_ID', 'batch'
    uns: 'Cell_class_colors', 'pca', 'neighbors', 'umap'
    obsm: 'spatial', 'spatial3d', 'X_pca', 'X_umap'
    varm: 'PCs'
    obsp: 'distances', 'connectivities'

Every niche method requires a spatial neighborhood graph, which is why sq.gr.spatial_neighbors needs to be run first.

sq.gr.spatial_neighbors(adata, coord_type="generic", delaunay=False, n_neighs=20)
fig, axs = plt.subplots(ncols=2, nrows=1, figsize=(13, 6))

sq.pl.spatial_scatter(adata, color="Cell_class", shape=None, legend_loc=None, ax=axs[0])

sc.pl.umap(adata, color="Cell_class", ax=axs[1])

plt.tight_layout()
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/5cd0c451c2481d0df0b498ca3288ecfc5d0968ff48040b9804e5d44aa0fc904e.png
<Figure size 640x480 with 0 Axes>

Neighborhood approach#

adapted from immunitastx/monkeybread

sq.gr.calculate_niche(
    adata,
    groups="Cell_class",
    flavor="neighborhood",
    n_neighbors=10,
    resolutions=[0.5, 1.0],
)
adata
AnnData object with n_obs × n_vars = 6185 × 161
    obs: 'Cell_ID', 'Animal_ID', 'Animal_sex', 'Behavior', 'Bregma', 'Centroid_X', 'Centroid_Y', 'Cell_class', 'Neuron_cluster_ID', 'batch', 'nhood_niche_res=0.5', 'nhood_niche_res=1.0'
    uns: 'Cell_class_colors', 'pca', 'neighbors', 'umap', 'spatial_neighbors'
    obsm: 'spatial', 'spatial3d', 'X_pca', 'X_umap'
    varm: 'PCs'
    obsp: 'distances', 'connectivities', 'spatial_connectivities', 'spatial_distances'

The niche result is now stored in adata.obs. One column per resolution is created, indicating the niche assignment.

adata.obs
Cell_ID Animal_ID Animal_sex Behavior Bregma Centroid_X Centroid_Y Cell_class Neuron_cluster_ID batch nhood_niche_res=0.5 nhood_niche_res=1.0
41437-4 8c7df84c-8a53-4aa4-86fd-26e575de9b0e 1 Female Naive -9.0 1313.511887 2162.459959 Microglia nan 4 2 34
41438-4 3617ee7c-c0a8-4f18-b9bd-c7ca737ff665 1 Female Naive -9.0 1321.787911 2288.708578 Astrocyte nan 4 2 1
41439-4 f0d0277a-cac1-4181-8528-abfd9a5403c0 1 Female Naive -9.0 1333.694106 2116.464893 Astrocyte nan 4 2 34
41440-4 2dbbce4f-c54f-4df8-aced-590c971db48a 1 Female Naive -9.0 1339.956433 2200.067589 Astrocyte nan 4 2 1
41441-4 74d3f69d-e8f2-4c33-a8ca-fac3eb65e55a 1 Female Naive -9.0 1340.563484 2251.463695 Endothelial 1 nan 4 2 1
... ... ... ... ... ... ... ... ... ... ... ... ...
47617-4 7a0e3ee6-aa12-4ed8-80ae-465e186caa3f 1 Female Naive -9.0 3060.524623 3700.928535 Inhibitory I-9 4 18 18
47618-4 6a2e534c-e94e-45d0-ae8b-a0459133d53b 1 Female Naive -9.0 3096.962169 3534.935314 Inhibitory I-18 4 8 9
47619-4 0e5b91a1-43f1-4821-8d36-ec587850de66 1 Female Naive -9.0 2907.293885 3524.461287 Ambiguous nan 4 14 12
47620-4 cc5fb740-cdd3-4456-999e-ad433c68d350 1 Female Naive -9.0 2908.555041 3568.968505 Ambiguous nan 4 14 12
47621-4 bf1b8cd7-76d3-4225-9ad9-751b2625987b 1 Female Naive -9.0 3097.514301 3736.664268 Inhibitory I-18 4 18 18

6185 rows × 12 columns

Visualize the result by comparing it to the cell type annotation:

sq.pl.spatial_scatter(
    adata,
    color=["Cell_class", "nhood_niche_res=0.5", "nhood_niche_res=1.0"],
    shape=None,
    figsize=(7, 7),
)
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/eb100082de2e9eff8cd841787dd167086aaa37c23e2892c7727820f565731bf1.png

This particular method allows us to use the distance and n_hop_weights parameters to control how we define the neighborhood. When distance is set to 1, the neighborhood is defined by the 1-hop neighbors. When distance is set to 2, the neighborhood is defined by the 2-hop neighbors, and so on. The n_hop_weights parameter is a list of weights for the different hop distances. When n_hop_weights is not provided, all hop distances are weighted equally.

sq.gr.calculate_niche(
    adata,
    groups="Cell_class",
    flavor="neighborhood",
    n_neighbors=10,
    resolutions=0.25,
    distance=3,
    n_hop_weights=[1, 0.7, 0.25],
)
fig, axs = plt.subplots(ncols=2, nrows=1, figsize=(13, 6))

sq.pl.spatial_scatter(
    adata, color="nhood_niche_res=0.25", shape=None, ax=axs[0], legend_loc=None
)

sc.pl.umap(adata, color="nhood_niche_res=0.25", ax=axs[1])
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/e1bf347184e770735fe09410a7eea83efaee5106367b682c0a6dae99431d7af7.png

UATG#

adapted from ElementoLab/utag

Next we follow the UTAG approach, which doesn’t require a previous annotation.

sq.gr.calculate_niche(adata, flavor="utag", n_neighbors=15, resolutions=[0.1, 0.5, 1.0])
adata.obs
Cell_ID Animal_ID Animal_sex Behavior Bregma Centroid_X Centroid_Y Cell_class Neuron_cluster_ID batch nhood_niche_res=0.5 nhood_niche_res=1.0 nhood_niche_res=0.25 utag_niche_res=0.1 utag_niche_res=0.5 utag_niche_res=1.0
41437-4 8c7df84c-8a53-4aa4-86fd-26e575de9b0e 1 Female Naive -9.0 1313.511887 2162.459959 Microglia nan 4 2 34 6 1 17 30
41438-4 3617ee7c-c0a8-4f18-b9bd-c7ca737ff665 1 Female Naive -9.0 1321.787911 2288.708578 Astrocyte nan 4 2 1 6 1 17 30
41439-4 f0d0277a-cac1-4181-8528-abfd9a5403c0 1 Female Naive -9.0 1333.694106 2116.464893 Astrocyte nan 4 2 34 6 1 17 30
41440-4 2dbbce4f-c54f-4df8-aced-590c971db48a 1 Female Naive -9.0 1339.956433 2200.067589 Astrocyte nan 4 2 1 6 1 17 30
41441-4 74d3f69d-e8f2-4c33-a8ca-fac3eb65e55a 1 Female Naive -9.0 1340.563484 2251.463695 Endothelial 1 nan 4 2 1 6 1 17 30
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
47617-4 7a0e3ee6-aa12-4ed8-80ae-465e186caa3f 1 Female Naive -9.0 3060.524623 3700.928535 Inhibitory I-9 4 18 18 2 0 6 3
47618-4 6a2e534c-e94e-45d0-ae8b-a0459133d53b 1 Female Naive -9.0 3096.962169 3534.935314 Inhibitory I-18 4 8 9 1 0 6 3
47619-4 0e5b91a1-43f1-4821-8d36-ec587850de66 1 Female Naive -9.0 2907.293885 3524.461287 Ambiguous nan 4 14 12 3 0 1 3
47620-4 cc5fb740-cdd3-4456-999e-ad433c68d350 1 Female Naive -9.0 2908.555041 3568.968505 Ambiguous nan 4 14 12 3 0 1 3
47621-4 bf1b8cd7-76d3-4225-9ad9-751b2625987b 1 Female Naive -9.0 3097.514301 3736.664268 Inhibitory I-18 4 18 18 2 0 6 3

6185 rows × 16 columns

Visualize the results:

sq.pl.spatial_scatter(
    adata,
    color=[
        "Cell_class",
        "utag_niche_res=0.1",
        "utag_niche_res=0.5",
        "utag_niche_res=1.0",
    ],
    shape=None,
    figsize=(7, 7),
)
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/f3d6a3724370b7a6ef108f6b4a436f7e323ccadcc51152a9cf4535f4317f916d.png

Cellcharter#

adapted from CSOgroup/cellcharter

For the Cellcharter approach, multiple neighborhood based matrices are aggregated, dimensionality reduced, then clustered. The advantage of this method is, it doesn’t require any annotation and we can decide the amount of niches we expect.

Here we choose 5 clusters and aggregate 3 n-hop neighbor matrices.

sq.gr.calculate_niche(adata, flavor="cellcharter", n_components=10, distance=2)
adata.obs
Cell_ID Animal_ID Animal_sex Behavior Bregma Centroid_X Centroid_Y Cell_class Neuron_cluster_ID batch nhood_niche_res=0.5 nhood_niche_res=1.0 nhood_niche_res=0.25 utag_niche_res=0.1 utag_niche_res=0.5 utag_niche_res=1.0 cellcharter_niche
41437-4 8c7df84c-8a53-4aa4-86fd-26e575de9b0e 1 Female Naive -9.0 1313.511887 2162.459959 Microglia nan 4 2 34 6 1 17 30 5
41438-4 3617ee7c-c0a8-4f18-b9bd-c7ca737ff665 1 Female Naive -9.0 1321.787911 2288.708578 Astrocyte nan 4 2 1 6 1 17 30 5
41439-4 f0d0277a-cac1-4181-8528-abfd9a5403c0 1 Female Naive -9.0 1333.694106 2116.464893 Astrocyte nan 4 2 34 6 1 17 30 5
41440-4 2dbbce4f-c54f-4df8-aced-590c971db48a 1 Female Naive -9.0 1339.956433 2200.067589 Astrocyte nan 4 2 1 6 1 17 30 5
41441-4 74d3f69d-e8f2-4c33-a8ca-fac3eb65e55a 1 Female Naive -9.0 1340.563484 2251.463695 Endothelial 1 nan 4 2 1 6 1 17 30 9
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
47617-4 7a0e3ee6-aa12-4ed8-80ae-465e186caa3f 1 Female Naive -9.0 3060.524623 3700.928535 Inhibitory I-9 4 18 18 2 0 6 3 4
47618-4 6a2e534c-e94e-45d0-ae8b-a0459133d53b 1 Female Naive -9.0 3096.962169 3534.935314 Inhibitory I-18 4 8 9 1 0 6 3 6
47619-4 0e5b91a1-43f1-4821-8d36-ec587850de66 1 Female Naive -9.0 2907.293885 3524.461287 Ambiguous nan 4 14 12 3 0 1 3 4
47620-4 cc5fb740-cdd3-4456-999e-ad433c68d350 1 Female Naive -9.0 2908.555041 3568.968505 Ambiguous nan 4 14 12 3 0 1 3 2
47621-4 bf1b8cd7-76d3-4225-9ad9-751b2625987b 1 Female Naive -9.0 3097.514301 3736.664268 Inhibitory I-18 4 18 18 2 0 6 3 4

6185 rows × 17 columns

fig, axs = plt.subplots(ncols=3, nrows=1, figsize=(30, 6))

sq.pl.spatial_scatter(adata, color="Cell_class", shape=None, ax=axs[0])

sq.pl.spatial_scatter(adata, color="cellcharter_niche", shape=None, ax=axs[1])

sc.pl.umap(adata, color="cellcharter_niche", ax=axs[2])

plt.tight_layout()
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/322c4a3c8cb7df86fa6e79d23a519b104032ab49f010c65b7cffa21561276feb.png
<Figure size 640x480 with 0 Axes>

Using library_key#

Prepare the data#

import pandas as pd


adata_all = sq.datasets.merfish()

# prettify column we'll use as library_key
adata_all.obs["Bregma"] = adata_all.obs["Bregma"].astype(int)
adata_all.obs["Bregma"] = pd.Categorical(adata_all.obs["Bregma"])

sq.gr.spatial_neighbors(adata_all, coord_type="generic", delaunay=False, n_neighs=20)

Neighborhood approach#

sq.gr.calculate_niche(
    adata_all,
    groups="Cell_class",
    flavor="neighborhood",
    library_key="Bregma",
    n_neighbors=20,
    resolutions=0.1,
)
INFO     Stratifying by library_key 'Bregma'                                                                       
INFO     Processing library '-28'                                                                                  
INFO     Processing library '-24'                                                                                  
INFO     Processing library '-19'                                                                                  
INFO     Processing library '-14'                                                                                  
INFO     Processing library '-9'                                                                                   
INFO     Processing library '-4'                                                                                   
INFO     Processing library '1'                                                                                    
INFO     Processing library '6'                                                                                    
INFO     Processing library '11'                                                                                   
INFO     Processing library '16'                                                                                   
INFO     Processing library '21'                                                                                   
INFO     Processing library '26'                                                                                   
fig, axs = plt.subplots(ncols=4, nrows=3, figsize=(22, 12))
libraries = sorted(adata_all.obs["Bregma"].unique())

# like this instead of inside the spatial_scatter call due to the number of colors
for i, ax in enumerate(axs.flatten()):
    adata_subset = adata_all[adata_all.obs["Bregma"] == libraries[i]]
    sq.pl.spatial_scatter(
        adata_subset, color="nhood_niche_res=0.1", shape=None, legend_loc="None", ax=ax
    )

plt.tight_layout()
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/42f70fa552be5d41ebb0922f7f67e7329e1500a2b199de08a438d1ff371e829f.png

UTAG#

sq.gr.calculate_niche(
    adata_all, flavor="utag", library_key="Bregma", n_neighbors=15, resolutions=0.5
)
INFO     Stratifying by library_key 'Bregma'                                                                       
INFO     Processing library '-28'                                                                                  
INFO     Processing library '-24'                                                                                  
INFO     Processing library '-19'                                                                                  
INFO     Processing library '-14'                                                                                  
INFO     Processing library '-9'                                                                                   
INFO     Processing library '-4'                                                                                   
INFO     Processing library '1'                                                                                    
INFO     Processing library '6'                                                                                    
INFO     Processing library '11'                                                                                   
INFO     Processing library '16'                                                                                   
INFO     Processing library '21'                                                                                   
INFO     Processing library '26'                                                                                   
fig, axs = plt.subplots(ncols=4, nrows=3, figsize=(22, 12))
libraries = sorted(adata_all.obs["Bregma"].unique())

# like this instead of inside the spatial_scatter call due to the number of colors
for i, ax in enumerate(axs.flatten()):
    adata_subset = adata_all[adata_all.obs["Bregma"] == libraries[i]]
    sq.pl.spatial_scatter(adata_subset, color="utag_niche_res=0.5", shape=None, ax=ax)

plt.tight_layout()
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/4cc4e08e2d102d23db3b4c192d85fc1e4a6944291fe77a5082ab27cecbbadd17.png

CellCharter#

sq.gr.calculate_niche(
    adata_all, flavor="cellcharter", library_key="Bregma", n_components=10, distance=2
)
INFO     Stratifying by library_key 'Bregma'                                                                       
INFO     Processing library '-28'                                                                                  
INFO     Processing library '-24'                                                                                  
INFO     Processing library '-19'                                                                                  
INFO     Processing library '-14'                                                                                  
INFO     Processing library '-9'                                                                                   
INFO     Processing library '-4'                                                                                   
INFO     Processing library '1'                                                                                    
INFO     Processing library '6'                                                                                    
INFO     Processing library '11'                                                                                   
INFO     Processing library '16'                                                                                   
INFO     Processing library '21'                                                                                   
INFO     Processing library '26'                                                                                   
fig, axs = plt.subplots(ncols=4, nrows=3, figsize=(22, 12))
libraries = sorted(adata_all.obs["Bregma"].unique())

# like this instead of inside the spatial_scatter call due to the number of colors
for i, ax in enumerate(axs.flatten()):
    adata_subset = adata_all[adata_all.obs["Bregma"] == libraries[i]]
    sq.pl.spatial_scatter(adata_subset, color="cellcharter_niche", shape=None, ax=ax)

plt.tight_layout()
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
WARNING: Please specify a valid `library_id` or set it permanently in `adata.uns['spatial']`
../../../_images/f438e3164e8c70ab77ced68870af49b8576d59665277aee537da2476bc021708.png