Python parabolic shooting animation with matplotlib - python

I have the problem that circle is not an iterable, how do I solve it? I'd like the parabolic shot to work with the circle.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from IPython.display import HTML
plt.style.use('dark_background')
ax = plt.axes(xlim=(-5, 25), ylim=(-5, 25))
patch = plt.Circle((1, -1), 0.5, fc='b') #figura
X = 30
Y = 30
gravity=9.81
angle=70
velocity=80
vx=velocity * np.cos(np.radians(angle))
vy=velocity * np.sin(np.radians(angle))
t=0
def setup():
patch.center = (10, 10)
ax.add_patch(patch)
return patch
def throwBall():
global X, Y, gravity, t,vx,vy
t +=0.02
X = vx*t
Y = 400 -(vy*t - (gravity/2)*t*t)
patch.center = (X, Y)
return patch
animen = animation.FuncAnimation(fig, throwBall,init_func=setup,frames=360,interval=15,blit=True)
HTML(animen.to_html5_video())

Pretty much what #JohanC said. According to the documentation, if blit=True "func must return an iterable of all artists that were modified or created." Therefore, you must return a list or a tuple of Artists, even if there only one artist modified.
I've also made some cosmetic changes. If you are incrementing t in your update function, why not pass directly the value of t as an argument to your update function using frames = np.arange(0,7.2,0.02) or something equivalent.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.patches import Circle
fig = plt.figure()
ax = fig.add_subplot(111, xlim=(0, 500), ylim=(0, 500), aspect='equal')
patch = Circle((1, -1), 10, fc='b')
ax.add_patch(patch)
X = 30
Y = 30
gravity=9.81
angle=70
velocity=80
vx=velocity * np.cos(np.radians(angle))
vy=velocity * np.sin(np.radians(angle))
def setup():
patch.set_center((X, Y))
return (patch,)
def throwBall(t):
global X, Y
X = vx*t
Y = 400 -(vy*t - (gravity/2)*t*t)
patch.set_center((X, Y))
return (patch)
ani = animation.FuncAnimation(fig, throwBall, init_func=setup, frames=np.arange(0,7.2,0.02), interval=20, blit=True)

Related

How to move a patch along a path?

