Reputation: 65
I am trying to plot particles in a 3d scatter animation using matplotlib. I've tried modifying the official 3d line plot animation example to achieve this. However, my code does not animate the points, but renders them all at once. I cannot figure out what the issues is. Any help or hints would be greatly appreciated.
MRE:
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
import numpy as np
def Gen_RandPrtcls():
n = 10
x = np.random.normal(size=(n,3))*5
# m = np.repeat(1. / n, n)
# Computing trajectory
data = [x]
nbr_iterations = 300
for iteration in range(nbr_iterations):
# data.append(data[-1] + GravAccel(data[-1], m))
data.append(data[-1]*1.01)
return data
def update_prtcls(num, dataPrtcls, parts):
for prtcl, data in zip(parts, dataPrtcls):
# NOTE: there is no .set_data() for 3 dim data...
prtcl.set_data(data[:num][:,0:1])
prtcl.set_3d_properties(data[:num][:,2])
return parts
# Attaching 3D axis to the figure
fig = plt.figure()
ax = p3.Axes3D(fig)
# Fifty parts of random 3-D parts
data = Gen_RandPrtcls()
# NOTE: Can't pass empty arrays into 3d version of plot()
parts = [ax.plot(dat[:,0], dat[:,1], dat[:,2], marker='.', linestyle="None")[0] for dat in data]
# Setting the axes properties
ax.set_xlim3d([-10.0, 10.0])
ax.set_xlabel('X')
ax.set_ylim3d([-10.0, 10.0])
ax.set_ylabel('Y')
ax.set_zlim3d([-10.0, 10.0])
ax.set_zlabel('Z')
ax.set_title('3D Test')
# Creating the Animation object
prtcl_ani = animation.FuncAnimation(fig, update_prtcls, 25, fargs=(data, parts),
interval=50, blit=False)
plt.show()
Upvotes: 3
Views: 1629
Reputation: 4537
You have structured your data
in a different order than you intended.
import numpy as np
def Gen_RandPrtcls(n_particles, n_iterations):
x = np.random.normal(size=(n_particles, 3))*5
# Computing trajectory
data = [x]
for iteration in range(n_iterations):
# data.append(data[-1] + GravAccel(data[-1], m))
data.append(data[-1]*1.01)
return data
data = Gen_RandPrtcls(n_particles=10, n_iterations=300)
data = np.array(data) # (n_iterations, n_particles, 3)
In the first dimension of data
are the iterations
, in the second are the different particles
and in the third are the spacial coordinates
.
In your current update you plot all the iteration for the particles up to num data[:, 0:num, :]
and not the iteartions up to num data[0:num, :, :]
for all particles.
I made some small changes to your code. I plot the trajectories of all particles simultaneously, starting just with the first iteration.
So I don't have to loop over the particles. (If all particles should be displayed with the same color [marker, ...] this works fine. Otherwise you would have
a LineObject
for each particle. But the logic should be the same).
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
fig = plt.figure()
ax = p3.Axes3D(fig)
# Plot the first position for all particles
h = ax.plot(*data[0].T, marker='.', linestyle='None')[0]
# Equivalent to
# h = ax.plot(data[0, :, 0], data[0, :, 1], data[0, :, 2],
# marker='.', linestyle='None')[0]
# Setting the axes properties
ax.set_xlim3d([-100.0, 100.0])
ax.set_xlabel('X')
ax.set_ylim3d([-100.0, 100.0])
ax.set_ylabel('Y')
ax.set_zlim3d([-100.0, 100.0])
ax.set_zlabel('Z')
ax.set_title('3D Test')
def update_particles(num):
# Plot the iterations up to num for all particles
h.set_xdata(data[:num, :, 0].ravel())
h.set_ydata(data[:num, :, 1].ravel())
h.set_3d_properties(data[:num, :, 2].ravel())
return h
prtcl_ani = animation.FuncAnimation(fig, update_particles, frames=301,
interval=10)
Here is the result. Hope that helps.
If you want different colors for the particles you need to plot them seperatly:
colormap = plt.cm.tab20c
colors = [colormap(i) for i in np.linspace(0, 1, n_particles)]
h_particles = [ax.plot(*data[:1, i].T, marker='.', c=colors[i], ls='None')[0]
for i in range(n_particles)]
def update_particles(num):
for i, h in enumerate(h_particles):
h.set_xdata(data[:num, i, 0])
h.set_ydata(data[:num, i, 1])
h.set_3d_properties(data[:num, i, 2])
return h_particles
Upvotes: 3