2016-11-30 150 views
0

我的程序在每个时间步骤中绘制了我的文件中粒子的位置。不幸的是,尽管我使用了matplotlib.animation,但它变得越来越慢。瓶颈在哪里?对于两个粒子Python:动画3D散点图变慢

我的数据文件,如下所示:

#  x y z 
# t1 1 2 4 
#  4 1 3 
# t2 4 0 4 
#  3 2 9 
# t3 ... 

我的脚本:

import numpy as np       
import matplotlib.pyplot as plt    
from mpl_toolkits.mplot3d import Axes3D 
import mpl_toolkits.mplot3d.axes3d as p3 
import matplotlib.animation as animation 

# Number of particles 
numP = 2 
# Dimensions 
DIM = 3 
timesteps = 2000 

with open('//home//data.dat', 'r') as fp: 
    particleData = [] 
    for line in fp: 
     line = line.split() 
     particleData.append(line) 

x = [float(item[0]) for item in particleData] 
y = [float(item[1]) for item in particleData] 
z = [float(item[2]) for item in particleData]  

# Attaching 3D axis to the figure 
fig = plt.figure() 
ax = p3.Axes3D(fig) 

# Setting the axes properties 
border = 1 
ax.set_xlim3d([-border, border]) 
ax.set_ylim3d([-border, border]) 
ax.set_zlim3d([-border, border]) 


def animate(i): 
    global x, y, z, numP 
    #ax.clear() 
    ax.set_xlim3d([-border, border]) 
    ax.set_ylim3d([-border, border]) 
    ax.set_zlim3d([-border, border]) 
    idx0 = i*numP 
    idx1 = numP*(i+1) 
    ax.scatter(x[idx0:idx1],y[idx0:idx1],z[idx0:idx1]) 

ani = animation.FuncAnimation(fig, animate, frames=timesteps, interval=1, blit=False, repeat=False) 
plt.show() 

回答

2

我建议在这种情况下使用pyqtgraph。从文档引文:

它的主要目标是:1)为 显示数据(图表,视频等)和2)提供工具 快速应用开发,以帮助提供快速,交互式图形(用于例如,在Qt Designer中使用的属性树,如 )。

您可以在安装后检查出一些例子:

import pyqtgraph.examples 
pyqtgraph.examples.run() 

这一小段代码生成1000个随机点,并通过不断更新的不透明它们显示在3D散点图,类似于三维散在pyqtgraph.examples情节例如:

from pyqtgraph.Qt import QtCore, QtGui 
import pyqtgraph.opengl as gl 
import numpy as np 

app = QtGui.QApplication([]) 
w = gl.GLViewWidget() 
w.show() 
g = gl.GLGridItem() 
w.addItem(g) 

#generate random points from -10 to 10, z-axis positive 
pos = np.random.randint(-10,10,size=(1000,3)) 
pos[:,2] = np.abs(pos[:,2]) 

sp2 = gl.GLScatterPlotItem(pos=pos) 
w.addItem(sp2) 

#generate a color opacity gradient 
color = np.zeros((pos.shape[0],4), dtype=np.float32) 
color[:,0] = 1 
color[:,1] = 0 
color[:,2] = 0.5 
color[0:100,3] = np.arange(0,100)/100. 

def update(): 
    ## update volume colors 
    global color 
    color = np.roll(color,1, axis=0) 
    sp2.setData(color=color) 

t = QtCore.QTimer() 
t.timeout.connect(update) 
t.start(50) 


## Start Qt event loop unless running in interactive mode. 
if __name__ == '__main__': 
    import sys 
    if (sys.flags.interactive != 1) or not hasattr(QtCore, PYQT_VERSION'): 
     QtGui.QApplication.instance().exec_() 

小GIF给你性能的想法:

enter image description here

编辑:

在每一个时间步长显示多点是有点棘手只是(N,3)-arrays作为点位置,因为gl.GLScatterPlotItem需要,请参阅here。你可以尝试制作一个ScatterPlotItems的字典,其中每个字典包含特定点的所有时间步骤。然后需要相应地调整更新功能。您可以在下面找到一个示例,其中pos(100,10,3)-array,代表每个点的100个时间步长。我将更新时间缩短到1000 ms以获得较慢的动画。

from pyqtgraph.Qt import QtCore, QtGui 
import pyqtgraph.opengl as gl 
import numpy as np 

app = QtGui.QApplication([]) 
w = gl.GLViewWidget() 
w.show() 
g = gl.GLGridItem() 
w.addItem(g) 

pos = np.random.randint(-10,10,size=(100,10,3)) 
pos[:,:,2] = np.abs(pos[:,:,2]) 

ScatterPlotItems = {} 
for point in np.arange(10): 
    ScatterPlotItems[point] = gl.GLScatterPlotItem(pos=pos[:,point,:]) 
    w.addItem(ScatterPlotItems[point]) 

color = np.zeros((pos.shape[0],10,4), dtype=np.float32) 
color[:,:,0] = 1 
color[:,:,1] = 0 
color[:,:,2] = 0.5 
color[0:5,:,3] = np.tile(np.arange(1,6)/5., (10,1)).T 

def update(): 
    ## update volume colors 
    global color 
    for point in np.arange(10): 
     ScatterPlotItems[point].setData(color=color[:,point,:]) 
    color = np.roll(color,1, axis=0) 

t = QtCore.QTimer() 
t.timeout.connect(update) 
t.start(1000) 


## Start Qt event loop unless running in interactive mode. 
if __name__ == '__main__': 
    import sys 
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): 
    QtGui.QApplication.instance().exec_() 

请记住,在这个例子中,在散点图显示所有点,但颜色不透明度(颜色阵列中的第四维)在每个时间步长更新以获得动画。你也可以尝试更新点,而不是颜色,以获得更好的性能...

+0

如果我的列表“pos”包含100个时步的10个点的位置,我将如何进行。我会在哪里将它集成到你的代码中?对于每个时间步,我需要像'plot(pos [timestep0:timestep1])'。如果你能给我一个提示就太好了! – Samuel

+0

我在更新中包含了一个示例 –

1

我想你的瓶颈是在动画的每个帧中调用ax.scatterax.set_xlim3d和类似。

理想情况下,你应该打个电话给scatter一次,然后使用由散射和在animate功能(more details here)其set_...属性返回的对象。

我不知道如何用scatter做到这一点,但如果您使用ax.plot(x, y, z, 'o')来代替,那么您可以按照演示方法here

使用一些随机数据x, y, z。它会这样工作

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
import mpl_toolkits.mplot3d.axes3d as p3 
import matplotlib.animation as animation 
from numpy.random import random 

# Number of particles 
numP = 2 
# Dimensions 
DIM = 3 
timesteps = 2000 

x, y, z = random(timesteps), random(timesteps), random(timesteps) 

# Attaching 3D axis to the figure 
fig = plt.figure() 
ax = p3.Axes3D(fig) 

# Setting the axes properties 
border = 1 
ax.set_xlim3d([-border, border]) 
ax.set_ylim3d([-border, border]) 
ax.set_zlim3d([-border, border]) 
line = ax.plot(x[:1], y[:1], z[:1], 'o')[0] 


def animate(i): 
    global x, y, z, numP 
    idx1 = numP*(i+1) 
    # join x and y into single 2 x N array 
    xy_data = np.c_[x[:idx1], y[:idx1]].T 
    line.set_data(xy_data) 
    line.set_3d_properties(z[:idx1]) 

ani = animation.FuncAnimation(fig, animate, frames=timesteps, interval=1, blit=False, repeat=False) 
plt.show()