Skip to content

spatial_neigbours extensibility features and clarification#1147

Open
selmanozleyen wants to merge 63 commits intoscverse:mainfrom
selmanozleyen:feat/spatial_neighbours
Open

spatial_neigbours extensibility features and clarification#1147
selmanozleyen wants to merge 63 commits intoscverse:mainfrom
selmanozleyen:feat/spatial_neighbours

Conversation

@selmanozleyen
Copy link
Copy Markdown
Member

@selmanozleyen selmanozleyen commented Apr 2, 2026

fixes: #1102 and #1047

It's backward compatible and I am curious what the community might bring to this!

  • I clarified the docs on argument precedence
  • Added extensibility features
  • Added tests to ensure the function behaves as written in the docs
  • No breaking changes

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 87.46518% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.82%. Comparing base (373228d) to head (13768e2).

Files with missing lines Patch % Lines
src/squidpy/gr/_build.py 80.41% 24 Missing and 4 partials ⚠️
src/squidpy/gr/neighbors.py 92.01% 11 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1147      +/-   ##
==========================================
+ Coverage   73.56%   73.82%   +0.26%     
==========================================
  Files          44       45       +1     
  Lines        6929     7098     +169     
  Branches     1174     1178       +4     
==========================================
+ Hits         5097     5240     +143     
- Misses       1347     1369      +22     
- Partials      485      489       +4     
Files with missing lines Coverage Δ
src/squidpy/_docs.py 94.44% <100.00%> (+0.24%) ⬆️
src/squidpy/gr/neighbors.py 92.01% <92.01%> (ø)
src/squidpy/gr/_build.py 81.21% <80.41%> (-7.31%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@selmanozleyen selmanozleyen requested a review from grst April 2, 2026 12:30
@selmanozleyen selmanozleyen requested a review from timtreis April 2, 2026 12:53
@selmanozleyen selmanozleyen self-assigned this Apr 2, 2026
Copy link
Copy Markdown
Contributor

@grst grst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @selmanozleyen, that goes in the right direction. I put up some design questions up for discussion!

Comment thread src/squidpy/gr/_build.py Outdated
Comment thread src/squidpy/gr/_build.py
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread src/squidpy/gr/neighbors.py Outdated
Comment thread docs/extensibility.md Outdated
from scipy.sparse import csr_matrix
from snnpy import build_snn_model

from squidpy._constants._constants import CoordType
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have the import of internal constants as the default behaviour?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good point, I will think about it in the week

Comment thread src/squidpy/gr/_build.py Outdated
Comment thread src/squidpy/gr/_build.py Outdated
Comment thread src/squidpy/gr/_build.py Outdated
Comment thread src/squidpy/gr/_build.py

Notes
-----
``spatial_neighbors`` has 4 graph-construction modes:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a good explanation of these somewhere?

Comment thread src/squidpy/gr/_build.py
"`spatial_neighbors_delaunay`, `spatial_neighbors_grid`, or "
"`spatial_neighbors_from_builder` instead.",
FutureWarning,
stacklevel=2,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your other future warning was stacklevel=3, how do you decide this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stacklevel 2: user code -> spatial_neighbors() -> warnings.warn(...)

vs

stacklevel 3: user code -> spatial_neighbors() -> _resolve_graph_builder() -> warnings.warn(...)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have this written down somewhere? I haven't really thought about this yet so I wonder if we should add that to some "how to Squidpy" doc somewhere?

Comment thread src/squidpy/gr/_build.py Outdated
}
@d.dedent
def spatial_neighbors_from_builder(
adata: AnnData | SpatialData,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other comment

Comment thread src/squidpy/gr/_build.py Outdated


def _prepare_spatial_neighbors_input(
adata: AnnData | SpatialData,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other comment

Comment thread src/squidpy/gr/_build.py
def _prepare_spatial_neighbors_input(
adata: AnnData | SpatialData,
*,
spatial_key: str,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align annotations across functions

Comment thread src/squidpy/gr/_build.py Outdated
Return D^{-1/2} * A * D^{-1/2}, where D = diag(degrees(A)) and A = adj.
@d.dedent
def spatial_neighbors_grid(
adata: AnnData | SpatialData,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other comment


def __init__(
self,
radius: float | tuple[float, float] | None = None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this used?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes by _filter_by_radius_interval. If I did this from scratch maybe I'd make it more complicated by having this filtering as a separate transform but this feels more appropiate for old implementation

@@ -0,0 +1,440 @@
"""Graph construction strategies for spatial neighbor graphs.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite some duplicates code, can you use a factory or prototcol instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I agree. What exactly do you think needs deduplication here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The two typevars here aren't modified anywhere. It could just be an ABC.

  2. apply_percentile is the only function using the coord_type. Since at the point of _resolve_graph_builder we decide on the downstream path, we don't need that guard. With that guard removed, the coord_type becomes superflous and would further simplify the class.

  3. Both apply_filters are identical, could be deduplicated by moving it into build of the ABC.

  4. KNNBuilder.build_graph and RadiusBuilder.build_graph share quite some overlap in building their nn-graphs. Just the delauny stuff would need to be routed differently.

but I guess the biggest win would be removing the non-CSR build option? Is this sth we'll realistically ever encounter?

Copy link
Copy Markdown
Member

@timtreis timtreis Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The factory/protocol comment doesn't make much sense in hind-sight after having gone through it in detail - still, quite some opportunity to remove LOCs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I guess the biggest win would be removing the non-CSR build option?

I'd like to also give possibility to support cupy sparse or whatever sparse types jax might have for example

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I noticed I use scipy operations also in the builder path so let me just have a second look.

selmanozleyen and others added 16 commits April 13, 2026 07:46
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/biomejs/pre-commit: v2.4.9 → v2.4.10](biomejs/pre-commit@v2.4.9...v2.4.10)
- [github.com/tox-dev/pyproject-fmt: v2.20.0 → v2.21.0](tox-dev/pyproject-fmt@v2.20.0...v2.21.0)
- [github.com/astral-sh/ruff-pre-commit: v0.15.8 → v0.15.9](astral-sh/ruff-pre-commit@v0.15.8...v0.15.9)

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
@selmanozleyen selmanozleyen requested a review from timtreis April 13, 2026 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Documentation for sq.gr.spatial_neighbors() likely needs more clarification about the interplay of arguments

4 participants