# 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()
```

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)
```

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

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

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 = 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 = np.append(idx, 420)
sq.pl.spatial_scatter(
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")

```<4668x4668 sparse matrix of type '<class 'numpy.float64'>'