Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 47 additions & 10 deletions src/squidpy/_compat.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,68 @@
from __future__ import annotations

from importlib import import_module
from importlib.metadata import version
from typing import Any

from packaging.version import Version
from scanpy.plotting._tools.scatterplots import _add_categorical_legend as add_categorical_legend
from scanpy.plotting._tools.scatterplots import _panel_grid as panel_grid
from scanpy.plotting._utils import add_colors_for_categorical_sample_annotation


def _scanpy_plotting_layout() -> tuple[str, Any | None, Any | None]:
try:
legacy = import_module("scanpy.plotting.legacy")
except ModuleNotFoundError as error:
if error.name != "scanpy.plotting.legacy":
raise
return "scanpy.plotting", None, import_module("scanpy").settings
return "scanpy.plotting.legacy", legacy.mpl_settings, None


_scanpy_plotting_path, _scanpy_mpl_settings, _scanpy_settings = _scanpy_plotting_layout()
_scanpy_plotting_utils = import_module(f"{_scanpy_plotting_path}._utils")
_scanpy_scatterplots = import_module(f"{_scanpy_plotting_path}._tools.scatterplots")
_scanpy_palettes = import_module(f"{_scanpy_plotting_path}.palettes")

add_categorical_legend = _scanpy_scatterplots._add_categorical_legend
panel_grid = _scanpy_scatterplots._panel_grid
default_palette = _scanpy_palettes.default_102

__all__ = [
# scanpy
"set_default_colors_for_categorical_obs",
"add_categorical_legend",
"panel_grid",
"add_colors_for_categorical_sample_annotation",
"default_palette",
"scanpy_frameon",
"scanpy_vector_friendly",
# anndata
"ArrayView",
"SparseCSCView",
"SparseCSRView",
]

# See https://github.com/scverse/squidpy/issues/1061 for more details.
# Scanpy 0.11.x-0.12.x renamed set_default_colors_for_categorical_obs to _set_default_colors_for_categorical_obs
# and then changed it back. Try underscore version first, fall back to non-underscore.
try:
from scanpy.plotting._utils import _set_default_colors_for_categorical_obs as set_default_colors_for_categorical_obs
except ImportError:
from scanpy.plotting._utils import set_default_colors_for_categorical_obs
add_colors_for_categorical_sample_annotation = _scanpy_plotting_utils.add_colors_for_categorical_sample_annotation
set_default_colors_for_categorical_obs = getattr(
_scanpy_plotting_utils,
"_set_default_colors_for_categorical_obs",
None,
)
if set_default_colors_for_categorical_obs is None:
set_default_colors_for_categorical_obs = _scanpy_plotting_utils.set_default_colors_for_categorical_obs


def scanpy_frameon() -> bool:
if _scanpy_mpl_settings is not None:
return _scanpy_mpl_settings.FRAMEON
assert _scanpy_settings is not None
return _scanpy_settings._frameon


def scanpy_vector_friendly() -> bool:
if _scanpy_mpl_settings is not None:
return _scanpy_mpl_settings.VECTOR_FRIENDLY
assert _scanpy_settings is not None
return _scanpy_settings._vector_friendly


CAN_USE_SPARSE_ARRAY = Version(version("anndata")) >= Version("0.11.0rc1")
Expand Down
2 changes: 1 addition & 1 deletion src/squidpy/im/_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
from dask import delayed
from matplotlib.colors import ListedColormap
from scanpy import logging as logg
from scanpy.plotting.palettes import default_102 as default_palette
from skimage.transform import rescale
from skimage.util import img_as_float

from squidpy._compat import default_palette
from squidpy._constants._constants import InferDimensions
from squidpy._constants._pkg_constants import Key
from squidpy._docs import d, inject_docs
Expand Down
13 changes: 6 additions & 7 deletions src/squidpy/pl/_spatial_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@
from matplotlib_scalebar.scalebar import ScaleBar
from pandas import CategoricalDtype
from scanpy import logging as logg
from scanpy import settings as sc_settings
from skimage.color import label2rgb
from skimage.morphology import erosion, square
from skimage.segmentation import find_boundaries
from skimage.util import map_array

from squidpy._compat import add_categorical_legend
from squidpy._compat import add_categorical_legend, scanpy_frameon, scanpy_vector_friendly
from squidpy._constants._constants import ScatterShape
from squidpy._constants._pkg_constants import Key
from squidpy._utils import NDArrayA
Expand Down Expand Up @@ -569,7 +568,7 @@ def _plot_edges(
ax=ax,
**kwargs,
)
edge_collection.set_rasterized(sc_settings._vector_friendly)
edge_collection.set_rasterized(scanpy_vector_friendly())
ax.add_collection(edge_collection)


