2016-11-30 2 views
0

Моя программа отображает позиции частиц в моем файле для каждого временного шага. К сожалению, он медленнее и медленнее, хотя я использовал matplotlib.animation. Где узкое место?Python: Анимированный 3D Scatterplot замедляется

Мой файл данных для двух частиц выглядит следующим образом:

#  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-диаграммы рассеяния, постоянно обновляя непрозрачность, похожий на 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

EDIT:

Отображение нескольких точек на каждом шаге по времени немного сложнее, так как gl.GLScatterPlotItem занимает только (N,3)-arrays в местах точек, см 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' содержит позиции для 10 точек для 100 временных меток. Где бы я интегрировал это в свой код? Для каждого timestep мне понадобится что-то вроде 'plot (pos [timestep0: timestep1])'. Было бы здорово, если бы вы могли дать мне подсказку! – Samuel

+0

Я включил пример в обновление –

1

Я бы предположил, что ваше узкое место вызывает ax.scatter и ax.set_xlim3d и аналогично в каждом кадре в анимации.

В идеале, вы должны сделать вызов scatter один раз, а затем использовать объект, возвращаемый разбросом и его set_... свойств в animate функции (more details here).

Я не могу понять, как это сделать с помощью 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() 
Смежные вопросы