Skip to content

[Feature request] Trace-specific color sequences in Plotly Express via templates #5416

@antonymilne

Description

@antonymilne

Hello! I'm a huge fan of plotly and especially plotly.express, but there's something that's bothers me a lot...

Problem

There's no way to make a template use different color sequences for different trace types in plotly express. Currently it always uses template.layout.colorway (unless explicitly overridden) and ignores per-trace defaults in template.data.<trace_type>.

Example

I'll use histogram and scatter here as an example but it applies very generally.

Let's say I want to use colors ["orange", "purple", "grey"] for a histogram. These are different from the default qualitative palette template.layout.colorway. Plotly enables you to give trace-specific colors like the below but it doesn't work: Plotly express ignores template.data.histogram and uses the same template.layout.colorway palette for both plots.

import plotly.express as px
import plotly.io as pio
import plotly.graph_objects as go

histogram_colors = ["orange", "purple", "grey"]

# Set histogram-specific colors in the template
histogram_template = go.layout.Template(
    data={"histogram": [{"marker": {"color": histogram_colors}}]}
)
template = pio.templates.merge_templates("plotly", histogram_template)

df = px.data.iris()

# Expectation: scatter uses global layout.colorway; histogram uses ["orange","purple","grey"]
# Actual behaviour: both use global layout.colorway
fig1 = px.scatter(df, x="sepal_length", y="petal_length", color="species", template=template)
fig2 = px.histogram(df, color="species", template=template)
Image

Current workarounds

  • supply color_discrete_sequence or color_discrete_map to each px call
  • use multiple templates with different layout.colorway and apply a different template to each chart

Why this matters

In reality I don't actually want to completely change colors between histogram and scatter. Actually what I'd like to do is apply the same palette but desaturated to the histogram. Seaborn supports this e.g. barplot(saturation=0.75).

I would like to be able to achieve this with a single template and without manually supplying arguments on per-figure basis.

Proposed solution

Extend plotly express's discrete color resolution to look at trace-specific colors in preference to template.layout.colorway. A single Plotly template already has space to supply a different color palette on each trace by using template.data, and Plotly express does look in template.data but only for a very limited number of things, e.g. it looks at template.data.scatter for line_dash_sequence. But color_discrete_sequence is always taken from template.layout.colorway rather than looking at template.data.

Instead, plotly could take color_discrete_sequence from the relevant template.data trace and then, if that's not defined, fall back on the current mechanism to default to template.layout.colorway.

Alternative solutions

  • a new saturation argument in plotly schema, like there's already opacity. This wouldn't allow arbitrary changes between different trace types but just to desaturate
  • a new saturation argument in plotly.express that would automatically apply the color transformation, like in seaborn. No need to modify the plotly figure schema
  • ability to define different color sequences for different trace types in plotly express. plotly.express.defaults currently defines a single color_discrete_sequence, but there could be a new color_discrete_sequence_by_trace = {"histogram": ..., ...} or similar

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions