Note

Click here to download the full example code

# Building spatial neighbors graph

This example shows how to compute a spatial neighbors graph.

Spatial graph is a graph of spatial neighbors with observations as nodes and neighbor-hood relations between observations as edges. We use spatial coordinates of spots/cells to identify neighbors among them. Different approach of defining a neighborhood relation among observations are used for different types of spatial datasets.

```
import squidpy as sq
import numpy as np
```

First, we show how to compute the spatial neighbors graph for a Visium dataset.

```
adata = sq.datasets.visium_fluo_adata()
adata
```

Out:

```
0%| | 0.00/242M [00:00<?, ?B/s]
0%| | 24.0k/242M [00:00<23:11, 183kB/s]
0%| | 56.0k/242M [00:00<19:33, 216kB/s]
0%| | 120k/242M [00:00<12:34, 337kB/s]
0%| | 224k/242M [00:00<08:16, 510kB/s]
0%| | 464k/242M [00:00<04:19, 977kB/s]
0%| | 920k/242M [00:00<02:19, 1.81MB/s]
1%| | 1.78M/242M [00:00<01:13, 3.44MB/s]
1%|1 | 3.57M/242M [00:01<00:37, 6.72MB/s]
3%|2 | 6.55M/242M [00:01<00:21, 11.8MB/s]
4%|3 | 9.48M/242M [00:01<00:16, 15.1MB/s]
5%|5 | 12.5M/242M [00:01<00:13, 17.5MB/s]
6%|6 | 15.5M/242M [00:01<00:12, 19.2MB/s]
8%|7 | 18.5M/242M [00:01<00:11, 20.3MB/s]
9%|8 | 21.3M/242M [00:01<00:11, 20.9MB/s]
10%|9 | 23.7M/242M [00:02<00:11, 20.1MB/s]
11%|# | 26.6M/242M [00:02<00:10, 20.7MB/s]
12%|#2 | 29.5M/242M [00:02<00:10, 21.2MB/s]
13%|#3 | 32.5M/242M [00:02<00:10, 21.7MB/s]
15%|#4 | 35.4M/242M [00:02<00:09, 21.8MB/s]
16%|#5 | 38.2M/242M [00:02<00:09, 21.8MB/s]
17%|#6 | 41.1M/242M [00:02<00:09, 22.0MB/s]
18%|#8 | 43.7M/242M [00:03<00:09, 21.4MB/s]
19%|#9 | 46.7M/242M [00:03<00:09, 21.8MB/s]
20%|## | 49.6M/242M [00:03<00:09, 22.0MB/s]
22%|##1 | 52.6M/242M [00:03<00:08, 22.2MB/s]
23%|##2 | 55.5M/242M [00:03<00:08, 22.2MB/s]
24%|##4 | 58.3M/242M [00:03<00:08, 22.1MB/s]
25%|##5 | 61.2M/242M [00:03<00:08, 22.1MB/s]
26%|##6 | 64.2M/242M [00:03<00:08, 22.3MB/s]
28%|##7 | 67.0M/242M [00:04<00:08, 22.2MB/s]
29%|##8 | 70.0M/242M [00:04<00:08, 22.3MB/s]
30%|### | 72.9M/242M [00:04<00:07, 23.6MB/s]
31%|###1 | 75.4M/242M [00:04<00:07, 24.1MB/s]
32%|###1 | 76.5M/242M [00:04<00:08, 20.5MB/s]
33%|###2 | 79.2M/242M [00:04<00:07, 22.4MB/s]
34%|###3 | 81.4M/242M [00:04<00:07, 22.6MB/s]
35%|###4 | 84.1M/242M [00:04<00:06, 24.1MB/s]
35%|###5 | 85.3M/242M [00:04<00:07, 20.8MB/s]
36%|###6 | 87.9M/242M [00:05<00:07, 22.7MB/s]
37%|###7 | 90.1M/242M [00:05<00:07, 22.3MB/s]
38%|###8 | 92.4M/242M [00:05<00:06, 22.6MB/s]
39%|###8 | 93.9M/242M [00:05<00:07, 20.1MB/s]
40%|###9 | 96.9M/242M [00:05<00:07, 21.0MB/s]
41%|####1 | 99.8M/242M [00:05<00:06, 21.5MB/s]
42%|####2 | 103M/242M [00:05<00:07, 20.6MB/s]
44%|####3 | 106M/242M [00:05<00:06, 21.2MB/s]
45%|####4 | 108M/242M [00:06<00:06, 21.4MB/s]
46%|####5 | 111M/242M [00:06<00:06, 21.7MB/s]
47%|####7 | 114M/242M [00:06<00:06, 22.0MB/s]
48%|####8 | 117M/242M [00:06<00:05, 22.2MB/s]
50%|####9 | 120M/242M [00:06<00:05, 22.4MB/s]
51%|##### | 123M/242M [00:06<00:05, 21.7MB/s]
52%|#####1 | 126M/242M [00:06<00:05, 21.9MB/s]
53%|#####3 | 129M/242M [00:07<00:05, 22.1MB/s]
54%|#####4 | 132M/242M [00:07<00:05, 22.1MB/s]
56%|#####5 | 135M/242M [00:07<00:05, 22.3MB/s]
57%|#####6 | 138M/242M [00:07<00:04, 22.5MB/s]
58%|#####8 | 140M/242M [00:07<00:04, 22.6MB/s]
59%|#####9 | 143M/242M [00:07<00:04, 22.6MB/s]
60%|###### | 146M/242M [00:07<00:04, 22.6MB/s]
62%|######1 | 149M/242M [00:07<00:04, 23.3MB/s]
63%|######2 | 152M/242M [00:08<00:03, 24.0MB/s]
64%|######3 | 154M/242M [00:08<00:04, 22.4MB/s]
65%|######4 | 157M/242M [00:08<00:03, 24.2MB/s]
65%|######5 | 158M/242M [00:08<00:04, 21.4MB/s]
66%|######6 | 161M/242M [00:08<00:04, 21.2MB/s]
67%|######7 | 163M/242M [00:08<00:03, 22.3MB/s]
68%|######8 | 166M/242M [00:08<00:03, 22.2MB/s]
69%|######9 | 168M/242M [00:08<00:03, 22.7MB/s]
70%|####### | 170M/242M [00:08<00:03, 22.0MB/s]
71%|#######1 | 172M/242M [00:09<00:03, 20.9MB/s]
72%|#######2 | 175M/242M [00:09<00:03, 23.0MB/s]
73%|#######2 | 176M/242M [00:09<00:03, 20.7MB/s]
74%|#######3 | 179M/242M [00:09<00:03, 20.4MB/s]
75%|#######4 | 182M/242M [00:09<00:03, 21.0MB/s]
76%|#######6 | 184M/242M [00:09<00:02, 21.4MB/s]
77%|#######7 | 187M/242M [00:09<00:02, 21.6MB/s]
78%|#######8 | 190M/242M [00:09<00:02, 23.1MB/s]
79%|#######9 | 192M/242M [00:10<00:02, 23.8MB/s]
80%|######## | 194M/242M [00:10<00:02, 21.2MB/s]
81%|######## | 196M/242M [00:10<00:02, 20.4MB/s]
82%|########2 | 199M/242M [00:10<00:02, 21.2MB/s]
83%|########3 | 202M/242M [00:10<00:01, 21.5MB/s]
84%|########4 | 205M/242M [00:10<00:01, 22.0MB/s]
86%|########5 | 207M/242M [00:10<00:01, 22.2MB/s]
87%|########6 | 210M/242M [00:10<00:01, 22.3MB/s]
88%|########8 | 213M/242M [00:11<00:01, 22.3MB/s]
89%|########9 | 216M/242M [00:11<00:01, 22.4MB/s]
91%|######### | 219M/242M [00:11<00:01, 22.4MB/s]
92%|#########1| 222M/242M [00:11<00:00, 22.3MB/s]
93%|#########2| 225M/242M [00:11<00:00, 22.1MB/s]
94%|#########4| 228M/242M [00:11<00:00, 21.8MB/s]
95%|#########5| 231M/242M [00:11<00:00, 22.0MB/s]
96%|#########6| 234M/242M [00:12<00:00, 22.1MB/s]
98%|#########7| 236M/242M [00:12<00:00, 22.3MB/s]
99%|#########8| 239M/242M [00:12<00:00, 22.2MB/s]
100%|#########9| 242M/242M [00:12<00:00, 21.7MB/s]
100%|##########| 242M/242M [00:12<00:00, 20.5MB/s]
AnnData object with n_obs × n_vars = 2800 × 16562
obs: 'in_tissue', 'array_row', 'array_col', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'pct_counts_in_top_50_genes', 'pct_counts_in_top_100_genes', 'pct_counts_in_top_200_genes', 'pct_counts_in_top_500_genes', 'total_counts_MT', 'log1p_total_counts_MT', 'pct_counts_MT', 'n_counts', 'leiden', 'cluster'
var: 'gene_ids', 'feature_types', 'genome', 'MT', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts', 'n_cells', 'highly_variable', 'highly_variable_rank', 'means', 'variances', 'variances_norm'
uns: 'cluster_colors', 'hvg', 'leiden', 'leiden_colors', 'neighbors', 'pca', 'spatial', 'umap'
obsm: 'X_pca', 'X_umap', 'spatial'
varm: 'PCs'
obsp: 'connectivities', 'distances'
```

We use `squidpy.gr.spatial_neighbors()`

for this.
The function expects `coord_type = 'visium'`

by default.
We set this parameter here explicitly for clarity.
`n_rings`

should be used only for Visium datasets.
It specifies for each spot how many hexagonal rings of spots around
will be considered neighbors.

```
sq.gr.spatial_neighbors(adata, n_rings=2, coord_type="grid", n_neighs=6)
```

The function builds a spatial graph and saves its adjacency matrix
to `adata.obsp['spatial_connectivities']`

and weighted adjacency matrix to
`adata.obsp['spatial_distances']`

by default.
Note that it can also build a a graph from a square grid, just set `n_neighs = 4`

.

```
adata.obsp["spatial_connectivities"]
```

Out:

```
<2800x2800 sparse matrix of type '<class 'numpy.float64'>'
with 48240 stored elements in Compressed Sparse Row format>
```

The weights of the weighted adjacency matrix are ordinal numbers of hexagonal rings
in the case of `coord_type = 'visium'`

.

```
adata.obsp["spatial_distances"]
```

Out:

```
<2800x2800 sparse matrix of type '<class 'numpy.float64'>'
with 48240 stored elements in Compressed Sparse Row format>
```

We can visualize the neighbors of a point to better visualize what n_rings mean:

