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
4 changes: 3 additions & 1 deletion src/spatialdata_plot/pl/_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,9 +662,11 @@ def _set_color_source_vec(
table_to_use = _resolve_color_table(value_from_element, table_name, sdata)
adata_for_mapping = sdata[table_to_use] if table_to_use is not None else None

# Check if custom colors exist in the resolved table's .uns slot
# Check if custom colors exist in the resolved table's .uns slot; an explicit
# category->color dict palette takes precedence over them.
if (
value_to_plot is not None
and not isinstance(palette, dict)
and table_to_use is not None
and _has_colors_in_uns(sdata, table_to_use, value_to_plot)
):
Expand Down
5 changes: 3 additions & 2 deletions src/spatialdata_plot/pl/_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ def _gate_palette_and_groups(
element_params: dict[str, Any],
param_dict: dict[str, Any],
) -> None:
"""Set palette/groups on element_params only when col_for_color is present, else warn."""
"""Keep palette when a fill or outline column is present; groups only with a fill column, else warn."""
has_col = element_params.get("col_for_color") is not None
element_params["palette"] = param_dict["palette"] if has_col else None
has_outline_col = element_params.get("col_for_outline_color") is not None
element_params["palette"] = param_dict["palette"] if has_col or has_outline_col else None
if not has_col and param_dict["groups"] is not None:
logger.warning(_GROUPS_IGNORED_WARNING)
element_params["groups"] = param_dict["groups"] if has_col else None
Expand Down
13 changes: 12 additions & 1 deletion tests/pl/test_render_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest
import scanpy as sc
from anndata import AnnData
from matplotlib.colors import Normalize
from matplotlib.colors import Normalize, to_hex
from matplotlib.legend import Legend
from spatial_image import to_spatial_image
from spatialdata import SpatialData, deepcopy, get_element_instances
Expand Down Expand Up @@ -852,6 +852,17 @@ def test_labels_outline_color_groups_filter_aligns(sdata_blobs: SpatialData):
plt.close(fig)


def test_render_labels_respects_dict_palette(sdata_blobs: SpatialData):
# Regression test: default colors materialized in `.uns` used to override an explicit dict palette.
sdata_blobs = _annotate_labels_with_outline_columns(sdata_blobs)
palette = {"c1": "#ff00ff", "c2": "#00ff00"}
fig, ax = plt.subplots()
sdata_blobs.pl.render_labels("blobs_labels", color="cluster", palette=palette).pl.show(ax=ax)
pixels = np.asarray(ax.images[0].get_array())[..., :3].reshape(-1, 3)
plt.close(fig)
assert set(palette.values()) <= {to_hex(p) for p in np.unique(pixels, axis=0)}


def test_render_labels_color_list_creates_one_panel_per_key(sdata_blobs: SpatialData):
"""A list of color keys produces one panel per key, titled by the key (#611)."""
# the default blobs table annotates blobs_labels with channel_*_sum vars
Expand Down
15 changes: 14 additions & 1 deletion tests/pl/test_render_shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest
import scanpy as sc
from anndata import AnnData
from matplotlib.colors import Normalize
from matplotlib.colors import Normalize, to_hex
from shapely.geometry import MultiPolygon, Point, Polygon
from spatialdata import SpatialData, deepcopy
from spatialdata.models import ShapesModel, TableModel
Expand Down Expand Up @@ -1688,6 +1688,19 @@ def test_outline_color_column_groups_filter_aligns(sdata_blobs: SpatialData):
plt.close(fig)


def test_outline_color_column_respects_palette_without_fill_column(sdata_blobs: SpatialData):
# Regression test for #777: palette was dropped when only `outline_color` named a column.
sdata_blobs = _annotate_polygons_with_outline_columns(sdata_blobs)
palette = {"c1": "#ff00ff", "c2": "#00ff00"}
fig, ax = plt.subplots()
sdata_blobs.pl.render_shapes(
"blobs_polygons", outline_color="cluster", palette=palette, fill_alpha=0, outline_width=1.5
).pl.show(ax=ax)
edge_colors = {to_hex(c) for c in ax.collections[0].get_edgecolor()}
plt.close(fig)
assert set(palette.values()) <= edge_colors


def test_outline_color_column_collision_raises(sdata_blobs: SpatialData):
"""If `outline_color` is a string that is both a matplotlib color and an obs column, raise."""
sdata_blobs["table"].obs["region"] = pd.Categorical(["blobs_polygons"] * sdata_blobs["table"].n_obs)
Expand Down
Loading