Hi,
I try to create an animated 3d stickman-like pose of mine with plotly.
The data consists of 180 frames with each 33 joint coordinates:
>>print(x_new.shape)
>>print(y_new.shape)
>>print(z_new.shape)
(180, 33)
(180, 33)
(180, 33)
Connections between the joints are saved in POSE_CONNECTIONS:
>>print(POSE_CONNECTIONS)
[(<PoseLandmark.RIGHT_HEEL: 30>, <PoseLandmark.RIGHT_FOOT_INDEX: 32>),
(<PoseLandmark.RIGHT_EYE: 5>, <PoseLandmark.RIGHT_EYE_OUTER: 6>),
(<PoseLandmark.RIGHT_HIP: 24>, <PoseLandmark.RIGHT_KNEE: 26>),
(<PoseLandmark.RIGHT_KNEE: 26>, <PoseLandmark.RIGHT_ANKLE: 28>),
...
>>print(len(POSE_CONNECTIONS))
35
To achieve this I generate 180 go.Frame objects with each 35 go.Scatter3d lines:
import plotly.graph_objects as go
import numpy as np
def add_lines(x,y,z):
data = []
for connection in POSE_CONNECTIONS:
line = go.Scatter3d(
x=(x[connection[0].value],x[connection[1].value]),
y=(y[connection[0].value],y[connection[1].value]),
z=(z[connection[0].value],z[connection[1].value]),
mode="lines",
line=dict(color="blue",width=2)
)
data.append(line)
return data
def add_frames(x,y,z):
line_frames = [
go.Frame(
data=add_lines(x[k],y[k],z[k]),
traces= [0],
name=f'frame{k}'
)for k in range(len(x)-1)
]
return line_frames
Here is the code for the full animation
# Create figure
fig = go.Figure(
data=[
go.Scatter3d(x=[], y=[], z=[],
mode="lines",
line=dict(color="red", width=1))
])
fig.update_layout(
scene = dict(
xaxis=dict(
range=[-1, 1],
autorange=False,
),
yaxis=dict(
range=[-1, 1],
autorange=False,
),
zaxis=dict(
range=[-1, 1],
autorange=False,
),
),
)
frames = add_frames(x=x_new,y=y_new,z=z_new)
fig.update(frames=frames),
def frame_args(duration):
return {
"frame": {"duration": duration},
"mode": "lines",
"fromcurrent": True,
"transition": {"duration": duration, "easing": "linear"},
}
sliders = [
{
"pad": {"b": 10, "t": 60},
"len": 0.9,
"x": 0.1,
"y": 0,
"steps": [
{
"args": [[f.name], frame_args(0)],
"label": str(k),
"method": "animate",
}
for k, f in enumerate(fig.frames)
],
}
]
fig.update_layout(
sliders=sliders,
scene=dict(
aspectratio=dict(x=1, y=1, z=1),
),
updatemenus=[
dict(
type="buttons",
buttons=[
dict(label="Play",
method="animate",
args=[
None,
dict(frame=dict(redraw=True,fromcurrent=True, mode='immediate'))
]),
dict(args= [[None], {"frame": {"duration": 0, "redraw": False},
"mode": "immediate",
"transition": {"duration": 0}}],
label= "Pause",
method= "animate"
)
],
)
]
)
fig.show()
My problem I encountered is, that only one line gets displayed in the final animation. What did I wrong?