【问题标题】:matplotlib animation plotting all the points instead of just the latest iterationmatplotlib 动画绘制所有点,而不仅仅是最新的迭代
【发布时间】:2017-11-26 17:40:35
【问题描述】:

我正在尝试使用 matplotlib 为在 2D 空间中移动的一组点设置动画。它目前有点工作,因为它的代码确实产生了点的动画,但这不是我认为它会工作的方式。它不是在每个时间点绘制点,而是在所有时间点绘制它们。

例如,如果代码以 20 个点运行,我希望它在一帧显示 20 个点,然后在下一帧显示相同的点,依此类推。相反,它会保留以前的帧点,而不是只显示新的帧点。

谁能告诉我哪里出错了?

此外,我从研究中发现,最好为动画启用 blitting 以优化问题,但是当我添加 blit=True 作为 FuncAnimation 的参数时,控制台会吐出一个巨大的回溯,结尾为:

文件“C:\Users\Anaconda3\lib\site-packages\matplotlib\animation.py”,第 1568 行,在 _draw_frame a.set_animated(self._blit)

AttributeError: 'numpy.ndarray' 对象没有属性 'set_animated'

我也不知道为什么会发生这种情况,并且在线搜索没有帮助。

代码如下:

import matplotlib.pyplot as plt #Import plotting library
from matplotlib import animation
import numpy as np #Import numpy library

dim = 2             #Defines the dimensionality of the system
n = 25               #Number of BOIDS
tmax = 80             #Length of sim
dmax = 5            #Distance boids can "see", determines what other boids interact with them
o = np.zeros(dim) #Origin as vector
r = np.random.rand(n,dim) #Places BOIDs randomly with co-ordinates (x,y,z) from 0 to 1. Has dimensions n and dim
v = 2*np.random.rand(n,dim)-1#Sets initial velocity of each BOID from -1 to 1 in each cardinal direction
rt = np.zeros((tmax,n,dim)) #This array contains the whole system's positions at each point in time
x = np.empty(n)
y = np.empty(n)
d = np.zeros(n)
vk = np.zeros((n,2))
vksum = np.zeros((n,2))
pltx = np.zeros((tmax,n))
plty = np.zeros((tmax,n))
"""rt[a][b][0] is the x co-ordinate of boid n=b at t=a
   rt[a][b][1] is the y co-ordiante of boid n=b at t=a
   np.linalg.norm gives the modulus of an array, check documentation for arguments"""

fig, ax = plt.subplots(figsize=(14,9))
ax.grid(True,linestyle='-',color='0.75') #Sets up a grid on subplot
ax.set_xlim(-50,50)
ax.set_ylim(-50,50) #Set limits for x and y axes 

for t in range (0,tmax):
    for i in range (0,n):
        for k in range (0,n):
            if abs(k-n)>0:
                d[k] = ((r[i][0]-r[k][0])**2+(r[i][1]-r[k][1])**2)**(1/2) #Checks distance from ith boid to each other boid
            if (d[k]-dmax)<0:   #If they are within range of the ith boid
                vk[k] = (v[i] +v[k])/((np.linalg.norm(v[i]))*np.linalg.norm(v[k]))#Aligns the velocity of ith boid toward the velocity of the kth boid
        for l in range (0,n):
            vksum[i] = vksum[i] + vk[l] #Sums the boid's velocity contributions together
        v[i] = (3/4)*v[i] + (vksum[i]/np.linalg.norm(vksum[i])) #Sets the boid's new velocity 
        r[i] = r[i] + v[i]  #Sets the boid's new position
        rt[t][i] = r[i] #Logs the position of the boid in the time array
        pltx[t][i] = r[i][0]
        plty[t][i] = r[i][1]


def init():
    for i in range (0,n):
        x[i] = rt[0][i][0]
        y[i] = rt[0][i][1]
    return x,y,  

def update(j):
    for i in range (0,n):
        x[i] = rt[j][i][0]
        y[i] = rt[j][i][1]
    points = ax.scatter(x[:],y[:],c='r')
    return x,y

anim = animation.FuncAnimation(fig, update, frames=tmax, interval=50,blit=True)

【问题讨论】:

  • 也许在update 你应该清除情节以删除以前的点。

标签: python numpy animation matplotlib


【解决方案1】:

我知道furas' answers 可以解决您的问题,但这里有更多关于您的问题的解释。