I am trying to animate a patch.Rectangle object using matplotlib. I want the said object to move along a path.Arc.
A roundabout way to do this would be (approximately) :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(0, 10), ylim=(0, 10))
# generate the patch
patch = mpat.Rectangle((5, 5), 1, 4)
patch.rotation_point = 'center'
# generate the path to follow
path_to_follow = mpat.Arc((5, 5), 2, 2)
ax.add_patch(path_to_follow)
def init():
patch.set(x=5, y=5)
ax.add_patch(patch)
return patch,
def animate(i, ax):
new_x = 5 + np.sin(np.radians(i)) - 0.5 # parametric form for the circle
new_y = 5 + np.cos(np.radians(i)) - 2
patch.set(x=new_x, y=new_y, angle=90-i)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=10,
blit=True)
plt.show()
The rectangle follows a circle, but a parametric one. Would it be possible to make it follow any path?
In other words, I would like to know if there are other simpler methods to do this (make my patch follow my path, here a circle), and if that could be generalized to other path.
Thanks in advance !
I searched into the matplotlib doc for a methods which gives the parametric form for a given path (but apparently there is not), or for a methods which directly move a patch along a path (obviously, there was not).
Here is one way to use matplotlib.path.Path to generate a path, whose vertices can be obtained using the method cleaned, to move a patch along it.
I have tried to showcase how blue and red colored Rectangles can be moved along a (blue) linear path and a (red) circular path, respectively:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation, path
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(0, 10), ylim=(0, 10))
# generate a linear path
path1 = np.column_stack((np.arange(500)/50, np.arange(500)/50))
# generate a circular path
circle = path.Path.circle(center=(5, 5), radius=1)
path2 = circle.cleaned().vertices[:-3]
# create patches
patch1 = mpat.Rectangle((0, 0), 1, 3)
patch2 = mpat.Rectangle((0, 0), 1, 3, color='red', fill=None)
# plot path vertices
plt.scatter(x=path1[:, 0], y=path1[:, 1], s=2)
plt.scatter(x=path2[:, 0], y=path2[:, 1], color='red', s=2)
def init():
patch1.set(x=0, y=0)
patch2.set(x=5, y=6)
ax.add_patch(patch1)
ax.add_patch(patch2)
return [patch1, patch2]
def animate(i, ax):
j = i % 500 # path1 has shape (500, 2)
k = (i % 16) # path2 has shape (16, 2)
patch1.set(x=path1[j][0], y=path1[j][1], angle=-j)
patch2.set(x=path2[k][0], y=path2[k][1], angle=-k)
return [patch1, patch2]
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=100,
blit=True)
plt.show()
If your path is some collection of coordinates, you can not only translate the rectangle, but also compute the vector from one point to the next and update the rectangle angle accordingly. In the next example (mix of your code with mine), we generate from the beginning the path, but it could be instead live read from some external source.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
# create some path with pairs of X and Y coordinates
t = np.linspace(0, 360, 361)
X = 5. * np.sin(np.radians(t))
Y = t * (t-360*2) / 8000 + 7.5
# create x and y lists to store the position pairs as they are plotted
x = [X[0],]
y = [Y[0],]
# plotting
fig, ax = plt.subplots()
ax.set(xlim=(-10, 10), ylim=(-10, 10))
patch = mpat.Rectangle((x[0], y[0]), 1, 3)
def init():
patch.set(x=x[0], y=y[0])
ax.plot(X, Y)
ax.add_patch(patch)
return patch,
def animate(i, ax):
new_x = X[i] # we are getting from pre-generated data,
new_y = Y[i] # but it could be some function, or even live external source
vx = new_x - x[-1] # calculate the vectors, which are used for angle
vy = new_y - y[-1]
x.append(new_x) # store for next iteration, so that we can calculate the vectors
y.append(new_y)
new_alfa = np.degrees(np.arctan2(vy, vx))
patch.set(x=new_x, y=new_y, angle = new_alfa)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=20,
blit=True)
plt.show()
Thanks a lot for your answers, here is the code I made (mixing the two answers) and which does exactly what I wanted, if it helps anyone :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(-6, 6), ylim=(-6, 6))
# generate a circular path
circle = mpat.Arc((0, 0), 10, 10, theta1=20, theta2=220, color='green')
path = circle.get_transform().transform_path(circle.get_path()).cleaned().vertices[:-3] # get_path is not enough because of the transformation, so we apply to the path the same transformation as the circle has got from the identity circle
ax.add_patch(circle)
# create patch
patch = mpat.Rectangle((0, 0), 1, 4, color='red', fill=None)
patch.rotation_point = 'center'
# plot path vertices
plt.scatter(x=path[:, 0], y=path[:, 1], color='red', s=2)
shape = len(path)
def init():
patch.set(x=5-0.5, y=6-2) # we substract to get to the center
ax.add_patch(patch)
return [patch]
def animate(i, ax):
k = i % shape
new_x = path[k][0]
new_y = path[k][1]
vx = new_x - path[k-1][0]
vy = new_y - path[k-1][1]
patch.set(x=new_x-0.5, y=new_y-2, angle=np.degrees(np.arctan2(vy, vx) + 90))
return [patch]
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=200,
blit=True,
repeat=False)
plt.show()
To improve this, is anyone know how to increase the number of points given? In other words, increase the len of path to be more precise in moving the rectangle.
Thanks in advance !

Function animation with plot_surface not drawing , just giving first picture

I have written the following code with function animation with plot_surface which is not drawing, just giving the first picture
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.outer(np.linspace(-2, 2, 50), np.ones(50))
#print(x)
y = x.copy().T # transpose
fig = plt.figure()
ax = plt.axes(projection='3d')
def animation_frame(i):
z = np.cos(x ** 2 + y ** 2) + np.cos(x ** (2*i) + y ** (2*i))
# print (z)
ax.plot_surface(x, y, z,cmap='viridis', edgecolor='none')
# return ax,
animation = FuncAnimation(fig, func=animation_frame, frames=np.arange(0, 10, 1), interval=1000, blit=False)
#plt.show()
animation
You should call the plt.show() method at the end. Moreover, you should erase the previous plot with ax.cla() at the beginning of the animation_frame.
Whole code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.outer(np.linspace(-2, 2, 50), np.ones(50))
y = x.copy().T
fig = plt.figure()
ax = plt.axes(projection = '3d')
def animation_frame(i):
ax.cla()
z = np.cos(x**2 + y**2) + np.cos(x**(2*i) + y**(2*i))
ax.plot_surface(x, y, z, cmap = 'viridis', edgecolor = 'none')
animation = FuncAnimation(fig, func = animation_frame, frames = np.arange(0, 10, 1), interval = 250, blit = False)
plt.show()

I want to animate the trajectory of a ball (really just a circle) using Matplotlib animation

