Skip to content

Commit 43bc9c2

Browse files
authored
Merge branch 'main' into wilcoxon-refactor
2 parents 3682c92 + 2afa3c6 commit 43bc9c2

4 files changed

Lines changed: 30 additions & 6 deletions

File tree

docs/release-notes/0.15.1.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
### 0.15.1 {small}`the-future`
22

3+
```{rubric} Features
4+
```
5+
* ``tl.leiden`` and ``tl.louvain`` now record the final modularity value in ``adata.uns[key_added]["modularity"]``
6+
(scalar for a single resolution, list for multiple resolutions) {pr}`648` {smaller}`J Pintar`
7+
38
```{rubric} Bug fixes
49
```
510
* Fixes `tl.rank_genes_groups` returning NaN/zero `logfoldchanges`/`pvals` with `groups=[subset]` and `reference='rest'` {pr}`651` {smaller}`S Dicks`
11+
12+
```{rubric} Misc
13+
```
14+
* ``adata.uns[key_added]["params"]["resolution"]`` is now stored as a scalar ``float`` when a single resolution
15+
is passed to ``tl.leiden`` and ``tl.louvain`` to match behaviour in Scanpy, and as a ``list`` when multiple
16+
resolutions are passed. Previously it was always stored as a list. {pr}`648`. {smaller}`J Pintar`

docs/release-notes/blank.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
```{rubric} Performance
77
```
88

9-
109
```{rubric} Bug fixes
1110
```
1211

13-
1412
```{rubric} Misc
1513
```
1614

src/rapids_singlecell/tools/_clustering.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,9 @@ def leiden(
229229
resolutions = [resolution]
230230
else:
231231
resolutions = resolution
232+
modularities = []
232233
for resolution in resolutions:
233-
leiden_parts, _ = culeiden(
234+
leiden_parts, modularity = culeiden(
234235
g,
235236
resolution=resolution,
236237
random_state=random_state,
@@ -241,6 +242,7 @@ def leiden(
241242
leiden_parts = leiden_parts.to_backend("pandas").compute()
242243
else:
243244
leiden_parts = leiden_parts.to_pandas()
245+
modularities.append(modularity)
244246

245247
# Format output
246248
groups = leiden_parts.sort_values("vertex")[["partition"]].to_numpy().ravel()
@@ -270,10 +272,13 @@ def leiden(
270272
# store information on the clustering parameters
271273
adata.uns[key_added] = {}
272274
adata.uns[key_added]["params"] = {
273-
"resolution": resolutions,
275+
"resolution": resolutions if len(resolutions) > 1 else resolutions[0],
274276
"random_state": random_state,
275277
"n_iterations": n_iterations,
276278
}
279+
adata.uns[key_added]["modularity"] = (
280+
modularities if len(modularities) > 1 else modularities[0]
281+
)
277282
return adata if copy else None
278283

279284

@@ -383,8 +388,9 @@ def louvain(
383388
resolutions = [resolution]
384389
else:
385390
resolutions = resolution
391+
modularities = []
386392
for resolution in resolutions:
387-
louvain_parts, _ = culouvain(
393+
louvain_parts, modularity = culouvain(
388394
g,
389395
resolution=resolution,
390396
max_level=n_iterations,
@@ -394,6 +400,7 @@ def louvain(
394400
louvain_parts = louvain_parts.to_backend("pandas").compute()
395401
else:
396402
louvain_parts = louvain_parts.to_pandas()
403+
modularities.append(modularity)
397404

398405
# Format output
399406
groups = louvain_parts.sort_values("vertex")[["partition"]].to_numpy().ravel()
@@ -422,10 +429,13 @@ def louvain(
422429
Comms.destroy()
423430
adata.uns[key_added] = {}
424431
adata.uns[key_added]["params"] = {
425-
"resolution": resolutions,
432+
"resolution": resolutions if len(resolutions) > 1 else resolutions[0],
426433
"n_iterations": n_iterations,
427434
"threshold": threshold,
428435
}
436+
adata.uns[key_added]["modularity"] = (
437+
modularities if len(modularities) > 1 else modularities[0]
438+
)
429439
return adata if copy else None
430440

431441

tests/test_clustering.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,13 @@ def test_clustering_resolution(adata_neighbors, clustering_function, resolution)
7878
if isinstance(resolution, list):
7979
for r in resolution:
8080
assert f"test_clustering_{r}" in adata.obs.columns
81+
assert isinstance(adata.uns["test_clustering"]["modularity"], list)
82+
assert len(adata.uns["test_clustering"]["modularity"]) == len(resolution)
83+
assert adata.uns["test_clustering"]["params"]["resolution"] == resolution
8184
else:
8285
assert "test_clustering" in adata.obs.columns
86+
assert isinstance(adata.uns["test_clustering"]["modularity"], float)
87+
assert adata.uns["test_clustering"]["params"]["resolution"] == resolution
8388

8489

8590
def test_kmeans_basic(adata_neighbors):

0 commit comments

Comments
 (0)