Skip to content

Commit 017e0b7

Browse files
committed
fix(color): degenerate colorbar matches the pixel norm (#700)
_make_continuous_mappable (the datashader continuous colorbar) expanded a degenerate vmin==vmax to ±0.5, while the pixel path (_resolve_continuous_norm) resets it to [0, 1] — so a constant continuous column drew a colorbar that disagreed with its fill. Use the same [0, 1] fallback in both. Adds a parity test. Intentional pixel change for the datashader-constant-column colorbar.
1 parent 6adef54 commit 017e0b7

2 files changed

Lines changed: 14 additions & 2 deletions

File tree

‎src/spatialdata_plot/pl/_color.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,13 @@ def _is_color_like(color: Any) -> bool:
105105

106106

107107
def _make_continuous_mappable(vmin: float, vmax: float, cmap: Any) -> ScalarMappable:
108-
"""Build a ``ScalarMappable`` for a continuous colorbar, with a ±0.5 fallback when ``vmin == vmax``."""
108+
"""Build a ``ScalarMappable`` for a continuous colorbar.
109+
110+
A degenerate ``vmin == vmax`` falls back to ``[0, 1]`` — the same rule as
111+
:func:`_resolve_continuous_norm`, so the colorbar agrees with the pixel mapping.
112+
"""
109113
if vmin == vmax:
110-
vmin, vmax = vmin - 0.5, vmax + 0.5
114+
vmin, vmax = 0.0, 1.0
111115
return ScalarMappable(norm=Normalize(vmin=vmin, vmax=vmax), cmap=cmap)
112116

113117

‎tests/pl/test_utils.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,14 @@ def test_degenerate_range_resets_to_unit_interval(self):
888888
norm = _resolve_continuous_norm(np.array([5.0, 5.0, 5.0]), self._params())
889889
assert (norm.vmin, norm.vmax) == (0.0, 1.0)
890890

891+
def test_degenerate_clim_matches_colorbar_mappable(self):
892+
# pixel norm and the (datashader) colorbar mappable must agree on a constant column
893+
from spatialdata_plot.pl._color import _make_continuous_mappable, _resolve_continuous_norm
894+
895+
norm = _resolve_continuous_norm(np.array([5.0, 5.0]), self._params())
896+
mappable = _make_continuous_mappable(5.0, 5.0, self._params().cmap)
897+
assert (norm.vmin, norm.vmax) == (mappable.norm.vmin, mappable.norm.vmax) == (0.0, 1.0)
898+
891899
def test_degenerate_lognorm_is_left_untouched(self):
892900
# LogNorm domain excludes 0, so the degenerate reset must not fire for it
893901
from matplotlib.colors import LogNorm

0 commit comments

Comments
 (0)