Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
5c08081
init
selmanozleyen Apr 2, 2026
5847d84
doc clarifications
selmanozleyen Apr 2, 2026
179ba06
don't expose the builders
selmanozleyen Apr 2, 2026
e187aba
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 2, 2026
cdb5699
deduplicate
selmanozleyen Apr 2, 2026
847a46b
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 2, 2026
69cda1a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 2, 2026
fddc027
arrange builders
selmanozleyen Apr 2, 2026
a30988a
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 2, 2026
f194b10
better behaviour
selmanozleyen Apr 2, 2026
ae1eba1
move classes
selmanozleyen Apr 2, 2026
a86572b
Merge branch 'main' into feat/spatial_neighbours
selmanozleyen Apr 2, 2026
039b852
cleanup
selmanozleyen Apr 2, 2026
4699993
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 2, 2026
b5dcf9f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 2, 2026
4c11adf
add docs
selmanozleyen Apr 2, 2026
2b937e9
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 2, 2026
ea1ce93
remove leftover
selmanozleyen Apr 2, 2026
ebb7fd5
resolution in reolve func
selmanozleyen Apr 2, 2026
69a9394
reduce dup code
selmanozleyen Apr 2, 2026
77755ed
deprecate invalid n_neighs
selmanozleyen Apr 2, 2026
d8a8145
expose new functions and deprecate the flat one
selmanozleyen Apr 2, 2026
2e75b3f
move branches to classes
selmanozleyen Apr 2, 2026
8c1c2ef
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 2, 2026
268d30c
remove radius abstraction
selmanozleyen Apr 2, 2026
3f41243
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 2, 2026
aa9734a
add extensibility page
selmanozleyen Apr 2, 2026
67bad43
unprivate methods and add extensibility page
selmanozleyen Apr 2, 2026
65fa245
give a better example
selmanozleyen Apr 2, 2026
85bfdeb
apply signature suggestion
selmanozleyen Apr 9, 2026
79f584f
reorganize abstractions
selmanozleyen Apr 9, 2026
43cdbb6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 9, 2026
e632f74
remove unnecessary abstraction
selmanozleyen Apr 9, 2026
1f9da0e
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 9, 2026
c026860
put the warning in resolve graph builder code
selmanozleyen Apr 9, 2026
10cc2f0
remove n_neighs from RadiusBuilder
selmanozleyen Apr 9, 2026
6477f18
definition of Adj, Dst and rename to adj, dst
selmanozleyen Apr 9, 2026
516b3e0
Generalize the base class for extensibility
selmanozleyen Apr 10, 2026
141fdb6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 10, 2026
1fe316b
update docs
selmanozleyen Apr 10, 2026
bc6746a
Merge branch 'feat/spatial_neighbours' of https://github.com/selmanoz…
selmanozleyen Apr 10, 2026
bb1ec50
clarify delauney vs grid
selmanozleyen Apr 10, 2026
84cbdc4
dtype rec
selmanozleyen Apr 10, 2026
6d942ec
be a bit more verbose on funcitons
selmanozleyen Apr 10, 2026
ae9a4e6
spatial_neighbours_from_builder
selmanozleyen Apr 10, 2026
cd3f6fd
update docs to refer to each other
selmanozleyen Apr 10, 2026
95012dc
refer to the classes properly
selmanozleyen Apr 10, 2026
5a02b59
mark as TODO's
selmanozleyen Apr 13, 2026
3af98cc
rename sugg
selmanozleyen Apr 13, 2026
e8a19d7
add combine into API
selmanozleyen Apr 13, 2026
ac682a3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 13, 2026
0f3329c
update docs
selmanozleyen Apr 13, 2026
00ec2b0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 13, 2026
042f749
[pre-commit.ci] pre-commit autoupdate (#1149)
pre-commit-ci[bot] Apr 10, 2026
1a87841
Functions to QC histopathology images (#1036)
timtreis Apr 10, 2026
1cb6fde
remove coord_type abstraction
selmanozleyen Apr 13, 2026
8afcd03
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 13, 2026
3c4dffb
Merge branch 'main' into feat/spatial_neighbours
selmanozleyen Apr 13, 2026
21f02c3
make builder positional consistently
selmanozleyen Apr 13, 2026
744c757
make more abstractions
selmanozleyen Apr 13, 2026
dbc7f0d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 13, 2026
d7e5e5f
graphmatrixT exposure
selmanozleyen Apr 13, 2026
13768e2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 13, 2026
ea3f3ca
Merge branch 'main' into feat/spatial_neighbours
selmanozleyen Apr 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ import squidpy as sq
:toctree: api

gr.spatial_neighbors
gr.spatial_neighbors_from_builder
gr.spatial_neighbors_knn
gr.spatial_neighbors_radius
gr.spatial_neighbors_delaunay
gr.spatial_neighbors_grid
gr.GraphMatrixT
gr.SpatialNeighborsResult
gr.mask_graph
gr.nhood_enrichment
Expand Down Expand Up @@ -109,3 +115,27 @@ import squidpy as sq
datasets.visium_hne_image_crop
datasets.visium_fluo_image_crop
```


## Extensibility

See the {doc}`extensibility guide </extensibility>` for how to implement a custom graph builder.

```{eval-rst}
.. module:: squidpy.gr.neighbors
.. currentmodule:: squidpy
.. autosummary::
:toctree: api

gr.neighbors.GraphBuilder
gr.neighbors.GraphBuilderCSR
gr.neighbors.GraphMatrixT
gr.neighbors.GraphPostprocessor
gr.neighbors.DistanceIntervalPostprocessor
gr.neighbors.PercentilePostprocessor
gr.neighbors.TransformPostprocessor
gr.neighbors.KNNBuilder
gr.neighbors.RadiusBuilder
gr.neighbors.DelaunayBuilder
gr.neighbors.GridBuilder
```
104 changes: 104 additions & 0 deletions docs/extensibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Extensibility

## Custom graph builders

The `squidpy.gr.neighbors` module exposes two builder base classes:

- {class}`~squidpy.gr.neighbors.GraphBuilder` is the generic builder pipeline.
Use it when you want to plug in a custom coordinate type or sparse-matrix backend.
- {class}`~squidpy.gr.neighbors.GraphBuilderCSR` is the CSR-specialized builder used
by the built-in graph construction strategies. Use it when your builder returns
{class}`~scipy.sparse.csr_matrix` objects and should reuse Squidpy's CSR-specific
postprocessors, sparse warning suppression, and multi-library combination.
- Reusable postprocessors such as
{class}`~squidpy.gr.neighbors.DistanceIntervalPostprocessor`,
{class}`~squidpy.gr.neighbors.PercentilePostprocessor`, and
{class}`~squidpy.gr.neighbors.TransformPostprocessor` are also exposed for
custom builder composition.

### What to override

| Base class | Method / property | Required | Purpose |
|---|---|---|---|
| {class}`~squidpy.gr.neighbors.GraphBuilder` | {meth}`~squidpy.gr.neighbors.GraphBuilder.build_graph` | yes | Construct and return ``(adj, dst)`` using the coordinate and matrix types of your custom backend. |
| {class}`~squidpy.gr.neighbors.GraphBuilder` | {meth}`~squidpy.gr.neighbors.GraphBuilder.postprocessors` | no | Return post-build processing steps for ``(adj, dst)``. You can either override this or pass ``postprocessors=...`` to ``super().__init__()``. |
| {class}`~squidpy.gr.neighbors.GraphBuilder` | {meth}`~squidpy.gr.neighbors.GraphBuilder.combine` | no | Combine per-library results when using ``library_key``. If you do not need ``library_key`` support, leaving this unimplemented is fine. |


The generic builder only defines the pipeline. The CSR-specialized builder adds
multi-library ``library_key`` combination and
{class}`~scipy.sparse.SparseEfficiencyWarning` suppression, while built-in and
custom CSR builders can compose the public reusable postprocessors for
distance-interval pruning, percentile filtering, and adjacency transforms.

Here ``adj`` and ``dst`` are square sparse matrices of shape ``(n_obs, n_obs)``
with matching sparsity structure:

- ``adj`` is the connectivity / adjacency matrix. Non-zero entries mark edges in
the graph, and built-in builders typically use ``1.0`` for present edges.
- ``dst`` is the distance matrix for those same edges. For generic graphs this is
usually the Euclidean edge length. For grid builders it may instead encode
graph-distance semantics such as ring number.
Comment thread
selmanozleyen marked this conversation as resolved.
- When subclassing {class}`~squidpy.gr.neighbors.GraphBuilderCSR`, both should be
returned as {class}`~scipy.sparse.csr_matrix`.
- For CSR-based builders, ``adj`` often behaves like a boolean or indicator
matrix describing whether an edge is present, even if it is stored with a
numeric dtype such as ``float32``. ``dst`` stores edge-associated values such
as distances and will often use a floating-point dtype. The exact dtype choice
is left to the builder implementation and may depend on performance, memory,
and numerical accuracy requirements.
- By convention, ``dst`` should have a zero diagonal, and ``adj`` should only
have a non-zero diagonal when ``set_diag=True``.

### Example: fast radius search with SNN

The built-in {class}`~squidpy.gr.neighbors.RadiusBuilder` uses scikit-learn's
``NearestNeighbors``. The [snnpy](https://github.com/nla-group/snn) library
provides a faster exact fixed-radius search based on PCA-based pruning. The
example below swaps the backend while keeping full compatibility with the rest
of the Squidpy graph pipeline:

```python
import numpy as np
from scipy.sparse import csr_matrix
from snnpy import build_snn_model

from squidpy.gr.neighbors import GraphBuilderCSR


class SNNRadiusBuilder(GraphBuilderCSR):
"""Radius graph using the SNN fixed-radius search backend."""

def __init__(self, radius: float, **kwargs):
super().__init__(**kwargs)
self.radius = radius

def build_graph(self, coords):
N = coords.shape[0]
model = build_snn_model(coords, verbose=0)
indices, dists = model.batch_query_radius(
coords, self.radius, return_distance=True,
)

row = np.repeat(np.arange(N), [len(idx) for idx in indices])
col = np.concatenate(indices)
d = np.concatenate(dists).astype(np.float64)

adj = csr_matrix(
(np.ones(len(row), dtype=np.float32), (row, col)),
shape=(N, N),
)
dst = csr_matrix((d, (row, col)), shape=(N, N))

adj.setdiag(1.0 if self.set_diag else adj.diagonal())
dst.setdiag(0.0)
return adj, dst
```

Use it like any other builder:

```python
import squidpy as sq

sq.gr.spatial_neighbors_from_builder(adata, SNNRadiusBuilder(radius=100.0))
```
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ We are happy about any contributions! Before you start, check out our [contribut
installation
api
classes
extensibility
release_notes
references
contributing
Expand Down
30 changes: 30 additions & 0 deletions src/squidpy/_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,33 @@ def decorator2(obj: Any) -> Any:
If multiple `library_id`, column in :attr:`anndata.AnnData.obs`
which stores mapping between ``library_id`` and obs."""

_sdata_params = """\
elements_to_coordinate_systems
A dictionary mapping element names of the SpatialData object to coordinate systems.
The elements can be either Shapes or Labels. For compatibility, the spatialdata table must annotate
all regions keys. Must not be ``None`` if ``adata`` is a :class:`spatialdata.SpatialData`.
table_key
Key in :attr:`spatialdata.SpatialData.tables` where the spatialdata table is stored. Must not be ``None`` if
``adata`` is a :class:`spatialdata.SpatialData`."""
_graph_common_params = """\
percentile
Percentile of the distances to use as threshold.
transform
Adjacency matrix transform (``'spectral'``, ``'cosine'``, or ``None``).
set_diag
Whether to set the diagonal of the connectivities to ``1.0``.
key_added
Key which controls where the results are saved if ``copy = False``."""
_spatial_neighbors_returns = """\
If ``copy = True``, returns a :class:`~squidpy.gr.SpatialNeighborsResult` with the
spatial connectivities and distances matrices.

Otherwise, modifies the ``adata`` with the following keys:

- :attr:`anndata.AnnData.obsp` ``['{key_added}_connectivities']`` - the spatial connectivities.
- :attr:`anndata.AnnData.obsp` ``['{key_added}_distances']`` - the spatial distances.
- :attr:`anndata.AnnData.uns` ``['{key_added}']`` - :class:`dict` containing parameters."""

d = DocstringProcessor(
adata=_adata,
img_container=_img_container,
Expand Down Expand Up @@ -401,4 +428,7 @@ def decorator2(obj: Any) -> Any:
groups=_groups,
plotting_library_id=_plotting_library_id,
library_key=_library_key,
sdata_params=_sdata_params,
graph_common_params=_graph_common_params,
spatial_neighbors_returns=_spatial_neighbors_returns,
)
20 changes: 19 additions & 1 deletion src/squidpy/gr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@

from __future__ import annotations

from squidpy.gr._build import SpatialNeighborsResult, mask_graph, spatial_neighbors
from squidpy.gr import neighbors
from squidpy.gr._build import (
GraphMatrixT,
SpatialNeighborsResult,
mask_graph,
spatial_neighbors,
spatial_neighbors_delaunay,
spatial_neighbors_from_builder,
spatial_neighbors_grid,
spatial_neighbors_knn,
spatial_neighbors_radius,
)
from squidpy.gr._ligrec import ligrec
from squidpy.gr._nhood import (
NhoodEnrichmentResult,
Expand All @@ -16,10 +27,17 @@
from squidpy.gr._sepal import sepal

__all__ = [
"GraphMatrixT",
"SpatialNeighborsResult",
"NhoodEnrichmentResult",
"neighbors",
"mask_graph",
"spatial_neighbors",
"spatial_neighbors_from_builder",
"spatial_neighbors_knn",
"spatial_neighbors_radius",
"spatial_neighbors_delaunay",
"spatial_neighbors_grid",
"ligrec",
"centrality_scores",
"interaction_matrix",
Expand Down
Loading
Loading