4

Okay, so my initial idea is to make a line plot in plotly and color the line with one color after certain threshold t, and another color before the threshold. It works for a 23 or less points, but it works with no more, using this method:

import numpy as np
import plotly.graph_objects as go

X = [j for j in range(0, 100)]
Y = [j for j in range(100000, 200000, 1000)]
X = X[:23]
Y = Y[:23]
X = np.array(X)
Y = np.array(Y)
t = 4

x = X[X <= t]  # Include the threshold
y = Y[X <= t]
bx = X[X >= t]
by = Y[X >= t]

fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, line=dict(width=4, color='grey'), name="useless data"))
fig.add_trace(go.Scatter(x=bx, y=by, line=dict(width=4, color='blue'), name="useful data"))
fig.update_layout(xaxis_title="x axis", yaxis_title="y axis")
fig.show()

So this works normally, and if you run it, you will see that 4 is included in the blue points. But now, please remove the lines where only 23 values are taken (X = X[:23], Y = Y[:23]). You will see that 4 is no longer part of the blue points, moreover, the points themselves disappear from the graph in the blue line, you can hover and see data, but you can't see the actual points! If anyone knows why this happens, is it an actual bug or it is normal behaviour and there is something I am missing? Thank you in advance!

S3DEV
  • 8,768
  • 3
  • 31
  • 42
Petar
  • 195
  • 2
  • 14

2 Answers2

7

Bug? Not necessarily. Weird behaviour? Perhaps...

In any case, the solution in your case is:

fig.data[1].mode = 'lines+markers'

What you seem to be struggling with here is caused by two things:

  1. When hovering over a point where there is one trace represented by a line, and one trace represented by a marker, plotly will display the information for the marker even though the line is placed on top.
  2. For an increasing length of a go.Scatter() trace, plotly will stop showing markers for after a certain threshold.
  3. And this is perhaps the arguably weird part; that the exact threshold does not seem to be determined by the length of the trace alone. We'll take a look at that in the end.

Details:


1. Hover behavior

Just run your code as it is, and hover over 4:

enter image description here

Now deselect useless data by clicking the name in the legend and you'll get:

enter image description here

If you zoom in a bit, you'll see that the data is actually there, it just won't show on hover when both traces are activated:

enter image description here

So, what to do about it?

Just include:

fig.data[1].mode = 'lines+markers'

And get:

enter image description here

2. Marker trigger threshold for go.Scatter

In your case, this threshold seems to be a trace with length = 23 since you're seeing the exact behaviour you're describing. So, what's weird about this? The next part:

3. Varying marker trigger threshold

First of all, *why is there a threshold? Probably because a trace with too many markers arguably looks weird:

enter image description here

You found the threshold to be 24. But in a figure built only with go.Figure(go.Scatter(x = x, y = y)), the threshold is 20:

pts = 20
x = np.arange(1,pts)
y = np.arange(1,pts)
fig = go.Figure(go.Scatter(x = x, y = y)).show()

enter image description here

pts = 21
x = np.arange(1,pts)
y = np.arange(1,pts)
fig = go.Figure(go.Scatter(x = x, y = y)).show()

enter image description here

And I'm not sure why. But I think that would make for a good question on its own.

vestland
  • 55,229
  • 37
  • 187
  • 305
3

The reason:

This is a 'feature' of Plotly Scatter plots. When (a number) of points are plotted, the underlying Plotly logic converts the 'scatter' plot to a 'line' plot, for rendering efficiency and plot cleanliness. Thus, the markers are converted to a solid line.

The fix:

Simply add mode='lines+markers' to the trace.

Full working example:

This is your source code, with the minor fix mentioned above:

import numpy as np
import plotly.graph_objects as go

X = [j for j in range(0, 100)]
Y = [j for j in range(100000, 200000, 1000)]
#X = X[:23]
#Y = Y[:23]
X = np.array(X)
Y = np.array(Y)
t = 4

x = X[X <= t]  # Include the threshold
y = Y[X <= t]
bx = X[X >= t]
by = Y[X >= t]

fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode='lines+markers', line=dict(width=1, color='grey'), name="useless data"))
fig.add_trace(go.Scatter(x=bx, y=by, mode='lines+markers', line=dict(width=1, color='blue'), name="useful data"))
fig.update_layout(xaxis_title="x axis", yaxis_title="y axis")
fig.show()

Output:

enter image description here

S3DEV
  • 8,768
  • 3
  • 31
  • 42