Skip to content

Commit a4d09db

Browse files
authored
Merge pull request #7 from HiDiHlabs/dev
Prepare new release
2 parents dff4ec0 + 961f2cf commit a4d09db

File tree

5 files changed

+59
-51
lines changed

5 files changed

+59
-51
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
- id: no-commit-to-branch
1616
args: [--branch=main]
1717
- repo: https://github.com/astral-sh/ruff-pre-commit
18-
rev: v0.6.9
18+
rev: v0.7.4
1919
hooks:
2020
- id: ruff
2121
args: [--fix]
@@ -28,7 +28,7 @@ repos:
2828
hooks:
2929
- id: black
3030
- repo: https://github.com/pre-commit/mirrors-mypy
31-
rev: v1.11.2
31+
rev: v1.13.0
3232
hooks:
3333
- id: mypy
3434
- repo: https://github.com/codespell-project/codespell

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ conda install bioconda::spatialleiden
3131
```
3232

3333
For detailed installation instructions please refer to the
34-
[documentation](https://spatialleiden.readthedocs.io/stable/installation.html).
34+
[documentation](https://spatialleiden.readthedocs.io/page/installation.html).
3535

3636
## Documentation
3737

@@ -46,6 +46,17 @@ Müller-Bötticher, N., Sahay, S., Eils, R., and Ishaque, N.
4646
"SpatialLeiden - Spatially-aware Leiden clustering"
4747
bioRxiv (2024) https://doi.org/10.1101/2024.08.23.609349
4848

49+
```
50+
@article {spatialleiden2024,
51+
author = {Müller-Bötticher, Niklas and Sahay, Shashwat and Eils, Roland and Ishaque, Naveed},
52+
title = {SpatialLeiden - Spatially-aware Leiden clustering},
53+
year = {2024},
54+
doi = {10.1101/2024.08.23.609349},
55+
journal = {bioRxiv},
56+
publisher = {Cold Spring Harbor Laboratory}
57+
}
58+
```
59+
4960
## Versioning
5061

5162
This project follows the [SemVer](https://semver.org/) guidelines for versioning.

pyproject.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ docs = ["sphinx", "sphinx-copybutton", "sphinx-rtd-theme", "squidpy", "myst-nb"]
3939
dev = ["spatialleiden[docs]", "pre-commit"]
4040

4141
[project.urls]
42-
homepage = "https://github.com/HiDiHlabs/SpatialLeiden"
43-
documentation = "https://spatialleiden.readthedocs.io"
44-
repository = "https://github.com/HiDiHlabs/SpatialLeiden"
42+
Homepage = "https://github.com/HiDiHlabs/SpatialLeiden"
43+
Documentation = "https://spatialleiden.readthedocs.io"
44+
Repository = "https://github.com/HiDiHlabs/SpatialLeiden"
45+
Issues = "https://github.com/HiDiHlabs/SpatialLeiden/issues"
4546

4647

4748
[tool]
@@ -56,12 +57,13 @@ include = ["spatialleiden"]
5657
profile = "black"
5758

5859
[tool.black]
59-
target-version = ["py310", "py311", "py312"]
60+
target-version = ["py310", "py311", "py312", "py313"]
6061

6162
[tool.ruff]
6263
target-version = "py310"
6364

6465
[tool.mypy]
66+
python_version = "3.10"
6567
ignore_missing_imports = true
6668
warn_no_return = false
6769
packages = "spatialleiden"

spatialleiden/_multiplex_leiden.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@
1313

1414

1515
def _build_igraph(adjacency: _GraphArray, *, directed: bool = True) -> Graph:
16-
# adapted from scanpy https://github.com/scverse/scanpy
1716
sources, targets, weights = find(adjacency)
18-
g = Graph(directed=directed)
19-
g.add_vertices(adjacency.shape[0])
20-
g.add_edges(list(zip(sources, targets)))
21-
g.es["weight"] = weights
22-
if g.vcount() != adjacency.shape[0]:
23-
raise RuntimeError(
24-
f"The constructed graph has only {g.vcount()} nodes. "
25-
"Your adjacency matrix contained redundant nodes."
26-
)
17+
g = Graph(
18+
n=adjacency.shape[0],
19+
edges=zip(sources, targets),
20+
directed=directed,
21+
edge_attrs={"weight": weights},
22+
)
2723
return g
2824

2925

spatialleiden/_resolution_search.py

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import Callable
2+
from warnings import warn
23

34
import scanpy as sc
45
from anndata import AnnData
@@ -8,42 +9,38 @@
89

910
def _search_resolution(
1011
fn: Callable[[float], int],
11-
ncluster: int,
12+
n_clusters: int,
1213
start: float = 1,
1314
step: float = 0.1,
1415
n_iterations: int = 15,
1516
) -> float:
16-
# adapted from SpaGCN.search_res (https://github.com/jianhuupenn/SpaGCN)
17-
res = start
18-
old_ncluster = fn(res)
19-
iter = 1
20-
while old_ncluster != ncluster:
21-
old_sign = 1 if (old_ncluster < ncluster) else -1
22-
new_ncluster = fn(res + step * old_sign)
23-
if new_ncluster == ncluster:
24-
res = res + step * old_sign
25-
# print(f"Recommended res = {res:.2f}")
26-
return res
27-
new_sign = 1 if (new_ncluster < ncluster) else -1
28-
if new_sign == old_sign:
29-
res = res + step * old_sign
30-
# print(f"Res changed to {res:.2f}")
31-
old_ncluster = new_ncluster
32-
else:
33-
step = step / 2
34-
# print(f"Step changed to {step:.2f}")
35-
if iter > n_iterations:
36-
# print("Exact resolution not found")
37-
# print(f"Recommended res = {res:.2f}")
38-
return res
39-
iter += 1
40-
# print(f"Recommended res = {res:.2f}")
41-
return res
17+
18+
if n_iterations <= 2:
19+
raise ValueError("At least 2 iterations are necessary")
20+
resolution = start
21+
n = fn(resolution)
22+
i = 1
23+
while n != n_clusters:
24+
if i >= n_iterations:
25+
warn(
26+
"Correct resolution not found. Consider increasing the number of "
27+
"iterations or adjusting the step size."
28+
)
29+
break
30+
sign = 1 if n < n_clusters else -1
31+
resolution += step * sign # TODO what happens when approaching zero
32+
n = fn(resolution)
33+
new_sign = 1 if n < n_clusters else -1
34+
if new_sign != sign:
35+
step /= 2
36+
i += 1
37+
38+
return resolution
4239

4340

4441
def search_resolution_latent(
4542
adata: AnnData,
46-
ncluster: int,
43+
n_clusters: int,
4744
*,
4845
start: float = 1,
4946
step: float = 0.1,
@@ -56,7 +53,7 @@ def search_resolution_latent(
5653
Parameters
5754
----------
5855
adata : anndata.AnnData
59-
ncluster : int
56+
n_clusters : int
6057
Number of clusters.
6158
start : float, optional
6259
Starting point for resolution.
@@ -75,17 +72,19 @@ def search_resolution_latent(
7572
"""
7673

7774
def ncluster4res_leiden(resolution: float) -> int:
78-
sc.tl.leiden(adata, resolution=resolution, **kwargs)
75+
sc.tl.leiden(adata, resolution=resolution, key_added=key_added, **kwargs)
7976
return adata.obs[key_added].cat.categories.size
8077

8178
key_added = kwargs.pop("key_added", "leiden")
8279

83-
return _search_resolution(ncluster4res_leiden, ncluster, start, step, n_iterations)
80+
return _search_resolution(
81+
ncluster4res_leiden, n_clusters, start, step, n_iterations
82+
)
8483

8584

8685
def search_resolution_spatial(
8786
adata: AnnData,
88-
ncluster: int,
87+
n_clusters: int,
8988
*,
9089
start: float = 0.4,
9190
step: float = 0.1,
@@ -102,7 +101,7 @@ def search_resolution_spatial(
102101
Parameters
103102
----------
104103
adata : anndata.AnnData
105-
ncluster : int
104+
n_clusters : int
106105
Number of clusters.
107106
start : float, optional
108107
Starting point for resolution.
@@ -133,7 +132,7 @@ def ncluster4res_spatialleiden(resolution: float) -> int:
133132
resolution_user = kwargs.pop("resolution", (1, 1))
134133

135134
return _search_resolution(
136-
ncluster4res_spatialleiden, ncluster, start, step, n_iterations
135+
ncluster4res_spatialleiden, n_clusters, start, step, n_iterations
137136
)
138137

139138

0 commit comments

Comments
 (0)