【问题标题】:how to move particles如何移动粒子
【发布时间】:2021-01-31 20:45:58
【问题描述】:

我正在使用qt-designer 使用 python 进行大流行模拟。我需要做的第一件事是制作移动粒子。我用FuncAnim 让它们移动,但没有用。

这是我的作品:

import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
import random

population = 100

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     

    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

    def animate(self):
        for pi in pop:
            pi.move()
            d, = self._static_ax.plot([particle.x for particle in pop],
                                      [particle.y for particle in pop], 'go')
            d.set_data([particle.x for particle in pop],
                       [particle.y for particle in pop])

    anim = animation.FuncAnimation(plt.gcf(), animate, frames=200, interval=450, repeat=True)


pop = [particle() for i in range(population)]

【问题讨论】:

  • 首先:你有错误的缩进,anim = ... 不在方法内。您无法获得正常代码并输入Class而不进行更改。
  • 什么是“没用”?你收到错误信息吗?始终将完整的错误消息(从“Traceback”一词开始)作为文本(不是屏幕截图)(不是commen)。还有其他有用的信息。
  • 我听不懂你的课——你为什么要把animateanim = ...放在课堂上?这样每个粒子都会有自己的animateanim = ... ,但应该只有一个animate 和一个anim = ... - 而且它们不应该是particle 的一部分

标签: python simulation


【解决方案1】:

Animateanim = ... 不应属于 Particle 类。

你混合了两种动画方法

  • plot() 需要在新绘图之前清除/移除粒子
  • set_data() 在新绘图之前不需要清除/移除粒子

我保留第二种方法,因为它更简单。

但第二种方法不会更新 x,y 限制,我需要 ax 手动设置限制。

animate 中你应该在所有移动之后plot()set_data(),而不是在for-loop 中。

最后我需要plt.show() 才能看到它。


工作代码:

我将vxvy 更改为更小 - 所以粒子不会从一种尺寸跳到另一种尺寸,而是移动得更平滑。我将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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    相关资源
    最近更新 更多