Skip to content

feature request: z-ordering parameter for traces #2345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lucgiffon opened this issue Apr 2, 2020 · 35 comments
Closed

feature request: z-ordering parameter for traces #2345

lucgiffon opened this issue Apr 2, 2020 · 35 comments
Assignees
Labels
P1 needed for current cycle

Comments

@lucgiffon
Copy link

Hello,

it would be very nice to have the possibilty to set the z-ordering priority of traces in plotly. I think the way matplotlib handles it is pretty handy:

  • default z-order value for a trace is 0;
  • if multiple trace have the same z-order value, matplotlib decides the ordering of traces itself (random or whatever);
  • if a trace have a greater z-order than an other, it appears on top of it;
  • if a trace have a smaller z-order value than the other, it appears below;

Veeeery useful. Right now I am strugling to have a marker to appear on top of a bunch of line plots and it is very annoying.

@lucgiffon
Copy link
Author

By the way, the hack I found to overcome this problem right now is to store the trace I want to add on TOP in a globalvariable (on can think of a list if one have multiple trace to add in a certain ordering) and then, just before rendering the figure, I had the trace to the figure. Then the last added trace appears on top of all other traces.

@huidongchen
Copy link

I am encountering the same issue. I would like to add several lines on top of scatter plot generated by px.scatter() .I tried to reorder the traces by doing fig.data = fig.data[::-1] but it only changes the order shown in legend, I still have not been able to add lines on top of points after trying almost all the tricks online, which is a bit frustrating..

it would be super helpful if plotly can support something like zorder

@tritemio
Copy link

Another use case for this feature is related to legend ordering. Currently, if you use the order of traces to specify the legend ordering, we cannot specify a z order independently. Since legend order is either None (i.e. insertion order) or alphabetical order, it is impossible to set an arbitrary order of legend items and at the same time set and arbitrary zorder of traces.

@dmalyuta
Copy link

Has there been any movement to try to implement this?

@nicolaskruchten
Copy link
Contributor

A few notes on this:

  1. This would have to be implemented in Plotly.js rather than in Python
  2. Traces are currently drawn in batches by type, so scatter is always drawn on top of bar, etc, and this would be quite complicated to change, so the more straightforward option would be to control the other within types first

@nicolaskruchten
Copy link
Contributor

I should add that fig.data = fig.data[::-1] does work for me:

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

fig = px.scatter(x=[1,2,3,4], y=[1,2,3,4], size=[1,2,3,4], color=["a","a","b","b"])
fig.add_trace(go.Scatter(x=[1,2,3,4], y=[1,2,3,4], mode="lines", line_color="black"))
fig.data = fig.data[::-1]
fig.show()

as does reordering fig.data like this:

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

fig = px.scatter(x=[1,2,3,4], y=[1,2,3,4], size=[1,2,3,4], color=["a","a","b","b"])
fig.add_trace(go.Scatter(x=[1,2,3,4], y=[1,2,3,4], mode="lines", line_color="black"))
fig.data = (fig.data[1],fig.data[2],fig.data[0])
fig.show()

@JoElfner
Copy link

Any news on this? This would be a great feature!

@jaymegordo
Copy link

jaymegordo commented Jan 3, 2021

+1, would love to be able to draw scatter traces BEHIND candlesticks for example. When trying to use hover label to inspect individual candles, other lines on top prevent label from showing.

@set92
Copy link

set92 commented Feb 13, 2021

I should add that fig.data = fig.data[::-1] does work for me:

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

fig = px.scatter(x=[1,2,3,4], y=[1,2,3,4], size=[1,2,3,4], color=["a","a","b","b"])
fig.add_trace(go.Scatter(x=[1,2,3,4], y=[1,2,3,4], mode="lines", line_color="black"))
fig.data = fig.data[::-1]
fig.show()

as does reordering fig.data like this:

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

fig = px.scatter(x=[1,2,3,4], y=[1,2,3,4], size=[1,2,3,4], color=["a","a","b","b"])
fig.add_trace(go.Scatter(x=[1,2,3,4], y=[1,2,3,4], mode="lines", line_color="black"))
fig.data = (fig.data[1],fig.data[2],fig.data[0])
fig.show()

Seems this trick doesn't work when there is too much data. Example:

