# How to create 3D animation of particles position vs time in python?

I am trying to make a 3-D animation of stars' position vs time. I have the information of the stars' x, y and z co-ordinates over time. I was looking at the example of Matplotlib and did understood what I need to do but I don't want the connecting lines between different times. All I need is to show the position of the stars at different time and make a movie of it. This is the example I was looking at

https://matplotlib.org/gallery/animation/simple_3danim.html

After that I want to make it a bit complicated. I have the stars size and mass as well. I was wondering if I can change the size of the circles in the plot according to the radius and use different Colors for different mass range?

• The answer you seek is going to be in the mplo3d documentation, not on this stackexchange. May 1 '20 at 1:18

After that I want to make it a bit complicated. I have the stars size and mass as well. I was wondering if I can change the size of the circles in the plot according to the radius and use different Colors for different mass range?

That part has been addressed in previous questions and answers here, I remember reading maybe a year ago (+/- 0.9 years).

Here is something you may find helpful reprinted from my answer in Stack Overflow. It's based on astronomer and data scientist Jake VanderPlas' blogpost from 2013.

For your needs keep the dots but not the lines. What I recommend is that you start from this and get as far as you can, then ask a question in Stack Overflow showing what you've tried and explaining what you still need.

Here is the Lorenz attractor both in 3D and animated. The script is in the following link (along with many goodies) in Jake VanderPlas' Pythonic Perambulations. You can learn a lot by going line-by-line through the script - it's an elegant use of matplotlib objects.

https://jakevdp.github.io/blog/2013/02/16/animating-the-lorentz-system-in-3d/

I added these two lines just before return in the animate function, and then used ImageJ to import the "image stack" and save the "animated GIF":

fname = "Astro_Jake_" + str(i+10000)[1:]
fig.savefig(fname)


Note: For OSX it seems to be necessary to set blit = False in animation.FuncAnimation. Here is a minimal, simplified example of plotting lines in 3D based on the above:

def lorentz_deriv((x, y, z), t0, sigma=10., beta=8./3, rho=28.0):
"""Compute the time-derivative of a Lorentz system."""
return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.integrate import odeint as ODEint

x = np.linspace(0, 20, 1000)
y, z = 10.*np.cos(x), 10.*np.sin(x) # something simple

fig = plt.figure()
ax.plot(x, y, z)

# now Lorentz
times = np.linspace(0, 4, 1000)

start_pts = 30. - 15.*np.random.random((20,3))  # 20 random xyz starting values

trajectories = []
for start_pt in start_pts:
trajectory = ODEint(lorentz_deriv, start_pt, times)
trajectories.append(trajectory)

for trajectory in trajectories:
x, y, z = trajectory.T  # transpose and unpack
# x, y, z = zip(*trajectory)  # this also works!
ax.plot(x, y, z)

plt.show()


I wrote this before I knew of PIL. Apparently you can use PIL to generate your GIFs instead of using an external program like I did.

See

and have fun!

An example of a GIF with stars in it from the first blogpost (Nyan Cat): Hi I did manage to write the code. Here is what I did

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
import pandas as pd

x=np.array(df1['x'])*3.24078e-17
y=np.array(df1['y'])*3.24078e-17
z=np.array(df1['z'])*3.24078e-17

data=[]
for i in range(len(x)):
blank=[]
for j in range(len(x[i])):
dummy=[]
dummy.append(x[i][j])
dummy.append(y[i][j])
dummy.append(z[i][j])
blank.append((dummy))

data.append(np.array(blank))

def animate_scatters(iteration, data, scatters):
for i in range(data.shape):
scatters[i]._offsets3d = (data[iteration][i,0:1], data[iteration][i,1:2], data[iteration][i,2:])
return scatters

def main(data, save=False):
fig = plt.figure()
ax = p3.Axes3D(fig)

# Initialize scatters
scatters = [ ax.scatter(data[i,0:1], data[i,1:2], data[i,2:]) for i in range(data.shape) ]

# Number of iterations
iterations = len(data)

# Setting the axes properties
ax.set_xlim3d([-10, 10])
ax.set_xlabel('X')

ax.set_ylim3d([-10, 10])
ax.set_ylabel('Y')

ax.set_zlim3d([-10, 10])
ax.set_zlabel('Z')

ax.set_title('Nuclear Star Cluster')

# Provide starting angle for the view.
ax.view_init(25, 10)

ani = animation.FuncAnimation(fig, animate_scatters, iterations, fargs=(data, scatters),
interval=50, blit=False, repeat=True)

if save:
Writer = animation.writers['ffmpeg']
writer = Writer(fps=30, metadata=dict(artist='Me'), bitrate=1800, extra_args=['-vcodec', 'libx264'])
ani.save('3d-scattered-animated.mp4', writer=writer)

plt.show()

#print data
main(data, save=True)


Now my problem is my data shape is changing with time, the number of particles is getting reduced. How do I incorporate that in the code?

• Is this an answer? Shouldn't this be part of the question? Then edit your question accordingly. May 1 '20 at 9:04
• @planetmaker Good point. However, this is looking more like a coding question now, and it may be better to ask it on Stack Overflow, where there are plenty of Python users who know matplotlib. OTOH, asking on SO can be a nerve-wracking experience, we're a bit gentler here on Astronomy. ;) May 1 '20 at 10:24
• Okay well I think this is the end of the road for Astronomy SE for your question, since this is no longer even a little bit about Astronomy. You have some experience with Stack Overflow, they need fairly specific questions, and there is also Code Review SE and they require running code that only needs improvement. We should't post follow up questions in answer posts.
– uhoh
May 1 '20 at 10:24
• @PM2Ring ya that's why I posted at least something here to at least get them started.
– uhoh
May 1 '20 at 10:25
• @ArpanDas when your data gets big you will have much better results if you follow that advice. "There's nothing wrong" will turn into "My script takes forever to run" to which the answer will be "You're definitely doing it wrong." Learn to let numpy do the work for you because numpy executes fast compiled code whereas nested python loops are far slower. Stacking and moving the order of axes of arrays have simple numpy syntax, and when you are done you can consider using .copy() to make a new instance of your reordered array (if you have enough memory) if caching/paging slows you down.
– uhoh
May 1 '20 at 23:58