Skip to content

Commit 6d26b18

Browse files
feat: add cmap_kwargs to Colormap, to pass kwargs to parametrized colormaps (#134)
* add parametrized colormap registry and expose cubehelix with Colormap("cubehelix", cmap_kwargs: dict[str, Any]) API * remove registry * update docs * fix test --------- Co-authored-by: Talley Lambert <talley.lambert@gmail.com>
1 parent e350a28 commit 6d26b18

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

src/cmap/_colormap.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ class Colormap:
109109
the matplotlib docs for more.
110110
- a `Callable` that takes an array of N values in the range [0, 1] and returns
111111
an (N, 4) array of RGBA values in the range [0, 1].
112+
cmap_kwargs : dict[str, Any] | None
113+
Keyword arguments to pass to the colormap function when `value` is a
114+
registered colormap name that maps to a callable function. For example:
115+
`Colormap("cubehelix", cmap_kwargs={"start": 1.0, "rotation": -1.0})`.
116+
If provided when `value` does not resolve to a callable colormap function, a
117+
`TypeError` will be raised.
112118
name : str | None
113119
A name for the colormap. If None, will be set to the identifier or the string
114120
`"custom colormap"`.
@@ -129,6 +135,14 @@ class Colormap:
129135
The color to use for values above the colormap's range.
130136
bad : ColorLike | None
131137
The color to use for bad (NaN, inf) values.
138+
139+
Raises
140+
------
141+
TypeError
142+
If `cmap_kwargs` is provided and `value` does not resolve to a callable
143+
colormap function.
144+
ValueError
145+
If `value` is a string colormap name that is not found in the catalog.
132146
"""
133147

134148
__slots__ = (
@@ -226,6 +240,7 @@ def __init__(
226240
under: ColorLike | None = None,
227241
over: ColorLike | None = None,
228242
bad: ColorLike | None = None,
243+
cmap_kwargs: dict[str, Any] | None = None,
229244
) -> None:
230245
self.info: CatalogItem | None = None
231246

@@ -238,6 +253,14 @@ def __init__(
238253
under = info.under if under is None else under
239254
bad = info.bad if bad is None else bad
240255
self.info = info
256+
257+
# Check if cmap_kwargs is provided for a non-callable colormap
258+
if cmap_kwargs and not callable(info.data):
259+
raise TypeError(
260+
f"Cannot apply cmap_kwargs to colormap {info.name!r}: "
261+
"colormap is not a parametrized callable"
262+
)
263+
241264
if isinstance(info.data, list):
242265
if not info.data: # pragma: no cover
243266
raise ValueError(f"Catalog colormap {info.name!r} has no data")
@@ -252,7 +275,12 @@ def __init__(
252275
f"Invalid catalog colormap data for {info.name!r}: {info.data}"
253276
)
254277
else:
255-
stops = _parse_colorstops(info.data)
278+
_data: ColormapLike
279+
if cmap_kwargs:
280+
_data = partial(cast("Callable", info.data), **cmap_kwargs)
281+
else:
282+
_data = info.data
283+
stops = _parse_colorstops(_data)
256284
if interpolation is None:
257285
interpolation = info.interpolation
258286
if rev:

tests/test_colormap.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,18 @@ def test_shifted() -> None:
236236
assert cm.shifted(0.5).shifted(-0.5) == cm
237237
# two shifts of 0.5 should give the original array
238238
assert cm.shifted().shifted() == cm
239+
240+
241+
def test_function_colormap_with_cmap_kwargs() -> None:
242+
# construct cubehelix with custom parameters
243+
ch = Colormap("cubehelix", cmap_kwargs={"start": 1.0, "rotation": -1.0})
244+
245+
# values should be different from default cubehelix
246+
default_ch = Colormap("cubehelix")
247+
assert ch(0.5) != default_ch(0.5)
248+
249+
250+
def test_invalid_function_colormap_with_cmap_kwargs() -> None:
251+
# providing cmap_kwargs to a non-callable colormap should raise TypeError
252+
with pytest.raises(TypeError, match=r"Cannot apply cmap_kwargs to colormap"):
253+
Colormap("viridis", cmap_kwargs={"param": 1.0})

0 commit comments

Comments
 (0)