Animate 和 anim = ... 不应属于 Particle 类。
你混合了两种动画方法
-
plot() 需要在新绘图之前清除/移除粒子
-
set_data() 在新绘图之前不需要清除/移除粒子
我保留第二种方法,因为它更简单。
但第二种方法不会更新 x,y 限制,我需要 ax 手动设置限制。
在animate 中你应该在所有移动之后plot() 或set_data(),而不是在for-loop 中。
最后我需要plt.show() 才能看到它。
工作代码:
我将vx、vy 更改为更小 - 所以粒子不会从一种尺寸跳到另一种尺寸,而是移动得更平滑。我将interval 更改为更小以使其更快。
import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import random
# --- classes --- # PEP8: `UpperCaseName`
class Particle:
def __init__(self):
self.x = 5 * np.random.random_sample()
self.y = 5 * np.random.random_sample()
#self.vx = 5 * np.random.random_sample() - 0.5 / 5
#self.vy = 5 * np.random.random_sample() - 0.5 / 5
self.vx = np.random.random_sample() / 5
self.vy = np.random.random_sample() / 5
def move(self):
if self.x < 0 or self.x >= 5:
self.vx *= -1
if self.y < 0 or self.y >= 5:
self.vy *= -1
self.x += self.vx
self.y += self.vy
# --- functions ---
def animate(frame_number):
print('frame_number:', frame_number)
# move all particles
for pi in pop:
pi.move()
# after `for`-loop
# update data without ploting (`FunAnimation` will plot it for us)
d.set_data([particle.x for particle in pop], [particle.y for particle in pop])
# it would have to return `data` only when we use `blit=True` in `FuncAnimation`
#return d,
# --- main ---
population = 100
pop = [Particle() for i in range(population)]
fig = plt.gcf()
ax = plt.axes(xlim=(0, 5), ylim=(0, 5))
# draw first plot
d, = plt.plot([particle.x for particle in pop], [particle.y for particle in pop], 'go')
anim = animation.FuncAnimation(fig, animate, frames=200, interval=45, repeat=True)#, blit=True)
plt.show()
anim.save('particles.gif', fps=25)
#anim.save('particles.gif', writer='ffmpeg', fps=25)
#anim.save('particles.gif', writer='imagemagick', fps=25)
编辑:
使用plot() 而不是set_data() 的版本。
它会自动更改限制,因此它显示的区域比0..5 大一点,因为有时particles 会离开这个区域。
import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import random
# --- classes ---
class Particle:
def __init__(self):
self.x = 5 * np.random.random_sample()
self.y = 5 * np.random.random_sample()
#self.vx = 5 * np.random.random_sample() - 0.5 / 5
#self.vy = 5 * np.random.random_sample() - 0.5 / 5
self.vx = np.random.random_sample() / 5
self.vy = np.random.random_sample() / 5
def move(self):
if self.x < 0 or self.x >= 5:
self.vx *= -1
if self.y < 0 or self.y >= 5:
self.vy *= -1
self.x += self.vx
self.y += self.vy
# --- functions ---
def animate(frame_number):
global d # need it to remove old plot
print('frame_number:', frame_number)
# move all particles
for pi in pop:
pi.move()
# after for-loop
# remove old plot
#d.set_data([], [])
d.remove()
# create new plot
d, = plt.plot([particle.x for particle in pop], [particle.y for particle in pop], 'go')
# --- main ---
population = 100
pop = [Particle() for i in range(population)]
fig = plt.gcf()
# draw first plot
d, = plt.plot([particle.x for particle in pop], [particle.y for particle in pop], 'go')
anim = animation.FuncAnimation(fig, animate, frames=200, interval=45, repeat=True)
plt.show()
anim.save('particles.gif', fps=25)
#anim.save('particles.gif', writer='ffmpeg', fps=25)
#anim.save('particles.gif', writer='imagemagick', fps=25)