import plotly.express as px
import plotly.graph_objects as go
import numpy as np

df = np.random.randint(0,100,size=(10000, 2))
color_df = np.random.randint(0,4,size=(10000, 1)).T[0]
centers = np.random.randint(0,100,size=(7, 2))

fig = px.scatter(x=df[:, 0], y=df[:, 1], color=color_df)
fig.add_scatter(
    x=centers[:, 0],
    y=centers[:, 1],
    marker=dict(size=20, color="LightSeaGreen"),
    name="Centers",
    mode="markers",
)
fig.data = (fig.data[1], fig.data[0])
fig.show()

I tried removing the optional parameters and use only X,Y but it keeps putting the centers below the data.

@ptim
Copy link

ptim commented Mar 29, 2021

Seems this trick doesn't work when there is too much data.

I'm having a similar issue with a Candlestick trace always rendering in the BG, but in my case, I see the the legend re-ordered, but the graph maintains the old z ordering (candles are obscured by the scatter I'm trying to put in the BG).

@benlindsay
Copy link

I should add that fig.data = fig.data[::-1] does work for me:

This does allow you to rearrange the order of the traces, but it rearranges it both in the legend and in the plot itself. The layering of the traces still seems to be inextricably linked to the order of the legend, unless there's something I'm missing. Often, I want less important traces to be at the bottom of the legend AND at the bottom layer on the plot. I don't see a way to do this currently. +1 for z-ordering parameter suggestion :)

(BTW, I love plotly and use it all the time. Thanks for maintaining such an awesome library!)

@fleimgruber
Copy link

fleimgruber commented Jun 10, 2021

@set92, @ptim just a quick FYI as I got a similar problem (with "too much" data) and got it working following your lead. The hint was in #2345 (comment), i.e. the ordering is done per type. In your example in #2345 (comment) the px.scatter is implicitly converted to a Scattergl but the add_scatter only adds a Scatter object. Now when the graph object for add_trace has the same resulting type (Scattergl), this works for me:

import plotly.express as px
import plotly.graph_objects as go
import numpy as np

df = np.random.randint(0, 100, size=(10000, 2))
color_df = np.random.randint(0, 4, size=(10000, 1)).T[0]
centers = np.random.randint(0, 100, size=(7, 2))

fig = px.scatter(x=df[:, 0], y=df[:, 1], color=color_df)
fig.add_trace(
    go.Scattergl(
        x=centers[:, 0],
        y=centers[:, 1],
        marker=dict(size=20, color="LightSeaGreen"),
        name="Centers",
        mode="markers",
    )
)
fig.show()

@nicolaskruchten
Copy link
Contributor

Please note that the idea of controlling the legend order is tracked in #2345, and is in principle distinct from the drawing order.

@nicolaskruchten
Copy link
Contributor

Update on legend ordering independently of trace ordering in data: this is now possible with the new legendrank attribute in v5.0 :) https://plotly.com/python/legend/#legend-order

@ievgennaida
Copy link

ievgennaida commented Jun 22, 2021

@nicolaskruchten Thank you!
Works fine even with the subplots.

Is it possible also to specify this for the shapes? I would like to keep sibling shapes in the same z-order.

Is it affecting traces z-order or only legends order in the legends panel?

@nicolaskruchten
Copy link
Contributor

legendrank only impacts the legend, not the z-order, and shapes aren't linked to the legend, so this approach will not impact shapes, no.

@ievgennaida
Copy link

@nicolaskruchten
Thank you, it's clear now, can it be also mentioned in the example documentation that it's about order, not z-order of the traces?

Basically, my problem was that when you have subplots it's hard to control order of the legends sorted.
Ex:

  • SubPlot 1 [legend 14, legend 15]
  • SubPlot 2 [legend 1, legend 2, legend 3, legend 4]

Expected legend:
[legend 1, legend 2, legend 3, legend 4, legend 14, legend 15]

But in reality it was taken grouped from subplots.

This sorting problem is solved by legendrank.

But also sorting collerates with order for me:
I am sorting legend by importance and it's expected that legends on top should be rendered top most (same is applicable for the related shapes, but less critical).

Actually to achieve the top most (legend on right) I have reverted order of the traces before appending them and than reverted back by the plotly property 'revert legends order'.

