Skip to content

Initial framework of the niche refactor - #1245

Open
shashkat wants to merge 26 commits into
scverse:mainfrom
shashkat:niche_refactor
Open

Initial framework of the niche refactor#1245
shashkat wants to merge 26 commits into
scverse:mainfrom
shashkat:niche_refactor

Conversation

@shashkat

Copy link
Copy Markdown

Description

Niche refactor improving the current implementation giving the user facing functions a more explicit API, more flexibility through embedder and clusterer classes and possibility of using combinations of them using calculate_niche_custom. Postprocessor classes allow more organized and flexible postprocessing actions like masking and min_niche_size filtering of niches.
The core idea is similar to the spatial_neighbors refactor in #1147 and builds on top of the relatively smaller fix in #1229.

The below graph demonstrates the code flow planned (read children of a node from left to right). This allows usage of different combinations of embeddings and clusterings to obtain niches, and also exposing easy to use and explicit user facing functions for the different flavors. Brown nodes are user-facing functions.
Screenshot 2026-07-21 at 1 50 05 AM

How has this been tested?

Keeping the API of function calculate_niche same, for i) backward compatibility and ii) being able to validate results being same before and after refactor for some test cases that I wrote for the purpose of this refactor, for the different flavors. Though later on, I think calculate_niche should be deprecated as its not clear how arguments of it interact with different values of flavor argument.

Closes

Closes #1192, where this was initially discussed

shashkat and others added 15 commits July 12, 2026 20:36
…late_niche() so that writing test case for sdata is possible
…ew implementation has differently named column
Tests in test_niche.py involving dummy_adata fail with
scanpy<1.12.1 because of a change in handling of small edge
weights by sc.pp.neighbors (scverse#4031). Updated the values
in tests to match the expected values with scanpy>=1.12.1
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.11634% with 79 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.68%. Comparing base (ca07e64) to head (4484b56).

Files with missing lines Patch % Lines
src/squidpy/gr/_niche.py 78.11% 54 Missing and 25 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1245      +/-   ##
==========================================
+ Coverage   77.24%   78.68%   +1.44%     
==========================================
  Files          63       63              
  Lines        9378     9491     +113     
  Branches     1579     1589      +10     
==========================================
+ Hits         7244     7468     +224     
+ Misses       1532     1415     -117     
- Partials      602      608       +6     
Files with missing lines Coverage Δ
src/squidpy/gr/_niche.py 76.17% <78.11%> (+38.63%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@shashkat
shashkat marked this pull request as ready for review July 27, 2026 05:24
@shashkat

Copy link
Copy Markdown
Author

This is ready for review @selmanozleyen @grst

Some important points:

  • I think one of the most important next steps after this PR is that the naming of the columns added in the different flavors is changed. Currently, column names added look like: adata.obs['nhood_niche_res=1.0']. However, sdata doesn't support such column names with equal-to sign More robust name validation spatialdata#703. Hence, if one used any of the current niche functions with sdata and inplace=True, it will give error. Currently, I kept naming strategy same for backward compatibility, but we should change it after this. It should be relatively straightforward after the refactor.

  • I believe the test cases I have added in test_niche.py are quite useful. They helped me validate that the output was the same before and after refactor for an example object (dummy_adata2) for different flavors. However, I realized that with scanpy<1.12.1 in the test env, the output was different than with scanpy>=1.12.1. This is because of a detail in scanpy mentioned here: fix: copy connectivities before passing to umap-learn scanpy#4031, and fixed in 1.12.1 onwards. This means that if someone will run hatch-test on squidpy and they have scanpy<1.12.1 in their test env, some tests will fail. I dont know what is the best way to handle this, hence would like to know your suggestions.

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.

Refactor gr.calculate_niche into separate functions

1 participant