-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
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)
Current workarounds
- supply
color_discrete_sequenceorcolor_discrete_mapto eachpxcall - use multiple templates with different
layout.colorwayand apply a differenttemplateto 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
saturationargument in plotly schema, like there's alreadyopacity. This wouldn't allow arbitrary changes between different trace types but just to desaturate - a new
saturationargument 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.defaultscurrently defines a singlecolor_discrete_sequence, but there could be a newcolor_discrete_sequence_by_trace = {"histogram": ..., ...}or similar