I'm coding a function which would animate a random walk in 3D but unfortunately the code isn't working. Where is a plot, no errors occur but nothing happens. I'm using %matplotlib tk.
There is my code:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
def path_generator(steps, step):
path = np.empty((3, steps))
for i in range(1, steps):
x_ran, y_ran, z_ran = np.random.rand(3)
sgnX = (x_ran - 0.5)/abs(x_ran - 0.5)
sgnY = (y_ran - 0.5)/abs(y_ran - 0.5)
sgnZ = (z_ran - 0.5)/abs(z_ran - 0.5)
dis = np.array([step*sgnX, step*sgnY, step*sgnZ])
path[:, i] = path[:, i - 1] + dis
return path
def animate(i):
global particles, trajectories
for trajectory, particle in zip(trajectories, particles):
trajectory.set_data(particle[0:2, :i])
trajectory.set_3d_properties(particle[2, :i])
return trajectories
def random_walk_3D_animated(n, traj = 1):
fig = plt.figure()
ax = p3.Axes3D(fig)
particles = [path_generator(n, 1) for i in range(traj)]
trajectories = [ax.plot(particle[0, 0:1], particle[1, 0:1], particle[2,
0:1])[0] for particle in particles]
ax.set_xlim3d([-100, 100])
ax.set_ylim3d([-100, 100])
ax.set_zlim3d([-100, 100])
animacion = animation.FuncAnimation(fig, animate, 1000, interval=50,
blit=False)
plt.show()
What is strange, the code do work when there is no function random_walk_3D_animated(n, traj = 1) and the values n and traj are given. And sometimes the code doesn't start the random walks from (0,0,0). I wonder why.
The start position will be the content of the emty array. This may be any value so it is not really useful here. Instead initialize path with zeros.
You need to return a reference to the animation. From the animation documentation: "[..] it is critical to keep a reference to the instance object."
Complete example:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
def path_generator(steps, step):
path = np.zeros((3, steps))
for i in range(1, steps):
x_ran, y_ran, z_ran = np.random.rand(3)
sgnX = (x_ran - 0.5)/abs(x_ran - 0.5)
sgnY = (y_ran - 0.5)/abs(y_ran - 0.5)
sgnZ = (z_ran - 0.5)/abs(z_ran - 0.5)
dis = np.array([step*sgnX, step*sgnY, step*sgnZ])
path[:, i] = path[:, i - 1] + dis
return path
def animate(i):
global particles, trajectories
for trajectory, particle in zip(trajectories, particles):
trajectory.set_data(particle[0:2, :i])
trajectory.set_3d_properties(particle[2, :i])
def random_walk_3D_animated(n, traj = 1):
global particles, trajectories
fig = plt.figure()
ax = p3.Axes3D(fig)
particles = [path_generator(n, 1) for i in range(traj)]
trajectories = [ax.plot(particle[0, 0:1], particle[1, 0:1], particle[2,
0:1])[0] for particle in particles]
ax.set_xlim3d([-100, 100])
ax.set_ylim3d([-100, 100])
ax.set_zlim3d([-100, 100])
animacion = animation.FuncAnimation(fig, animate, 1000, interval=50,
blit=False)
return animacion
ani = random_walk_3D_animated(100, traj = 1)
plt.show()
Related
I have the following code which creates a graph animation. The graph should start from 0, but the 1st interval graph isn't coming.
Below is the code:
import matplotlib.pylab as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots()
left = -1
right = 2*np.pi - 1
def animate(i):
global left, right
left = left + 1
right = right + 1
x = np.linspace(left, right, 50)
y = np.cos(x)
ax.cla()
ax.set_xlim(left, right)
ax.plot(x, y, lw=2)
ani = animation.FuncAnimation(fig, animate, interval = 1000)
plt.show()
For the 1st interval [0, 2π] the graph isn't coming.
What's the mistake?
I changed a little bit your code:
first of all I plot the first frame outside the animate function and I generate a line object from it
then I update the line data within animate function
I suggest to use i counter (which starts from 0 and increases by 1 in each frame) to update your data, in place of calling global variables and change them
Complete Code
import matplotlib.pylab as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots()
left = 0
right = 2*np.pi
x = np.linspace(left, right, 50)
y = np.cos(x)
line, = ax.plot(x, y)
ax.set_xlim(left, right)
def animate(i):
x = np.linspace(left + i, right + i, 50)
y = np.cos(x)
line.set_data(x, y)
ax.set_xlim(left + i, right + i)
return line,
ani = animation.FuncAnimation(fig = fig, func = animate, interval = 1000)
plt.show()
basically I am trying to have a sine wave be displayed by matplotlib and then when a certain x value is reached (block_start_pos) for the animation speed to change (slow down in this case). I understand that FuncAnimation repeatedly calls update_plot based on the given parameters but I was wondering if there was a way to change the interval mid animation. My code (mostly taken from a youtube video) is shown below. Thanks!
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import tkinter as tk
x = np.arange(0, 10*np.pi, 0.01)
index_of_refraction = 10
index_of_refraction_lst = [1, 200, 3, 4, 5]
medium = 20*index_of_refraction
w = 1
y = np.cos(w*x)
fig = plt.figure()
ax = plt.subplot(1, 1, 1)
data_skip = 50
block_start_pos = 6*np.pi
def init_func():
ax.clear()
plt.xlabel('pi')
plt.ylabel('sin(pi)')
plt.xlim((x[0], x[-1]))
plt.ylim((-1, 1))
def update_plot(i):
ax.plot(x[i:i+data_skip], y[i:i+data_skip], color='k')
ax.scatter(x[i], y[i], marker='o', color='r')
return medium_test(i)
def medium_test(i):
if x[i] > block_start_pos:
index_of_refraction = index_of_refraction_lst[1]
medium = 20*index_of_refraction
medium = 20*index_of_refraction
anim = FuncAnimation(fig,
update_plot,
frames=np.arange(0, len(x), data_skip),
init_func=init_func,
interval=medium)
plt.show()
# anim.save('sine.mp4', dpi=150, fps = 30, writer='ffmpeg')```
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?
The problem I am simulating is a simple pendulum. While I have done it before using PyGame I now decided to use matplotlib's animation tools. It is working but not with the desired effect. Simulating it in real time seems to be working. I have tweeked the interval and amount of frames but the fps is way too low. How do you increase the fps while still playing it in real time. I would greatly appreciate it. Anyway here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
g = 9.80665
L = 2
mu = 0.1
t = 100
theta_0 = np.pi/3
d_theta_0 = 0
def get_d2_theta(theta,d_theta):
return -mu*d_theta-(g/L)*np.sin(theta)
def theta(t):
theta = theta_0
d_theta = d_theta_0
delta_t = 1./60
for time in np.arange(0,t,delta_t):
d2_theta = get_d2_theta(theta,d_theta)
theta += d_theta*delta_t
d_theta += d2_theta*delta_t
return theta
x_data = [0,0]
y_data = [0,0]
fig, ax = plt.subplots()
ax.set_xlim(-2, 2)
ax.set_ylim(-2.5,1)
line, = ax.plot(0, 0)
def animation_frame(i):
x = L*np.sin(theta(i))
y = -L*np.cos(theta(i))
x_data[1] = x
y_data[1] = y
line.set_xdata(x_data)
line.set_ydata(y_data)
return line,
animation = FuncAnimation(fig, func=animation_frame, frames=np.arange(0, 60, (1./60)),interval = 10)
plt.show()
I am new to coding and have been trying to create an animation in python from a previously generated code in Octave (below). So far I have not had any success, besides plotting an unanimated scatter plot. Any tips or help would be greatly appreciated.
clear;
N = 100;
NT = 200;
for i=1:N
x(i) = 0;
y(i) = 0;
end
plot(x,y,'o');
axis([0 20 -10 10]);
for k = 1 : NT
x = x + normrnd(0.1,0.1,1,N);
y = y + normrnd(0,0.1,1,N);
temp = mod(k,1);
if temp == 0
plot(x,y,'s');
axis([0 20 -10 10]);
drawnow
end
end
Here is one of the many attempts that did not work (below).
import numpy as np
import matplotlib as plt
from pylab import *
from matplotlib import animation
import random
n=100
nt=2000
m=20
mu=0
sigma=0.1
p=100
fig = plt.figure()
ax = plt.axes(xlim=(-10, 10), ylim=(-10, 10))
scat, = ax.plot([], [])
# initialization function: plot the background of each frame
def init():
x = 0
y = 0
return scat,
# animation function. This is called sequentially
def animate(i):
for k in range (1,nt):
x = x+ np.random.normal(mu, sigma, n)
return scat,
for i in range (1,nt):
y = y+ np.random.normal(mu, sigma, n)
return scat,
anim = animation.FuncAnimation(fig, animate,
init_func=init,frames=200, interval=20, blit=True)
plt.show()
you could do the animation using Octave of Python.
For the python script I think that one of the problems was to set a return within a loop, therefore several times for one function def animate. Looking at the animation doc https://matplotlib.org/api/animation_api.html I edited your example and got this which I think might be usefull:
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
from matplotlib.animation import FuncAnimation
import random
n=100
sigma=0.1
nt=2000
fig, ax = plt.subplots()
xdata, ydata = [0.0], [0.0]
ln, = plt.plot([], [], 'ro', animated=True)
def init():
ax.set_xlim( 0, 20)
ax.set_ylim(-10, 10)
return ln,
def update(frame):
global xdata
global ydata
xdata = xdata + np.random.normal(0.1, sigma, n)
ydata = ydata + np.random.normal(0.0, sigma, n)
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()
You could also do the animation using octaves print command to generate several pngs and use gimp to produce a gif or embbed in LaTeX the pngs using animate.
Best,
Jorge