Skip to content
Merged
Changes from 1 commit
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
Next Next commit
Add trace-specific color sequence support from template.data
- Check template.data.<trace_type> for marker.color or line.color before falling back to template.layout.colorway
- Handle timeline special case (maps to bar trace type)
- Use marker colors first, fall back to line colors if no markers found
- Fixes issue #5416
  • Loading branch information
antonymilne committed Nov 26, 2025
commit 965b3bdc18a6e2fa10fbbded0751a83d2fce8812
23 changes: 21 additions & 2 deletions plotly/express/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ def one_group(x):
return ""


def apply_default_cascade(args):
def apply_default_cascade(args, constructor=None):
# first we apply px.defaults to unspecified args

for param in defaults.__slots__:
Expand Down Expand Up @@ -1038,6 +1038,25 @@ def apply_default_cascade(args):
args["color_continuous_scale"] = sequential.Viridis

if "color_discrete_sequence" in args:
if args["color_discrete_sequence"] is None and constructor is not None:
if constructor == "timeline":
trace_type = "bar"
else:
trace_type = constructor().type
if trace_data_list := getattr(args["template"].data, trace_type, None):
collected_colors = [
trace_data.marker.color
for trace_data in trace_data_list
if hasattr(trace_data, "marker")
]
if not collected_colors:
collected_colors = [
trace_data.line.color
for trace_data in trace_data_list
if hasattr(trace_data, "line")
]
if collected_colors:
args["color_discrete_sequence"] = collected_colors
if args["color_discrete_sequence"] is None and args["template"].layout.colorway:
args["color_discrete_sequence"] = args["template"].layout.colorway
if args["color_discrete_sequence"] is None:
Expand Down Expand Up @@ -2486,7 +2505,7 @@ def get_groups_and_orders(args, grouper):
def make_figure(args, constructor, trace_patch=None, layout_patch=None):
trace_patch = trace_patch or {}
layout_patch = layout_patch or {}
apply_default_cascade(args)
apply_default_cascade(args, constructor=constructor)

args = build_dataframe(args, constructor)
if constructor in [go.Treemap, go.Sunburst, go.Icicle] and args["path"] is not None:
Expand Down