Now I can append in any order to control z and rank legends to keep order.

@maegul
Copy link

maegul commented Jul 26, 2021

Related to this, not having a z-order for a ridgeline plot caused me some trouble.

I wanted the bottom traces to be drawn on top. But it seems that both the stacking order for violin plots and the (implicit) z-order are both bound to the fig.data ordering ... it isn't possible without some unintuitive hacking (see my example result at the bottom)

See my comment on the ridgeline plots issue: plotly/plotly_express#25 (comment)

See my post in the community forum: https://community.plotly.com/t/ridgeline-joy-plot-without-transparency/55028?u=maegul

Screen Shot 2021-07-26 at 2 32 46 pm

@DJM-GM
Copy link

DJM-GM commented Aug 8, 2021

px.scatter is implicitly converted to a Scattergl but the add_scatter only adds a Scatter object. Now when the graph object for add_trace has the same resulting type (Scattergl)

And it works for me also.

So pleased that fleimgruber found and offered the work around that, after 'wasting' a day trying to find a solution, I signed up just to say 'Thank You, fleimgruber'.

@MichauGabriel
Copy link

For the Scattergl trick, I also had the problem that px.scatter makes either Scattergl or Scatter traces (depending on the number of points to plot?). But one can force webgl in all cases with 'render_mode="webgl"', so that the trick of re-ordering fig.data always works.

@florian6973
Copy link

Would be a very nice and useful feature

@vuk119
Copy link

vuk119 commented May 6, 2023

Why is it still not implemented after 3 years?!

@janosh
Copy link
Contributor

janosh commented May 6, 2023

Why is it still not implemented after 3 years?!

Nobody is being paid to do this. it's not happening unless you or someone else decides to donate their time.

@MikePreston
Copy link

Does someone fancy donating their time to this issue? - for the forwarding and advancement of humankind

@frozensimo
Copy link

Up! This feature would be ace to have!

steveand117 added a commit to claws-lab/dygetviz that referenced this issue Sep 14, 2023
After reading this issue, plotly/plotly.py#2345 (comment)

We needed to convert the traces, which were Scatter() objects, into Scattergl() objects as they have different drawing priorities.

In the future, we should change the cache to be of ScatterGL objects instead of Scatter. This is a temporary fix
@aleferna12
Copy link

Life changing feature, would love to see it implemented in the future!

@devamin
Copy link

devamin commented Jan 13, 2024

push push

@aymeric-roucher
Copy link

Same here, this would be useful!

@Coding-with-Adam Coding-with-Adam added new feature P1 needed for current cycle labels Jan 18, 2024
@beevabeeva
Copy link

beevabeeva commented Feb 27, 2024

imperative feature. It should also be possible to alter the order in the rendered plot, by dragging and dropping the key items into the desired order.

@ayjayt
Copy link
Contributor

ayjayt commented Mar 11, 2024

looks like someone is working on it

@ndrezn
Copy link
Member

ndrezn commented Mar 27, 2024

Want to note, given there is so much excitement about this feature in this thread: Members of the Plotly team are currently working on this feature in plotly.js in plotly/plotly.js#6918, which means it will be inherited by plotly.py once completed. Really excited to see this feature land!

@Farkites
Copy link

I'm happy to announce that this feature is now available from version 5.21.0 for all SVG based cartesian traces. Please see the example below:

import plotly.graph_objects as go

fig = go.Figure(
    go.Bar(
        x=[0, 1, 2],
        y=[1, 2, 3]
    )

)
fig.add_trace(
    go.Scatter(
        x=[0, 1, 2],
        y=[3, 2, 1],
        zorder=-2
    )
)
fig.show()

newplot (2)

@yotkadata
Copy link

Awesome! Thanks so much to all the developers.

@janjoch
Copy link

janjoch commented Jul 5, 2024

Really awesome! This helps a lot.

However, it is still not supported for annotations plotly.graph_objects.Figure.add_annotation. Is this on the roadmap?

It would be really useful to set a watermark or "disclaimer message", for instance.

@jarrisondev
Copy link

It's still not supported for scattergl traces in plotly.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P1 needed for current cycle
Projects
None yet
Development

No branches or pull requests