Context
I have a scattergl with many datapoints. Therefore, created an animation using shapes. It works wonderful until I update the frames for the second time in the callback. I check that all data still exists, and it does, so it should be drawn. But checking the dev console in the brower it says:
Uncaught TypeError: r[v] is undefined
Code is functional if I use go.Scatter instead of go.Scattergl. I traced the error back to the source code:
// form batch arrays, and check for selected points
var dragmode = fullLayout.dragmode;
var isSelectMode = selectMode(dragmode);
var clickSelectEnabled = fullLayout.clickmode.indexOf('select') > -1;
for(i = 0; i < count; i++) {
var cd0 = cdata[i][0]; //This is what causes "r[v] is undefined" in the plotly.min.js
var trace = cd0.trace;
var stash = cd0.t;
...
Link:
So in plotly.min.js
, r[v][0]
refers to cdata[i][0]
This is as far as I’ve gotten. I’m unable to figure it out and could really use some help.
My code
Figure setup:
fig = go.Figure(
layout=go.Layout(
updatemenus=[dict(
type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None, dict(frame=dict(duration=60//1000, redraw=False))])])]
)
)
for cluster in range(cluster_ids):
msk = cluster_labels == cluster
x, y = embedding[msk].T
fig.add_trace(
go.Scattergl(
x=x,
y=y,
name=f'Cluster {cluster}',
mode='markers',
marker=dict(color=CLUSTER_COLORS[cluster], size=MARKER_SIZE),
hoverinfo='skip'
)
)
#update layout...
Code for creating frames
frames=[]
for H, T in zip(head, tail):
head_circle = get_svg_circular_path(H[0], H[1], r) # calculates circle as svg to prevent resizing
tail_circle = get_svg_circular_path(T[0], T[1], r) # calculates circle as svg to prevent resizing
frame = go.Frame(
layout=dict(
shapes=[
dict(type="line", x0=T[0], y0=T[1], x1=H[0], y1=H[1], fillcolor='#636EFA'),
dict(type='path', path=head_circle, **path_kwargs),
dict(type='path', path=tail_circle, **path_kwargs),
],
),
)
frames.append(frame)
Callback
@callback(
Output('graph-id', 'figure'),
[
Input('calculate-button', 'n_clicks'),
State({'type': 'value-sliders', 'index': ALL}, 'value'),
# State('graph-id', 'figure') <-- using the fig's data object has same effect
]
)
def calculate_new_fig(n_clicks, values):
# removed some code for readability
# but the essence is that I use to the values to update the animation location
fig = get_initial_map() # this get the figure earlier code snippet
if n_clicks:
frames = get_frames()
fig.update(frames=frames)
return fig
return fig
What I’ve tried
I’ve tried re-creating the figure, using the dcc.Graph figure atribute, extending the list with frames instead of overriding, reduce scattergl size (as in number of datapoints), adding data dict to go.Frame, and redraw True.
Notable observations
Code 100% works if I replace the go.Scattergl
with go.Scatter
.
First time the frame are added the animation plays perfectly smooth. When I then update the frames with a new animation, the animation is shown, but the points in the Scattergl dissappear. So animation - yes, data - no.
Additionally, when printing the fig.data[0]
datastructure, everything is EXACTLY the same each iteration. So, first, second, third, nth animation frames. It just DOES NOT get drawn and I see and Uncaught TypeError: r[v] is undefined
in the console. Note that app doesn’t crash.