```
_, idx = adata.obsp["spatial_connectivities"][420, :].nonzero()
idx = np.append(idx, 420)
sq.pl.spatial_scatter(adata[idx, :], connectivity_key="spatial_connectivities", img=False, na_color="lightgrey")
```

Next, we show how to compute the spatial neighbors graph for a non-grid dataset.

```
adata = sq.datasets.imc()
adata
```

Out:

```
0%| | 0.00/1.50M [00:00<?, ?B/s]
2%|1 | 24.0k/1.50M [00:00<00:08, 183kB/s]
4%|3 | 56.0k/1.50M [00:00<00:07, 217kB/s]
6%|5 | 88.0k/1.50M [00:00<00:06, 227kB/s]
14%|#3 | 208k/1.50M [00:00<00:02, 493kB/s]
28%|##8 | 432k/1.50M [00:00<00:01, 921kB/s]
57%|#####6 | 872k/1.50M [00:00<00:00, 1.73MB/s]
100%|##########| 1.50M/1.50M [00:00<00:00, 1.91MB/s]
AnnData object with n_obs × n_vars = 4668 × 34
obs: 'cell type'
uns: 'cell type_colors'
obsm: 'spatial'
```

We use the same function for this with `coord_type = 'generic'`

.
`n_neighs`

and `radius`

can be used for non-Visium datasets.
`n_neighs`

specifies a fixed number of the closest spots for each spot as neighbors.
Alternatively, `delaunay = True`

can be used, for a Delaunay triangulation graph.

```
sq.gr.spatial_neighbors(adata, n_neighs=10, coord_type="generic")
_, idx = adata.obsp["spatial_connectivities"][420, :].nonzero()
idx = np.append(idx, 420)
sq.pl.spatial_scatter(adata[idx, :], shape=None, color="cell type", connectivity_key="spatial_connectivities", size=100)
```

Out:

```
/home/runner/work/squidpy_notebooks/squidpy_notebooks/.tox/docs/lib/python3.9/site-packages/squidpy/pl/_color_utils.py:26: ImplicitModificationWarning: Trying to modify attribute `._uns` of view, initializing view as actual.
target.uns[color_key] = source.uns[color_key]
/home/runner/work/squidpy_notebooks/squidpy_notebooks/.tox/docs/lib/python3.9/site-packages/squidpy/pl/_spatial_utils.py:956: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap', 'norm' will be ignored
_cax = scatter(
```

We use the same function for this with `coord_type = 'generic'`

and `delaunay = True`

.
You can appreciate that the neighbor graph is slightly different than before.

```
sq.gr.spatial_neighbors(adata, delaunay=True, coord_type="generic")
_, idx = adata.obsp["spatial_connectivities"][420, :].nonzero()
idx = np.append(idx, 420)
sq.pl.spatial_scatter(
adata[idx, :],
shape=None,
color="cell type",
connectivity_key="spatial_connectivities",
size=100,
)
```

Out:

```
/home/runner/work/squidpy_notebooks/squidpy_notebooks/.tox/docs/lib/python3.9/site-packages/squidpy/pl/_color_utils.py:26: ImplicitModificationWarning: Trying to modify attribute `._uns` of view, initializing view as actual.
target.uns[color_key] = source.uns[color_key]
/home/runner/work/squidpy_notebooks/squidpy_notebooks/.tox/docs/lib/python3.9/site-packages/squidpy/pl/_spatial_utils.py:956: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap', 'norm' will be ignored
_cax = scatter(
```

In order to get all spots within a specified radius (in units of the spatial coordinates)
from each spot as neighbors, the parameter `radius`

should be used.

```
sq.gr.spatial_neighbors(adata, radius=0.3, coord_type="generic")
adata.obsp["spatial_connectivities"]
adata.obsp["spatial_distances"]
```

Out:

```
<4668x4668 sparse matrix of type '<class 'numpy.float64'>'
with 0 stored elements in Compressed Sparse Row format>
```

**Total running time of the script:** ( 0 minutes 26.994 seconds)

**Estimated memory usage:** 234 MB