Scatter3d animation deletes other traces?

Here is a minimal example, which plots a grid of points and uses a slider to interactively display selected rows. However, the original grid plot disappears as soon as the slider is moved.

Is this intentional or a bug?

If it’s not a bug, how can I prevent that trace from disappearing?

import numpy as np
import plotly.graph_objects as go
# generate grid
N = 10
x, y = np.meshgrid(np.linspace(0, 1, N), np.linspace(0, 1, N))
z = np.zeros((N, N))
# plot
fig = go.Figure(
    # all points (THIS DISAPPEARS!)
    data=[go.Scatter3d(x=x.flatten(), y=y.flatten(), z=z.flatten())],
    # single rows animated via slider
    frames=[go.Frame(data=[go.Scatter3d(x=x[i], y=y[i], z=z[i])], name=f"{i}") for i in range(N)],
    layout_sliders=[dict(steps=[dict(method='animate', args=[[f"{k}"]], label=f"{k}") for k in range(N)])])
fig.write_html('plot.html')
fig.show()

Two other weird things, which might be unrelated:

  1. Setting a marker size on the first trace also changes the marker size of the animated traces. Should that be the case?!
  2. The interactively opened plot behaves differently from opening the saved html plot (the second one starts playing the animation right away, the first one doesn’t). Bug?

@robert-lieck

  • If your frame does not change the marker size, then it inherits the marker size from your fig.data[0].
    To get markers of size different from that in fig.data[0] you should define a frame like this:
go.Frame(go.Scatter3d(x=x[i], y=y[i], z=z[i], marker_size=2)

With a slight modification your animation works.
Namely, I added a dummy trace to keep the scene fixed. Otherwise it moves during the animation and your markers are not visible in the new scene.
I post here two versions: the first one, that displays a single row of markers in each frame, like in your code, and the second one keeps the rows already added:

1.

import numpy as np
import plotly.graph_objects as go
# generate grid
N = 10
x, y = np.meshgrid(np.linspace(0, 1, N), np.linspace(0, 1, N))
z = np.zeros((N, N))
# plot
fig = go.Figure(
    
    data=[go.Scatter3d(x=[x.min(),x.max()], y=[y.min(), y.max()], z=[z.min(), z.max()], mode="markers",
                       marker_size=0.05, marker_color="white", showlegend=False),
          go.Scatter3d(x=x.flatten(), y=y.flatten(), z=z.flatten())],
    # single rows animated via slider
    frames=[go.Frame(data=[go.Scatter3d(x=x[i], y=y[i], z=z[i])], 
                     name=i,
                     traces=[1])  for i in range(N)], #traces=[1] tells plotly.js that each frame updates fig.data[1]
    layout_sliders=[dict(steps=[dict(method='animate', args=[[i]], label=f"{i}") for i in range(N)])])
fig.show()

2.

import numpy as np
import plotly.graph_objects as go
# generate grid
N = 10
x, y = np.meshgrid(np.linspace(0, 1, N), np.linspace(0, 1, N))
z = np.zeros((N, N))
# plot
fig = go.Figure(
    data=[go.Scatter3d(x=[x.min(),x.max()], y=[y.min(), y.max()], z=[z.min(), z.max()], mode="markers",
                       marker_size=0.05, marker_color="white", showlegend=False),
          go.Scatter3d(x=x.flatten(), y=y.flatten(), z=z.flatten())],
    # single rows animated via slider
    frames=[go.Frame(data=[go.Scatter3d(x=x[:i, :].flatten(), y=y[:i, :].flatten(), z=z[:i, :].flatten())], 
                     name=i,
                     traces=[1])  for i in range(N)],
    layout_sliders=[dict(steps=[dict(method='animate', args=[[i]], label=f"{i}") for i in range(N)])])
fig.show()

LE:

fig.write_html("plot.html", auto_play=False)

is the fix for the second issue.

Thanks @empet! I am keeping the discussion on the page of the related GitHub issue.