Skip to content

Commit e3d0dcb

Browse files
committed
drop leidenalg dependency
1 parent 10680eb commit e3d0dcb

File tree

7 files changed

+38
-9
lines changed

7 files changed

+38
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ notebooks/testing.ipynb
1010
dist/
1111
.vscode/
1212
data/
13+
*.ipynb

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Release Notes
7575
### Version 1.4.1
7676
* update `LICENSE` file to be consistent with MIT - license
7777
* implement `plot_trajectories` to show multiple poaths on the UMAP
78+
* Drop leiden dependency to allow Python >= 3.13. igrph is used instead.
7879

7980
### Version 1.4.0
8081
* Made pygam an optional dependency that can be installed with `pip install palantir[gam]` or `pip install palantir[full]`

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ dependencies = [
3434
"scikit-learn",
3535
"joblib",
3636
"fcsparser>=0.1.2",
37-
"leidenalg>=0.9.1",
3837
"matplotlib>=3.8.0",
3938
"anndata>=0.8.0",
4039
"scanpy>=1.6.0",
@@ -103,4 +102,4 @@ exclude_lines = [
103102
"raise ImportError",
104103
"def _return_cell",
105104
"print"
106-
]
105+
]

src/palantir/io.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ def from_fcs(
191191
"""
192192
# Parse the fcs file
193193
text, data = fcsparser.parse(fcs_file)
194-
data = data.astype(np.float64)
194+
# Use view instead of newbyteorder for NumPy 2.0 compatibility
195+
data = data.astype(np.float64, copy=False)
195196

196197
# Extract the S and N features (Indexing assumed to start from 1)
197198
# Assumes channel names are in S

src/palantir/plot.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ def plot_gene_trend_clusters(
19841984
)
19851985

19861986
# Obtain unique clusters and prepare figure
1987-
if pd.api.types.is_categorical_dtype(clusters):
1987+
if isinstance(clusters.dtype, pd.CategoricalDtype):
19881988
cluster_labels = clusters.cat.categories
19891989
else:
19901990
# Filter out NaN values to avoid issues with np.NaN vs np.nan
@@ -2096,7 +2096,9 @@ def gene_score_histogram(
20962096
label=f"{quantile:.0%} percentile",
20972097
)
20982098

2099-
ax.legend()
2099+
# Only create legend if we have elements with labels
2100+
if quantile is not None:
2101+
ax.legend()
21002102
ax.set_xlabel(f"{score_key} score")
21012103
ax.set_ylabel("# of genes")
21022104

src/palantir/presults.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,13 @@ def cluster_gene_trends(
504504

505505
gt_ad = AnnData(trends.values, dtype=np.float32)
506506
sc.pp.neighbors(gt_ad, n_neighbors=n_neighbors, use_rep="X")
507-
sc.tl.leiden(gt_ad, **kwargs)
507+
508+
# Add required kwargs for leiden with igraph backend to avoid FutureWarning
509+
leiden_kwargs = {'flavor': 'igraph', 'n_iterations': 2, 'directed': False}
510+
# Override with user-provided kwargs if any
511+
leiden_kwargs.update(kwargs)
512+
513+
sc.tl.leiden(gt_ad, **leiden_kwargs)
508514

509515
communities = pd.Series(gt_ad.obs["leiden"].values, index=trends.index)
510516

tests/test_plot.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,14 +401,19 @@ def test_plot_palantir_results_custom_args(mock_anndata):
401401

402402
# Test with AnnData and all keys available
403403
def test_plot_terminal_state_probs_anndata(mock_anndata, mock_cells):
404+
# Close existing figures to avoid warnings
405+
plt.close('all')
404406
fig = plot_terminal_state_probs(mock_anndata, mock_cells)
405407
assert isinstance(fig, plt.Figure)
408+
plt.close(fig)
406409

407410

408411
# Test with DataFrame and PResults
409412
def test_plot_terminal_state_probs_dataframe(mock_data, mock_presults, mock_cells):
413+
plt.close('all')
410414
fig = plot_terminal_state_probs(mock_data, mock_cells, pr_res=mock_presults)
411415
assert isinstance(fig, plt.Figure)
416+
plt.close(fig)
412417

413418

414419
# Test ValueError for missing pr_res in DataFrame input
@@ -616,31 +621,42 @@ def test_plot_gene_trend_heatmaps(mock_anndata):
616621

617622

618623
def test_plot_gene_trend_clusters(mock_anndata):
624+
# Close all figures to start clean
625+
plt.close('all')
626+
619627
# Test with AnnData object
620628
fig = plot_gene_trend_clusters(mock_anndata, branch_name="a", clusters="clusters")
621629
assert isinstance(fig, plt.Figure)
622630

623631
# We expect one subplot per unique non-NaN cluster
624632
unique_clusters = [x for x in mock_anndata.var["clusters"].unique() if not pd.isna(x)]
625633
assert len(fig.axes) == len(unique_clusters)
634+
plt.close(fig)
626635

636+
# Close all figures again before next test
637+
plt.close('all')
638+
627639
# Test DataFrame input
628640
trends_df = mock_anndata.varm["gene_trends_a"]
629641
clusters_series = mock_anndata.var["clusters"]
630642
fig_df = plot_gene_trend_clusters(trends_df, clusters=clusters_series)
631643

632644
assert isinstance(fig_df, plt.Figure)
633645
assert len(fig_df.axes) == len(unique_clusters)
634-
635-
plt.close(fig)
646+
636647
plt.close(fig_df)
648+
plt.close('all')
637649

638650

639651
def test_gene_score_histogram(mock_anndata):
652+
# Close all figures before testing
653+
plt.close('all')
654+
640655
# Test with minimum required parameters
641656
fig = gene_score_histogram(mock_anndata, "gene_score")
642657
assert isinstance(fig, plt.Figure)
643658
plt.close(fig)
659+
plt.close('all')
644660

645661
# Test with optional parameters
646662
fig = gene_score_histogram(
@@ -652,15 +668,18 @@ def test_gene_score_histogram(mock_anndata):
652668
)
653669
assert isinstance(fig, plt.Figure)
654670
plt.close(fig)
671+
plt.close('all')
655672

656-
# Test with None quantile
673+
# Test with None quantile - this would previously cause a warning
674+
# about empty legend when quantile is None
657675
fig = gene_score_histogram(
658676
mock_anndata,
659677
"gene_score",
660678
quantile=None,
661679
)
662680
assert isinstance(fig, plt.Figure)
663681
plt.close(fig)
682+
plt.close('all')
664683

665684

666685
def test_gene_score_histogram_errors(mock_anndata):

0 commit comments

Comments
 (0)