Skip to content

Commit 40f2a6d

Browse files
FBumannclaude
andcommitted
fix: continuous colorscale strings with discrete-only chart types
Passing a continuous colorscale like `colors='turbo'` to area(), line(), fast_bar(), box(), or pie() previously failed because `resolve_colors` set `color_continuous_scale` which these px functions don't accept. Now samples from the continuous scale into a discrete sequence for these chart types. bar() and scatter() natively support continuous scales so are left unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 63f37a7 commit 40f2a6d

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

xarray_plotly/common.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,21 @@ def _get_qualitative_scale_names() -> frozenset[str]:
251251
)
252252

253253

254-
def resolve_colors(colors: Colors, px_kwargs: dict[str, Any]) -> dict[str, Any]:
254+
def _sample_colorscale(name: str, n: int) -> list[str]:
255+
"""Sample *n* evenly-spaced colors from a named Plotly colorscale."""
256+
scale = px.colors.get_colorscale(name)
257+
samplepoints = [i / max(n - 1, 1) for i in range(n)]
258+
result: list[str] = px.colors.sample_colorscale(scale, samplepoints)
259+
return result
260+
261+
262+
def resolve_colors(
263+
colors: Colors,
264+
px_kwargs: dict[str, Any],
265+
*,
266+
color_dim: Hashable | None = None,
267+
darray: DataArray | None = None,
268+
) -> dict[str, Any]:
255269
"""Map unified `colors` parameter to appropriate Plotly px_kwargs.
256270
257271
Direct color_* kwargs take precedence and trigger a warning if
@@ -260,6 +274,14 @@ def resolve_colors(colors: Colors, px_kwargs: dict[str, Any]) -> dict[str, Any]:
260274
Args:
261275
colors: Unified color specification (str, list, dict, or None).
262276
px_kwargs: Existing kwargs to pass to Plotly Express.
277+
color_dim: Dimension name used for discrete color grouping.
278+
When provided together with *darray*, a continuous colorscale
279+
string is sampled into a discrete sequence whose length
280+
matches the number of coordinates along this dimension.
281+
Use for chart types that only accept discrete color
282+
parameters (line, area, box, pie).
283+
darray: Source DataArray; used with *color_dim* to determine the
284+
number of discrete colors to sample.
263285
264286
Returns:
265287
Updated px_kwargs with color parameters injected.
@@ -284,6 +306,10 @@ def resolve_colors(colors: Colors, px_kwargs: dict[str, Any]) -> dict[str, Any]:
284306
# Check if it's a qualitative (discrete) palette name
285307
if colors in _get_qualitative_scale_names():
286308
px_kwargs["color_discrete_sequence"] = getattr(px.colors.qualitative, colors)
309+
elif color_dim is not None and darray is not None:
310+
# Sample from continuous scale into a discrete sequence
311+
n = darray.sizes[color_dim]
312+
px_kwargs["color_discrete_sequence"] = _sample_colorscale(colors, n)
287313
else:
288314
# Assume continuous scale
289315
px_kwargs["color_continuous_scale"] = colors

xarray_plotly/plotting.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ def line(
8282
-------
8383
plotly.graph_objects.Figure
8484
"""
85-
px_kwargs = resolve_colors(colors, px_kwargs)
8685
slots = assign_slots(
8786
list(darray.dims),
8887
"line",
@@ -94,6 +93,7 @@ def line(
9493
facet_row=facet_row,
9594
animation_frame=animation_frame,
9695
)
96+
px_kwargs = resolve_colors(colors, px_kwargs, color_dim=slots.get("color"), darray=darray)
9797

9898
df = to_dataframe(darray)
9999
value_col = get_value_col(darray)
@@ -329,7 +329,6 @@ def fast_bar(
329329
-------
330330
plotly.graph_objects.Figure
331331
"""
332-
px_kwargs = resolve_colors(colors, px_kwargs)
333332
slots = assign_slots(
334333
list(darray.dims),
335334
"fast_bar",
@@ -339,6 +338,7 @@ def fast_bar(
339338
facet_row=facet_row,
340339
animation_frame=animation_frame,
341340
)
341+
px_kwargs = resolve_colors(colors, px_kwargs, color_dim=slots.get("color"), darray=darray)
342342

343343
df = to_dataframe(darray)
344344
value_col = get_value_col(darray)
@@ -410,7 +410,6 @@ def area(
410410
-------
411411
plotly.graph_objects.Figure
412412
"""
413-
px_kwargs = resolve_colors(colors, px_kwargs)
414413
slots = assign_slots(
415414
list(darray.dims),
416415
"area",
@@ -421,6 +420,7 @@ def area(
421420
facet_row=facet_row,
422421
animation_frame=animation_frame,
423422
)
423+
px_kwargs = resolve_colors(colors, px_kwargs, color_dim=slots.get("color"), darray=darray)
424424

425425
df = to_dataframe(darray)
426426
value_col = get_value_col(darray)
@@ -487,7 +487,6 @@ def box(
487487
-------
488488
plotly.graph_objects.Figure
489489
"""
490-
px_kwargs = resolve_colors(colors, px_kwargs)
491490
slots = assign_slots(
492491
list(darray.dims),
493492
"box",
@@ -498,6 +497,7 @@ def box(
498497
facet_row=facet_row,
499498
animation_frame=animation_frame,
500499
)
500+
px_kwargs = resolve_colors(colors, px_kwargs, color_dim=slots.get("color"), darray=darray)
501501

502502
df = to_dataframe(darray)
503503
value_col = get_value_col(darray)
@@ -746,14 +746,14 @@ def pie(
746746
-------
747747
plotly.graph_objects.Figure
748748
"""
749-
px_kwargs = resolve_colors(colors, px_kwargs)
750749
slots = assign_slots(
751750
list(darray.dims),
752751
"pie",
753752
names=names,
754753
facet_col=facet_col,
755754
facet_row=facet_row,
756755
)
756+
px_kwargs = resolve_colors(colors, px_kwargs, color_dim=slots.get("names"), darray=darray)
757757

758758
df = to_dataframe(darray)
759759
value_col = get_value_col(darray)

0 commit comments

Comments
 (0)