import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
x, y = [], []
line, = plt.plot([], [], 'bo')
circle = plt.Circle((0,0), 1, color = 'g', fill = False,)
def update(frame):
x.append(np.cos(frame))
y.append(np.sin(frame))
line.set_data(x, y)
return circle, line,
ani = FuncAnimation(fig, update, frames= np.linspace(0, 2*np.pi, 128), interval = 0.1)
plt.show()
what I want to animate
I tried to animate uniform circular motion through the code above, but what I can see was only dot moving, not the circle under the dot. How can I plot circle while animating dot?
You can add the circle to the artist with ax.add_artist(circle).
Also, I rewrite the update function so that it only tracks the current dot.
Reference: https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.add_artist.html
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(figsize=(5, 5))
radius = 2
ax.set_xlim(-radius * 1.05, radius * 1.05)
ax.set_ylim(-radius * 1.05, radius * 1.05)
line, = plt.plot([], [], 'bo')
circle = plt.Circle((0, 0), radius, color='k', fill=False)
red_dot = plt.plot(0, 0, 'ro')
ax.set_aspect('equal')
ax.add_artist(circle)
ax.set_axis_off()
def update(i):
theta = np.deg2rad(i)
x = [0, radius * np.cos(theta)]
y = [0, radius * np.sin(theta)]
line.set_data(x, y)
ani = FuncAnimation(fig, update, frames=360, interval=30)
ani.save('fig_1.gif', writer='pillow', fps=45)
plt.show()
Related
I have 35 different radial lines that I am displaying on a polar plot that I would like to animate as their angular dispersion increases. If I just want to animate one line I would do something like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
speed = 5.5
weight=0.5
angle=0
fig = plt.figure(figsize=(12, 12))
ax = plt.subplot(111, projection = 'polar')
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
line, = ax.plot([0, angle], [0, speed],color='blue',linewidth=3,alpha=weight)
def animate(i):
angle=i*(np.pi/180)
new_datax = [0, angle]
lines.set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
And that seems to spin round quite nicely! However if "speed, weight and angles" are arrays not just values how can I animate them all at once without having to do 35 different set_xdata? I know it's not like this!
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
speeds = np.array([5.5,5.5,5.1,5.5,5.6,5.7,5.8,6,6.5,7,7.5,8.5,9.5,11.5,17.5,23,26,29,32,27,22,14.5,9.5,6.3,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10])
weights = np.array([1,0.93,0.90,0.86,0.83,0.83,0.83,0.83,0.82,0.80,0.73,0.77,0.72,0.68,0.68,0.70,0.59,0.71,0.71,0.64,0.73,0.77,0.74,0.680.636977,0.59,0.54,0.53,0.51,0.48,0.46,0.40,0.44,0.38,0.36])
angles=np.linspace(0,0,35)*(np.pi/180)
fig = plt.figure(figsize=(12, 12))
ax = plt.subplot(111, projection = 'polar')
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
for j in range (35):
lines, = ax.plot([0, angles[j]], [0, speeds[j]],color='blue',linewidth=3,alpha=weight3[j])
def animate(i):
angles=np.linspace(0,i,35)*(np.pi/180)
for j in range(35):
new_datax = [0, angles[j]]
lines.set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
But I don't know how else to approach this problem! Any help would be greatly appreciated!
You need to keep track of all the line objects. Right now you're overwriting the lines object every time. Something like this should work:
lines = []
for j in range(35):
line, = ax.plot([0, angles[j]], [0, speeds[j]], color='blue', linewidth=3, alpha=weights[j])
lines.append(line)
def animate(i):
angles = np.linspace(0, i, 35) * (np.pi / 180)
for j in range(35):
new_datax = [0, angles[j]]
lines[j].set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
When I remove linspace and plot points by typing them into a list by hand they are plotted just fine. However switch to linspace, and the points on the graph come up blank. What am I missing here? Printing the linspace lists show they are generating the values, but they don't seem to make the graph
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
%matplotlib qt
fig = plt.figure(figsize=(6,4))
axes = fig.add_subplot(1,1,1)
plt.title("Image That's Moving")
P=np.linspace(1,50,100)
T=np.linspace(1,50,100)
Position =[P]
Time = [T]
p2=[P]
t2=[T]
x,y=[],[]
x2,y2=[],[]
def animate(i):
x.append(Time[i])
y.append((Position[i]))
x2.append(t2[i])
y2.append((p2[i]))
plt.xlim(0,100)
plt.ylim(0,100)
plt.plot(x,y, color="blue")
plt.plot(x2,y2, color="red")
anim = FuncAnimation(fig, animate, interval=300)
It seems like you are facing a problem because of Position = [P] and Time = [T].
Because numpy.linspace already returns an array, you don't need additional [].
Here is a working example that is referenced from matplotlib tutorial.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def init():
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
return ln,
def update(i):
xdata.append(T[i])
ydata.append(P[i])
ln.set_data(xdata, ydata)
return ln,
P = np.linspace(1, 50, 99)
T = np.linspace(1, 50, 99)
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=np.arange(len(T)),
init_func=init, blit=True)
plt.show()
It is not as easy as your written code and, also, not related to np.linspace, AIK. Combining Choi answer (or matplotlib example) with another related SO post we can do this job using some code like:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
def init():
ax1.set_xlim(0, 100)
ax1.set_ylim(0, 100)
ax2.set_xlim(0, 100)
ax2.set_ylim(0, 100)
return ln, ln2
def update(i, Position, Time, P2, T2, ln, ln2):
x.append(Time[i])
y.append(Position[i])
x2.append(T2[i] + 10)
y2.append(P2[i] + 10)
ln.set_data(x, y)
ln2.set_data(x2, y2)
return ln, ln2
Position = P2 = np.linspace(1, 50, 100)
Time = T2 = np.linspace(1, 50, 100)
fig = plt.figure(figsize=(6, 4))
plt.title("Image That's Moving")
plt.xticks([])
plt.yticks([])
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
x, y, x2, y2 = [], [], [], []
ln, = ax1.plot([], [], 'bo')
ln2, = ax2.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=Time.shape[0], fargs=(Position, Time, P2, T2, ln, ln2), init_func=init, blit=True)
ani.save('test.gif', writer='imagemagick', fps=30)
EDIT
I will try to be more precise (above details have been removed because they are unnecessary):
I want to make an animation where a (red) ball departs from (0,0) and draws the function sin(x). The function has to be drawn in blue, and the leading point has to be red (just as seen on the above pic)
I have found a method to draw (animate) a function:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'bo')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
My issue now is how to make the leading point red
I've been told that I should create an empty list of the line elements and use the "append()" method to add new line elements, but I still don't get how to do so.
Reference https://www.physicsforums.com/threads/how-to-make-an-animation-in-sympy-using-python.969906/
Thank you for your help.
Definitely, there are better ways:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
points = 50
x = np.linspace(0, 2 * np.pi, points)
y = np.sin(x)
fig, ax = plt.subplots()
ax.set_xlim(-0.3, 2 * np.pi + 0.3)
ax.set_ylim(-1.2, 1.2)
def animate(i):
if i == 0:
# fig.clear()
ax.plot(x[i], y[i], 'ro')
else:
# fig.clear()
ax.plot(x[i-1], y[i-1], 'bo')
ax.plot(x[i], y[i], 'ro')
anim = FuncAnimation(fig, animate, frames=points, repeat=False, interval=150)
plt.show()
I have written a code that plot some points and lines on the xy plane. It plots everything for a given value of n. So for different n I get my desired plots. But I want to animate these plots for different values of n, say, for n=1, 2, ..., 100. But I cannot do this animation.
Can anyone here help me to do this? Thank you.. I paste my code here:
My Code
import matplotlib as mpl
mpl.rc('text', usetex = True)
mpl.rc('font', family = 'serif')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
fig = plt.subplots()
ax = plt.axes(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))
plt.gca().set_aspect('equal', adjustable='box')
plt.style.use(['ggplot','dark_background'])
plt.rcParams['figure.figsize'] = (12, 8)
n = 10 #I want to animate this n.
p = 2
for k in range(0,n,1):
theta1 = np.pi + 2*k*np.pi / n
theta2 = np.pi + 2*p*k*np.pi / n
x, y = np.cos(theta1), np.sin(theta1)
x1, y1 = np.cos(theta2), np.sin(theta2)
plt.scatter(x, y, s=50, c='violet', zorder=3)
plt.plot([x,x1], [y,y1], color = 'w')
circle = plt.Circle((0, 0), 1, color='c', fill=False, lw = 1)
ax.add_artist(circle)
#Customize the axes and gridlines:
ax.grid(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
#TickMarks Customization:
ax.set_xticks([])
ax.set_yticks([])
#plt.savefig('nthRoots.png', format='png', dpi=1000,bbox_inches='tight')
plt.show()
Output
Is it possible to animate n over different values?
EDIT: Here I donot have only scatter plots ...so I cannot understand how to do this job using those links..!
My Attempt
#Animation.
import matplotlib as mpl
mpl.rc('text', usetex = True) #for LaTex notation in the Plot
mpl.rc('font', family = 'serif')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
from matplotlib import animation, rc
rc('animation', html='html5')
fig = plt.subplots()
ax = plt.axes(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))
plt.gca().set_aspect('equal', adjustable='box')
plt.style.use(['ggplot','dark_background'])
plt.rcParams['figure.figsize'] = (12, 8)
p = 2
#Plotting Function:
def f(n):
for k in range(0,n,1):
theta1 = np.pi + 2*k*np.pi / n
theta2 = np.pi + 2*p*k*np.pi / n
x, y = np.cos(theta1), np.sin(theta1)
x1, y1 = np.cos(theta2), np.sin(theta2)
plt.scatter(x, y, s=50, c='violet', zorder=3)
plt.plot([x,x1], [y,y1], color = 'w')
circle = plt.Circle((0, 0), 1, color='c', fill=False, lw = 1)
ax.add_artist(circle)
#Customize the axes and gridlines:
ax.grid(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
#TickMarks Customization:
ax.set_xticks([])
ax.set_yticks([])
plt.show()
#Now I try to define a function for animating n in f(n)
def animate(n):
f(n)
anim = animation.FuncAnimation(fig, animate,
frames=100, interval=100, blit=True)
#anim.save('Wave.mp4', writer = 'ffmpeg', fps = 2, dpi=500,extra_args=['-vcodec', 'libx264'])
That's all I had... But this idea didn't work...I think I have to properly define animate(n).
Any suggestion...! thanks.
Several problems in your code (most are unrelated to animations)
rcParams need to be defined before creating the figure
plt.subplots returns a tuple of figure and axes.
The animation must return a sequence of artist objects when blitting is used. You might turn it off though
plt.show() should be called once at the end of the script.
Correcting for those you get
import matplotlib as mpl
mpl.rc('font', family = 'serif')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
from matplotlib import animation, rc
plt.rcParams['figure.figsize'] = (12, 8)
plt.style.use(['ggplot','dark_background'])
fig, ax = plt.subplots()
p = 2
#Plotting Function:
def f(n):
ax.clear()
ax.set(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))
ax.set_aspect('equal', adjustable='box')
for k in range(0,n,1):
theta1 = np.pi + 2*k*np.pi / n
theta2 = np.pi + 2*p*k*np.pi / n
x, y = np.cos(theta1), np.sin(theta1)
x1, y1 = np.cos(theta2), np.sin(theta2)
plt.scatter(x, y, s=50, c='violet', zorder=3)
plt.plot([x,x1], [y,y1], color = 'w')
circle = Circle((0, 0), 1, color='c', fill=False, lw = 1)
ax.add_artist(circle)
#Customize the axes and gridlines:
ax.grid(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
#TickMarks Customization:
ax.set_xticks([])
ax.set_yticks([])
anim = animation.FuncAnimation(fig, f, frames=100, interval=100, blit=False)
plt.show()
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: