I want to make 3D animation with matplotlib, but I don't know how to. Here is my non-working code.
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
from math import *
fig = plt.figure()
ax = fig.add_subplot(111) #, projection='3d'
#setting
ax.set_xlim(-5,5)
ax.set_ylim(-5,5)
#ax.set_zlim(-5,5)
ax.set_xlabel('x')
ax.set_ylabel('y')
#ax.set_zlabel('z')
ax.grid()
f1, = ax.plot([], [], "r-", lw=1) #plot1
def gen():
for phi in np.linspace(0,2*pi,100):
yield np.cos(phi), np.sin(phi), phi
def update(data):
p1, q1, psi = data
f1.set_data(p1,q1)
#f1.set_3d_properties(psi)
ani = animation.FuncAnimation(fig, update, gen, blit=False, interval=100, repeat=True)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()
I used this example http://matplotlib.org/1.4.1/examples/animation/simple_3danim.html
and modified your code:
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
def gen(n):
phi = 0
while phi < 2*np.pi:
yield np.array([np.cos(phi), np.sin(phi), phi])
phi += 2*np.pi/n
def update(num, data, line):
line.set_data(data[:2, :num])
line.set_3d_properties(data[2, :num])
N = 100
data = np.array(list(gen(N))).T
line, = ax.plot(data[0, 0:1], data[1, 0:1], data[2, 0:1])
# Setting the axes properties
ax.set_xlim3d([-1.0, 1.0])
ax.set_xlabel('X')
ax.set_ylim3d([-1.0, 1.0])
ax.set_ylabel('Y')
ax.set_zlim3d([0.0, 10.0])
ax.set_zlabel('Z')
ani = animation.FuncAnimation(fig, update, N, fargs=(data, line), interval=10000/N, blit=False)
#ani.save('matplot003.gif', writer='imagemagick')
plt.show()
Here is the following code for a sphere moving to the right and off the screen.
You will have to run this code in a folder for tidiness, as it generates 26 .png images (and a .gif image):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from numpy import sin, cos, pi, outer, ones, size, linspace
# Define x, y, z lists for sphere
a = linspace(0, 2 * pi)
b = linspace(0, pi)
x = 10 * outer(cos(a), sin(b))
y = 10 * outer(sin(a), sin(b))
z = 10 * outer(ones(size(a)), cos(b))
# The amount of frames in the animation
frames = 26
# Generate each frame
for n in range(frames):
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, color=('b'))
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
ax.set_xlim(-8,8)
plt.savefig(f"{n}.png")
plt.close()
# Add 1 to the x so the sphere moves right by 1
x += 1
# Use pillow to save all frames as an animation in a gif file
from PIL import Image
images = [Image.open(f"{n}.png") for n in range(frames)]
images[0].save('ball.gif', save_all=True, append_images=images[1:], duration=100, loop=0)
Output:
Related
I have some points and I plot the surface of them using the code below:
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:20j, 0.0:2.0*pi:20j]
radis=np.random.normal(1,0.2,(20,20))
x = radis*sin(phi)*cos(theta)
y = radis*sin(phi)*sin(theta)
z = radis*cos(phi)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
x, y, z, rstride=1, cstride=1, color='c', alpha=0.3, linewidth=0)
ax.scatter3D(x,y,z, c='r')
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
# ax.set_aspect("equal")
plt.tight_layout()
plt.show()
Then I get the 3d plot result:
The thing I want to do is that get the image of any plane, like z=0.
Is there any method or library can cover this problem?
I'm trying to animate a curve in 3D and am having some trouble. I've successfully animated some things in 2D, so I thought I knew what I was doing. In the code below, I generate x, y, and z values parametrically to be a helix and have verified that I can plot the full curve in 3D. To animate the curve I am trying to begin by plotting only the first two data points and then use FuncAnimation to update the data so that it plots larger portions of the data. But as I said, it is not working for some reason and I have no idea why; all I get is the initial plot with the first two data points. Any help would be appreciated.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
t_max = 10
steps = 100
t = np.linspace(0, t_max, steps)
x = np.cos(t)
y = np.sin(t)
z = 0.1*t
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
line, = ax.plot(x[0:1], y[0:1], z[0:1])
def update(i):
line.set_xdata(x[0:i])
line.set_ydata(y[0:i])
line.set_zdata(z[0:i])
fig.canvas.draw()
ani = animation.FuncAnimation(fig, update, frames=t, interval=25, blit=False)
plt.show()
Okay, I finally got it to work. I had a dumb error (frames=t), but also figured out that you need to set the data in the update function differently. Here is the working code in case anyone is interested.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
t_max = 10
steps = 100
t = np.linspace(0, t_max, steps)
x = np.cos(t)
y = np.sin(t)
z = 0.1*t
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
line, = ax.plot([], [], [], lw=1)
ax.set_xlim(-1,1)
ax.set_ylim(-1,1)
ax.set_zlim(0,1)
plt.show()
def update(i):
line.set_data(x[0:i], y[0:i])
line.set_3d_properties(z[0:i])
return
ani = animation.FuncAnimation(fig, update, frames=100, interval=10, blit=True)
plt.show()
I have code for "live" plotting with Matplotlib in Python, but it closes once it's done. I would like the plot to remain open.
Code below
import time
import matplotlib.pyplot as plt
plt.ion()
plt.show()
for i in range(10):
time.sleep(1)
x = i ** 2
plt.scatter(i, x)
plt.draw()
Maybe you want something like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def make_data():
for i in range(100):
yield i, i*2
fig, ax = plt.subplots()
color = plt.cm.cubehelix(np.linspace(0.1,0.9,100))
plot, = ax.plot([], [],'o')
xdata, ydata = [], []
ax.set_ylim(0, 1)
ax.set_xlim(0, 1)
def run(data):
x,y = data
xdata.append(x)
ydata.append(y)
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
if y > ymax:
ax.set_xlim(xmin, 1+xmax)
ax.set_ylim(ymin, 1+ymax)
ax.figure.canvas.draw()
plot.set_color(color[x])
plot.set_data(xdata,ydata)
return plot,
ani = animation.FuncAnimation(fig,run,make_data,blit=True,interval=10,repeat=False)
plt.show()
Maybe scatter would be better since it might allow for different colors of each circle.
I have 3xN array positions that vary in time for a particle. I want to take the coordinates at each time point, plot that position as a point on a 3D axis and then repeat, creating an animation.
I can create a single image of this effect using matplotlib's Axes3D
x_a = particle_a[:,0]
y_a = particle_a[:,1]
z_a = particle_a[:,2]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x_a, y_a, z_a, c='b')
plt.show
'particle_a' is just an array of shape (N,3) where N is the number of timepoints.
How can I animate this?
Adapting this example from the matplotlib site you can represent a particle moving in 3D with:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
def make_helix(n):
theta_max = 8 * np.pi
theta = np.linspace(0, theta_max, n)
x, y, z = theta, np.sin(theta), np.cos(theta)
helix = np.vstack((x, y, z))
return helix
def update_lines(num, dataLines, lines) :
for line, data in zip(lines, dataLines) :
line.set_data(data[0:2, num-1:num])
line.set_3d_properties(data[2,num-1:num])
return lines
# Attach 3D axis to the figure
fig = plt.figure()
ax = p3.Axes3D(fig)
n = 100
data = [make_helix(n)]
lines = [ax.plot(data[0][0,0:1], data[0][1,0:1], data[0][2,0:1], 'o')[0]]
# Setthe axes properties
ax.set_xlim3d([0.0, 8*np.pi])
ax.set_xlabel('X')
ax.set_ylim3d([-1.0, 1.0])
ax.set_ylabel('Y')
ax.set_zlim3d([-1.0, 1.0])
ax.set_zlabel('Z')
ax.set_title('3D Test')
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, n, fargs=(data, lines),
interval=50, blit=False)
plt.show()
(replace helix with your own data and set the axes limits accordingly).
I would like to visualize the magnitude of VM with respect to time t. In the following program, t is set to zero. I would appreciate it if one could tell me how to produce an animation of the bilinear interpolation contour plot. Thank you!
Please here is the code:
import numpy as np
from numpy import cos, sin, pi, exp, sqrt
from matplotlib import pyplot as plt
import matplotlib.cm as cm
nx=30
ny=30
nu=0.0025
p=2*pi
x = np.linspace(0,p,nx)
y = np.linspace(0,p,ny)
fig,ax = plt.subplots(1,1)
ax.set_xlim(0,p)
ax.set_ylim(0,p)
t=0
X,Y = np.meshgrid(x,y)
U=-cos(X)*sin(Y)*exp(-2*nu*t)
V=sin(X)*cos(Y)*exp(-2*nu*t)
VM=sqrt(U**2+V**2)
im = plt.imshow(VM, interpolation='bilinear', origin='lower',
cmap=cm.gray, extent=(0, p, 0, p))
levels = np.arange(-1.2, 1.6, 0.2)
# add a vertical colorbar.
CBI = plt.colorbar(im, orientation='vertical', shrink=0.8)
plt.show()
mostly copied from here. See there for in depth explanations.
import numpy as np
from numpy import cos, sin, pi, exp, sqrt
from matplotlib import pyplot as plt
import matplotlib.cm as cm
from matplotlib import animation
nx=30
ny=30
nu=0.0025
p=2*pi
x = np.linspace(0,p,nx)
y = np.linspace(0,p,ny)
fig,ax = plt.subplots(1,1)
ax.set_xlim(0,p)
ax.set_ylim(0,p)
t=0
X,Y = np.meshgrid(x,y)
U=-cos(X)*sin(Y)*exp(-2*nu*t)
V=sin(X)*cos(Y)*exp(-2*nu*t)
VM=sqrt(U**2+V**2)
im = plt.imshow(VM, interpolation='bilinear', origin='lower',
cmap=cm.gray, extent=(0, p, 0, p))
levels = np.arange(-1.2, 1.6, 0.2)
# add a vertical colorbar.
CBI = plt.colorbar(im, orientation='vertical', shrink=0.8)
def init():
im.set_data((np.empty_like(VM)))
return im,
def animate(t):
U=-cos(X)*sin(Y)*exp(-2*nu*t)
V=sin(X)*cos(Y)*exp(-2*nu*t)
VM=sqrt(U**2+V**2)
im.set_data(VM)
return im,
# # call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()