首先,blitting。如果你想使用 blitting,你的 update() 函数 needs to return a list of updated artists。您正在返回两个 numpy 数组,但您应该 return points,

关于绘制先前时间点的保持点的第二个问题是由于您在每次迭代中重复调用ax.scatter()。与正常的 matplotlib 行为类似,如果您在同一轴上执行两次 scatter() 调用,您最终会得到两组点。

动画的一般建议是在初始化阶段创建一个艺术家(无论是使用plot()Line2D 对象还是PathCollectionscatter() 的情况下),然后更新 更新函数中此艺术家的属性(颜色、位置等),而不创建新的艺术家。

考虑到所有这些,您的代码最终:

dim = 2             #Defines the dimensionality of the system
n = 25               #Number of BOIDS
tmax = 80             #Length of sim
dmax = 5            #Distance boids can "see", determines what other boids interact with them
o = np.zeros(dim) #Origin as vector
r = np.random.rand(n,dim) #Places BOIDs randomly with co-ordinates (x,y,z) from 0 to 1. Has dimensions n and dim
v = 2*np.random.rand(n,dim)-1#Sets initial velocity of each BOID from -1 to 1 in each cardinal direction
rt = np.zeros((tmax,n,dim)) #This array contains the whole system's positions at each point in time
x = np.empty(n)
y = np.empty(n)
d = np.zeros(n)
vk = np.zeros((n,2))
vksum = np.zeros((n,2))
pltx = np.zeros((tmax,n))
plty = np.zeros((tmax,n))
"""rt[a][b][0] is the x co-ordinate of boid n=b at t=a
   rt[a][b][1] is the y co-ordiante of boid n=b at t=a
   np.linalg.norm gives the modulus of an array, check documentation for arguments"""

fig, ax = plt.subplots(figsize=(14,9))
ax.grid(True,linestyle='-',color='0.75') #Sets up a grid on subplot
ax.set_xlim(-50,50)
ax.set_ylim(-50,50) #Set limits for x and y axes

# initialize an empty PathCollection artist, to be updated at each iteration
points = ax.scatter([],[],c='r')    

for t in range (0,tmax):
    for i in range (0,n):
        for k in range (0,n):
            if abs(k-n)>0:
                d[k] = ((r[i][0]-r[k][0])**2+(r[i][1]-r[k][1])**2)**(1/2) #Checks distance from ith boid to each other boid
            if (d[k]-dmax)<0:   #If they are within range of the ith boid
                vk[k] = (v[i] +v[k])/((np.linalg.norm(v[i]))*np.linalg.norm(v[k]))#Aligns the velocity of ith boid toward the velocity of the kth boid
        for l in range (0,n):
            vksum[i] = vksum[i] + vk[l] #Sums the boid's velocity contributions together
        v[i] = (3/4)*v[i] + (vksum[i]/np.linalg.norm(vksum[i])) #Sets the boid's new velocity 
        r[i] = r[i] + v[i]  #Sets the boid's new position
        rt[t][i] = r[i] #Logs the position of the boid in the time array
        pltx[t][i] = r[i][0]
        plty[t][i] = r[i][1]


def init():
    for i in range (0,n):
        x[i] = rt[0][i][0]
        y[i] = rt[0][i][1]
    return x,y,  

def update(j):
    for i in range (0,n):
        x[i] = rt[j][i][0]
        y[i] = rt[j][i][1]
    xy = np.hstack((x,y))
    points.set_offsets(xy) # update the coordinates of the PathCollection members
    return points, # return the updated artist(s) for blitting

anim = animation.FuncAnimation(fig, update, frames=tmax, interval=50,blit=True)

【讨论】:

    【解决方案2】:

    使用ax.clear() 删除之前的点(当您使用blit=False 时)

    def update(j):
    
        ax.clear()
    
        for i in range (0,n):
            x[i] = rt[j][i][0]
            y[i] = rt[j][i][1]
        points = ax.scatter(x[:], y[:], c='r')
    
        return x,y
    

    【讨论】:

    • 非常感谢,解决了这个问题。你知道为什么我不能在动画中使用 blitting 吗?
    • 我不知道。我只有一个适用于 blit=Trueblit=False 的示例,但我不知道它为什么有效 - animation sinus
    猜你喜欢
    • 2021-12-21
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多