I want to animate the trajectory of a circle (ball) defined by y = -t^2 + 11t - 18. Basically it would just be bouncing up and down (i.e. no change in x). Its intercepts are (2,0) and (9,0) so the animation should start at time t = 2 as it leaves the ground and end at time t = 9 as it returns to the ground. I am also hoping that a running display of the time could also be included in the animation. So basically between times t=0 and t=2, the ball would just be on the ground. This is the code I have so far but it doesn't seem to make sense. I'm not sure whether the animation is just going too fast.
%matplotlib notebook
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(3, 3)
ax = plt.axes(xlim=(0, 10), ylim=(0, 15))
patch = plt.Circle((5, 0), 0.2, fc='r')
def init():
patch.center = (5, 0)
ax.add_patch(patch)
return patch,
def animate(i):
x, y = patch.center
x = 0 * i+5
y = - i**2 + 11 * i - 18
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=3600,
interval=1,
blit=True)
plt.show()

How to draw real-time moving circle in Python matplotlib

I'm trying to make 2D collision simulation in Python.
I made a circle on the figure to use as an object, and I wanted to move it in real-time without the figure window closed.
I found this code:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.cos(x)
fig = plt.figure()
for p in range(50):
p=3
updated_x=x+p
updated_y=np.cos(x)
plt.plot(updated_x,updated_y)
plt.draw()
x=updated_x
y=updated_y
plt.pause(0.2)
fig.clear()
and I tried this:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
board = plt.axes(xlim = (0, 200), ylim = (0, 100))
x = 10
y = 10
r = 10
for p in range(10):
circle = plt.Circle((x, y), body.r, fc='w', ec='b')
board.add_patch(circle)
plt.annotate("", xytext=(x, y), xy=(x+10, y+10), arrowprops=dict(facecolor='r', edgecolor='r', headwidth=6, headlength=6, width=0.1))
plt.draw()
plt.pause(0.2)
fig.clear()
x += 10
y += 10
I wanted to draw only the present circle and delete the previous one.
But it didn't worked, and I can't understand why fig.clear() in the first code didn't really clear it.
Please help me...
Your problem was with fig.clear(). If you just remove the circle and the annotation from the plot you get an animation.
from matplotlib import pyplot as plt, animation as an
import numpy as np
fig = plt.figure()
board = plt.axes(xlim=(0, 200), ylim=(0, 100))
x = 10
y = 10
r = 10
for p in range(10):
circle = plt.Circle((x, y), r, fc='w', ec='b')
board.add_patch(circle)
annotation = plt.annotate("", xytext=(x, y), xy=(x+10, y+10), arrowprops=dict(facecolor='r', edgecolor='r', headwidth=6, headlength=6, width=0.1))
plt.draw()
plt.pause(0.2)
circle.remove()
annotation.remove()
x += 10
y += 10
plt.show()

Animating Donuts in Matplotlib

I am doing a small animation for a teaching course in which I need to draw a donut that moves around following a trajectory. However, I am having a problem with funcAnimation insofar as I don't manage to use blit to refresh the position. Here is my code with an example dataset
import numpy as np
x1 = np.random.randint(1,101,10)
y1 = np.random.randint(1,101,10)
The animation itself is done by
%matplotlib inline
import numpy as np
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
fig, ax = plt.subplots()
def make_circle(r,x_c,y_c):
t = np.arange(0, np.pi * 2.0, 0.01)
t = t.reshape((len(t), 1))
x = r * np.cos(t) + x_c
y = r * np.sin(t) + y_c
return np.hstack((x, y))
def draw_donut(r_o,r_i,x_c,y_c):
Path = mpath.Path
inside_vertices = make_circle(r_i,x_c,y_c)
outside_vertices = make_circle(r_o,x_c,y_c)
codes = np.ones(len(inside_vertices), dtype=mpath.Path.code_type) * mpath.Path.LINETO
codes[0] = mpath.Path.MOVETO
vertices = np.concatenate((outside_vertices[::1],inside_vertices[::-1]))
all_codes = np.concatenate((codes, codes))
path = mpath.Path(vertices, all_codes)
patch = mpatches.PathPatch(path, facecolor='#885500', edgecolor='black')
return patch
def animate(i):
return ax.add_patch(draw_donut(10,5,x1[i],y1[i]))
anim = animation.FuncAnimation(fig, animate, frames = 10, interval=100, blit = False)
ax.set_xlim(-100, 100)
ax.set_ylim(-100, 100)
ax.set_aspect(1.0)
HTML(anim.to_jshtml())
If I set blit = True I get the error
TypeError: 'PathPatch' object is not iterable
blit = False just keep plotting more donuts. Any idea how to solve this?

Categories