Skip to content

Commit 0546d18

Browse files
authored
Merge branch 'main' into manifold_map_dims
2 parents b4cee1e + 30c842e commit 0546d18

2 files changed

Lines changed: 94 additions & 3 deletions

File tree

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ repos:
55
- id: trailing-whitespace
66
- id: end-of-file-fixer
77
- repo: https://github.com/astral-sh/ruff-pre-commit
8-
rev: v0.15.20
8+
rev: v0.15.21
99
hooks:
1010
- id: ruff-check
1111
args: [--fix, --preview]
1212
- id: ruff-format
1313
- repo: https://github.com/tox-dev/pyproject-fmt
14-
rev: v2.25.1
14+
rev: v2.25.2
1515
hooks:
1616
- id: pyproject-fmt
1717
- repo: https://github.com/biomejs/pre-commit
18-
rev: v2.5.2
18+
rev: v2.5.3
1919
hooks:
2020
- id: biome-format
2121
- repo: https://github.com/kynan/nbstripout

tests/plotting/test_manifold.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import numpy as np
1111
import pandas as pd
1212
import panel as pn
13+
import panel_material_ui as pmui
1314
import pytest
1415
from holoviews.operation.datashader import dynspread, rasterize
1516

1617
from hv_anndata import A, ManifoldMap, create_manifoldmap_plot
1718
from hv_anndata.interface import register, unregister
19+
from hv_anndata.plotting.manifoldmap import CAT_CMAPS, CONT_CMAPS
1820

1921
if TYPE_CHECKING:
2022
from collections.abc import Iterator
@@ -211,3 +213,92 @@ def test_manifoldmap_streams(sadata: ad.AnnData) -> None:
211213
assert bounds_xy.source is None
212214
mm.__panel__()
213215
assert bounds_xy.source is not None
216+
217+
218+
@pytest.mark.usefixtures("bokeh_renderer")
219+
def test_manifoldmap_get_dim_cols_uses_x_column(sadata: ad.AnnData) -> None:
220+
"""color_by_dim="cols" without var_reference must read expression from X.
221+
222+
A.var.index has no per-observation values and mismatches the obsm-based
223+
x/y coordinates on the obs axis; see #161.
224+
"""
225+
mm = ManifoldMap(adata=sadata, color_by_dim="cols", color_by="gene_1")
226+
227+
assert mm._get_dim() == A.X[:, "gene_1"]
228+
229+
230+
@pytest.mark.usefixtures("bokeh_renderer")
231+
def test_manifoldmap_color_by_cols_plot_view_no_var_reference(
232+
sadata: ad.AnnData,
233+
) -> None:
234+
"""Coloring by a variable (no var_reference) renders instead of raising.
235+
236+
Previously raised a HoloViews DataError mixing the obs and var axes; see
237+
#161.
238+
"""
239+
mm = ManifoldMap(adata=sadata, color_by_dim="cols", color_by="gene_1")
240+
241+
plot = mm._plot_view()
242+
243+
assert isinstance(plot, hv.core.Dimensioned)
244+
assert mm._categorical is False
245+
246+
247+
@pytest.mark.usefixtures("bokeh_renderer")
248+
def test_manifoldmap_colormap_survives_categorical_round_trip(
249+
sadata: ad.AnnData,
250+
) -> None:
251+
"""colormap must round-trip through a categorical/continuous/categorical cycle.
252+
253+
Once selected, colormap holds an unhashable palette list rather than its
254+
name, so membership must be tested against dict values, not keys, or this
255+
raises `TypeError: unhashable type: 'list'`; see #161.
256+
"""
257+
mm = ManifoldMap(adata=sadata, color_by="cell_type")
258+
assert mm.colormap in CAT_CMAPS.values()
259+
260+
mm.color_by = "expression_level"
261+
assert mm._categorical is False
262+
assert mm.colormap in CONT_CMAPS.values()
263+
264+
mm.color_by = "cell_type"
265+
assert mm._categorical is True
266+
assert mm.colormap in CAT_CMAPS.values()
267+
268+
269+
@pytest.mark.usefixtures("bokeh_renderer")
270+
@pytest.mark.parametrize("color_by", [None, ""], ids=["none", "empty_string"])
271+
def test_manifoldmap_create_plot_no_color_by(
272+
sadata: ad.AnnData, color_by: str | None
273+
) -> None:
274+
"""create_plot shows a prompt instead of erroring when color_by is unset."""
275+
mm = ManifoldMap(adata=sadata)
276+
277+
result = mm.create_plot(
278+
dr_key="X_umap",
279+
x_value="UMAP1",
280+
y_value="UMAP2",
281+
color_by=color_by,
282+
datashade_value=False,
283+
show_labels=False,
284+
cmap=None,
285+
)
286+
287+
assert isinstance(result, pmui.pane.Typography)
288+
assert "select a variable to color by" in result.object
289+
290+
291+
@pytest.mark.usefixtures("bokeh_renderer")
292+
def test_manifoldmap_plot_view_skips_opts_for_error_pane(sadata: ad.AnnData) -> None:
293+
"""_plot_view must not call .opts() on a Typography error pane from create_plot.
294+
295+
Typography has no `.opts()`, so calling it unconditionally would raise;
296+
see #161.
297+
"""
298+
mm = ManifoldMap(adata=sadata)
299+
error_pane = pmui.pane.Typography("boom")
300+
mm.create_plot = lambda **_: error_pane
301+
302+
plot = mm._plot_view()
303+
304+
assert plot is error_pane

0 commit comments

Comments
 (0)