Expand Down Expand Up @@ -904,7 +903,7 @@ def _panel_grid(

def _set_ax_title(fig_params: FigParams, count: int, value_to_plot: str | None = None) -> Axes:
ax = fig_params.axs[count] if fig_params.axs is not None else fig_params.ax
if not (sc_settings._frameon if fig_params.frameon is None else fig_params.frameon):
if not (scanpy_frameon() if fig_params.frameon is None else fig_params.frameon):
ax.axis("off")

if fig_params.title is None:
Expand Down Expand Up @@ -959,7 +958,7 @@ def _plot_scatter(
coords[:, 1],
s=outline_params.bg_size,
c=outline_params.bg_color,
rasterized=sc_settings._vector_friendly,
rasterized=scanpy_vector_friendly(),
cmap=cmap_params.cmap,
norm=norm,
**kwargs,
Expand All @@ -970,7 +969,7 @@ def _plot_scatter(
coords[:, 1],
s=outline_params.gap_size,
c=outline_params.gap_color,
rasterized=sc_settings._vector_friendly,
rasterized=scanpy_vector_friendly(),
cmap=cmap_params.cmap,
norm=norm,
**kwargs,
Expand All @@ -981,7 +980,7 @@ def _plot_scatter(
coords[:, 1],
c=np.array(color_vector),
s=size,
rasterized=sc_settings._vector_friendly,
rasterized=scanpy_vector_friendly(),
cmap=cmap_params.cmap,
norm=norm,
**kwargs,
Expand Down
62 changes: 62 additions & 0 deletions tests/plotting/test_spatial_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import platform
from collections.abc import Sequence
from functools import partial
from types import SimpleNamespace

import matplotlib.pyplot as plt
import numpy as np
Expand All @@ -12,6 +13,7 @@
from anndata import AnnData
from matplotlib.colors import ListedColormap

import squidpy._compat as compat
from squidpy import pl
from squidpy._constants._pkg_constants import Key
from squidpy.gr import spatial_neighbors_grid, spatial_neighbors_radius
Expand All @@ -28,6 +30,66 @@
# ".png" is appended to <your_filename>, no need to set it


def test_scanpy_plotting_legacy_layout(monkeypatch: pytest.MonkeyPatch) -> None:
settings = object()
legacy = SimpleNamespace(mpl_settings=settings)
monkeypatch.setattr(compat, "import_module", lambda name: legacy)

assert compat._scanpy_plotting_layout() == ("scanpy.plotting.legacy", settings, None)


def test_scanpy_plotting_released_layout(monkeypatch: pytest.MonkeyPatch) -> None:
settings = object()

def import_released(name: str):
if name == "scanpy.plotting.legacy":
raise ModuleNotFoundError(name=name)
return SimpleNamespace(settings=settings)

monkeypatch.setattr(compat, "import_module", import_released)

assert compat._scanpy_plotting_layout() == ("scanpy.plotting", None, settings)


def test_scanpy_plotting_layout_preserves_import_errors(monkeypatch: pytest.MonkeyPatch) -> None:
def import_broken(name: str):
raise ModuleNotFoundError(name="scanpy_dependency")

monkeypatch.setattr(compat, "import_module", import_broken)

with pytest.raises(ModuleNotFoundError) as error:
compat._scanpy_plotting_layout()
assert error.value.name == "scanpy_dependency"


@pytest.mark.parametrize(
("accessor", "legacy_name", "released_name"),
[
(compat.scanpy_frameon, "FRAMEON", "_frameon"),
(compat.scanpy_vector_friendly, "VECTOR_FRIENDLY", "_vector_friendly"),
],
)
def test_scanpy_plotting_setting_compatibility(
monkeypatch: pytest.MonkeyPatch,
accessor,
legacy_name: str,
released_name: str,
) -> None:
legacy_settings = SimpleNamespace(**{legacy_name: False})
released_settings = SimpleNamespace(**{released_name: True})
monkeypatch.setattr(compat, "_scanpy_mpl_settings", legacy_settings)
monkeypatch.setattr(compat, "_scanpy_settings", released_settings)

assert accessor() is False
setattr(legacy_settings, legacy_name, True)
assert accessor() is True

monkeypatch.setattr(compat, "_scanpy_mpl_settings", None)
assert accessor() is True
setattr(released_settings, released_name, False)
assert accessor() is False


class TestSpatialStatic(PlotTester, metaclass=PlotTesterMeta):
def test_tol_plot_spatial_scatter_image(self, adata_hne: AnnData):
pl.spatial_scatter(adata_hne, na_color="lightgrey")
Expand Down
Loading