Skip to content

Commit f5b74b8

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 f5b74b8

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

xarray_plotly/common.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,20 @@ 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+
n_colors: int | None = None,
267+
) -> dict[str, Any]:
255268
"""Map unified `colors` parameter to appropriate Plotly px_kwargs.
256269
257270
Direct color_* kwargs take precedence and trigger a warning if
@@ -260,6 +273,10 @@ def resolve_colors(colors: Colors, px_kwargs: dict[str, Any]) -> dict[str, Any]:
260273
Args:
261274
colors: Unified color specification (str, list, dict, or None).
262275
px_kwargs: Existing kwargs to pass to Plotly Express.
276+
n_colors: When set, continuous colorscale strings are sampled
277+
into a discrete sequence of this length instead of setting
278+
``color_continuous_scale``. Use for chart types that only
279+
accept discrete color parameters (line, area, box, pie).
263280
264281
Returns:
265282
Updated px_kwargs with color parameters injected.
@@ -284,6 +301,9 @@ def resolve_colors(colors: Colors, px_kwargs: dict[str, Any]) -> dict[str, Any]:
284301
# Check if it's a qualitative (discrete) palette name
285302
if colors in _get_qualitative_scale_names():
286303
px_kwargs["color_discrete_sequence"] = getattr(px.colors.qualitative, colors)
304+
elif n_colors is not None:
305+
# Sample from continuous scale into a discrete sequence
306+
px_kwargs["color_discrete_sequence"] = _sample_colorscale(colors, n_colors)
287307
else:
288308
# Assume continuous scale
289309
px_kwargs["color_continuous_scale"] = colors

xarray_plotly/plotting.py

Lines changed: 15 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,9 @@ def line(
9493
facet_row=facet_row,
9594
animation_frame=animation_frame,
9695
)
96+
px_kwargs = resolve_colors(
97+
colors, px_kwargs, n_colors=darray.sizes[slots["color"]] if slots.get("color") else None
98+
)
9799

98100
df = to_dataframe(darray)
99101
value_col = get_value_col(darray)
@@ -329,7 +331,6 @@ def fast_bar(
329331
-------
330332
plotly.graph_objects.Figure
331333
"""
332-
px_kwargs = resolve_colors(colors, px_kwargs)
333334
slots = assign_slots(
334335
list(darray.dims),
335336
"fast_bar",
@@ -339,6 +340,9 @@ def fast_bar(
339340
facet_row=facet_row,
340341
animation_frame=animation_frame,
341342
)
343+
px_kwargs = resolve_colors(
344+
colors, px_kwargs, n_colors=darray.sizes[slots["color"]] if slots.get("color") else None
345+
)
342346

343347
df = to_dataframe(darray)
344348
value_col = get_value_col(darray)
@@ -410,7 +414,6 @@ def area(
410414
-------
411415
plotly.graph_objects.Figure
412416
"""
413-
px_kwargs = resolve_colors(colors, px_kwargs)
414417
slots = assign_slots(
415418
list(darray.dims),
416419
"area",
@@ -421,6 +424,9 @@ def area(
421424
facet_row=facet_row,
422425
animation_frame=animation_frame,
423426
)
427+
px_kwargs = resolve_colors(
428+
colors, px_kwargs, n_colors=darray.sizes[slots["color"]] if slots.get("color") else None
429+
)
424430

425431
df = to_dataframe(darray)
426432
value_col = get_value_col(darray)
@@ -487,7 +493,6 @@ def box(
487493
-------
488494
plotly.graph_objects.Figure
489495
"""
490-
px_kwargs = resolve_colors(colors, px_kwargs)
491496
slots = assign_slots(
492497
list(darray.dims),
493498
"box",
@@ -498,6 +503,9 @@ def box(
498503
facet_row=facet_row,
499504
animation_frame=animation_frame,
500505
)
506+
px_kwargs = resolve_colors(
507+
colors, px_kwargs, n_colors=darray.sizes[slots["color"]] if slots.get("color") else None
508+
)
501509

502510
df = to_dataframe(darray)
503511
value_col = get_value_col(darray)
@@ -746,14 +754,16 @@ def pie(
746754
-------
747755
plotly.graph_objects.Figure
748756
"""
749-
px_kwargs = resolve_colors(colors, px_kwargs)
750757
slots = assign_slots(
751758
list(darray.dims),
752759
"pie",
753760
names=names,
754761
facet_col=facet_col,
755762
facet_row=facet_row,
756763
)
764+
px_kwargs = resolve_colors(
765+
colors, px_kwargs, n_colors=darray.sizes[slots["names"]] if slots.get("names") else None
766+
)
757767

758768
df = to_dataframe(darray)
759769
value_col = get_value_col(darray)

0 commit comments

Comments
 (0)