2016-11-30 155 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()