2012-05-16 2 views
4

Я пытаюсь сделать анимацию оптимизации роя частиц, используя Python и Mayavi2.Как взаимодействовать с окном майави во время анимации частиц? (во время оптимизации роицы частиц)

Анимация работает нормально, моя проблема в том, что невозможно взаимодействовать с сюжетом, пока оно оживляет движение. В частности, я хотел бы повернуть график и увеличить масштаб. Может быть, у кого-то есть опыт анимации?

Способ, которым я занимаюсь, заключается в том, чтобы сначала вычислить положения частиц, а затем сохранить их. По завершении расчета я выстраиваю позиции частицы в первый момент времени с помощью точки 3d(), а затем i итерации через время, обновляя данные с помощью метода set().

Есть ли способ сделать это возможным! Я слышал о чем-то с потоками, отрицая рендеринг, но я не мог понять, как это сделать в моем коде. Кроме того, много других вещей, я прочитал:

http://code.enthought.com/projects/mayavi//docs/development/html/mayavi/mlab_animating.html

http://code.enthought.com/projects/mayavi//docs/development/html/mayavi/tips.html#acceleration-mayavi-scripts

, но он не может видеть, как использовать его.

Любые предложения?

Вот мой код:

#!/usr/bin/env python 
''' 
    @author rt 
''' 
import pylab as plt 
from numpy import * 
from mayavi import mlab 
from threading import Thread # making plotting faster? 
import ackley as ac 

class Swarm(Thread, object): 
    ''' 
     constructor for the swarm 
     initializes all instance variables 
    ''' 
    def __init__(self,objective_function): 
     Thread.__init__(self) 
     # optimization options 
     self.omega = 0.9 # inertial constant 
     self.c1 = 0.06 # cognitive/private constant 
     self.c2 = 0.06 # social constant 
     self.objective = objective_function # function object 

     self.max_iteration = 100 # maximal number of iterations 
     # Swarm stuff 
     self.number = 0 
     self.best = [] # gbest; the global best position 
     self.particles = [] # empty list for particles 
     # temporary 
     self.min = self.objective.min 
     self.max = self.objective.max 
     self.best_evolution = [] 
     # self.dimensions = 2 # dimensions NB! 


    ''' 
     add particles to the swarm 
     find the best position of particle in swarm to set global best 
    ''' 
    def add_particles(self, n): 
     for i in range(n): 
      particle = Particle(self) 
      if i == 0: # initialize self.best 
       self.best = particle.position 
      if particle.eval() < self._eval(): # check if there is a better and if, set it 
       self.best = copy(particle.position) 
      self.particles.append(particle) # append the particle to the swarm  

    def _eval(self): 
     return self.objective.evaluate(self.best) 

    def plot(self): 
     for i in range(self.max_iteration): 
      pos_x = [] 
      pos_y = [] 
      pos_z = [] 
      #print pos_x 
      for particle in self.particles: 
       [x,y,z] = particle.trail[i] 
       pos_x.append(x) 
       pos_y.append(y) 
       pos_z.append(z) 
      #print pos_x 
      if i ==0: 
       g = mlab.points3d(pos_x, pos_y,pos_z, scale_factor=0.5) 
       ms =g.mlab_source 
       ms.anti_aliasing_frames = 0 
      ms.set(x=pos_x, y = pos_y, z = pos_z,scale_factor=0.5)  #updating y value 
      #print pos_y 
      #ms.set(x=pos_x) # update x values 
      #ms.set(y=pos_y)  #updating y value 
      #ms.set(z=pos_z)  #updating y value 

     #for p in self.particles: 
      #p.plot() 
    def plot_objective(self): 
     delta = 0.1 
     v = mgrid[self.min:self.max:delta,self.min:self.max:delta] 
     z = self.objective.evaluate(v) 
     #mlab.mesh(v[0],v[1],z) 
     mlab.surf(v[0],v[1],z) # surf creates a more efficient data structure than mesh 
     mlab.xlabel('x-axis', object=None) 
     mlab.ylabel('y-axis', object=None) 
     mlab.zlabel('z-axis', object=None) 


    def _info(self): 
     self.plot() 
     print '----------------------------' 
     print 'The best result is:' 
     print 'Coordinates:', self.best 
     print 'Value: ', self._eval() 
     #print 'with ', nreval, 'evaluations' 
     print 'nr of particles: ', len(self.particles) 
     print '----------------------------' 

    def run(self): 
     self.plot_objective() 
     self.best = self.particles[0].get_position() 
     iteration = 0 
     while iteration < self.max_iteration: 
      #if iteration!= 0: obj.scene.disable_render = True 
      #disable_render = True 
      for particle in self.particles: 
       rnd_c1 = array([random.uniform(0,1),random.uniform(0,1)]) 
       rnd_c2 = array([random.uniform(0,1),random.uniform(0,1)]) 
       particle.velocity = self.omega * array(particle.velocity) + \ 
            self.c1 * rnd_c1 * (array(particle.best) - array(particle.position)) + \ 
            self.c2 * rnd_c2 * (array(self.best) - array(particle.position)) # TODO: change so independent rnd for components 
       particle.position = array(particle.position) + particle.velocity 
       if particle.eval() < particle.best_eval(): 
        particle.best = copy(particle.position) 
        if particle.eval() < self._eval(): 
         self.best = copy(particle.position) 
       particle.update() # add the point to the trail 
      iteration +=1 
      self.best_evolution.append(self._eval()) 
      #obj.scene.disable_render = False 
     print 'finished: ', iteration 
     self._info() 

''' 
    Class modeling particle 
''' 
class Particle(): 
    def __init__(self, swarm): 
     self.swarm = swarm 
     x_rand = random.uniform(self.swarm.min,self.swarm.max) 
     y_rand = random.uniform(self.swarm.min,self.swarm.max) 
     self.position = array([x_rand,y_rand]) 
     v_x_rand = random.uniform(self.swarm.min,self.swarm.max) 
     v_y_rand = random.uniform(self.swarm.min,self.swarm.max) 
     self.velocity = array([v_x_rand, v_y_rand]) 
     self.size = 0.5 
     self.best = self.position 
     # visualization 
     self.trail = [] 

    def plot(self): 
     [x,y] = self.position 
     z = self.eval() 
     mlab.points3d(x,y,z,scale_factor=self.size) 
    def eval(self): 
     return self.swarm.objective.evaluate(self.position) 
    def best_eval(self): 
     return self.swarm.objective.evaluate(self.best) 
    def get_position(self): 
     return self.position 
    def update(self): 
     [x,y] = self.position 
     z = self.eval() 
     #print [x,y,z] 
     self.trail.append([x,y,z]) 
    def plot_trail(self,index): 
     [x,y,z] = self.trail[index] 
     mlab.points3d(x,y,z,scale_factor=self.size) 

# Make the animation 
mlab.figure(1, bgcolor=(0, 0, 0), size=(1300, 700)) # create a new figure with black background and size 1300x700 

objective = ac.Ackley() # make an objective function 

swarm = pso.Swarm(objective) # create a swarm 
nr_of_particles = 25 # nr of particles in swarm 

swarm.add_particles(nr_of_particles)  
swarm.run() 
#swarm.start() 
mlab.show() 

print '------------------------------------------------------' 
print 'Particle Swarm Optimization' 
#objective.info() 
print 'Objective function to minimize has dimension = ', objective.get_dimension() 
print '# of iterations = ', 1000 
print '# of particles in swarm = ', nr_of_particles 
print '------------------------------------------------------' 

ответ

0

Ваша проблема заключается в том, что цикл wx события, которое запускает окно MayaVi GUI и прослушивает щелчок мышей и перетаскивание и реагирует путем перемещения сцены, не получает в любое время для запуска во время анимации, потому что вы сохраняете Python в своем цикле, не позволяя ему управлять return.

Вместо того, чтобы контролировать программу с помощью собственной петли, вам необходимо создать класс wx.Timer, который продвигает сцену с помощью одного обновления кадра, а затем возвращает управление в цикл событий wx после того, как он снова запланирован. Это будет выглядеть примерно так:

import wx 

... 

class Animator(wx.Timer): 

    def Notify(self): 
     """When a wx.Timer goes off, it calls its Notify() method.""" 

     if (...the animation is complete...): 
      return 

     # Otherwise, update all necessary data to advance one step 
     # in the animation; you might need to keep a counter or 
     # other state as an instance variable on `self` 

     # [DATA UPDATE GOES HERE] 

     # Schedule ourselves again, giving the wx event loop time to 
     # process any pending mouse motion. 

     self.Start(0, oneShot=True) # "in zero milliseconds, call me again!" 

я играл с несколько более высокими значениями, как 1 для числа миллисекунд, wx получает запустить пользовательский интерфейс с, но не мог сказать, разница между этим и просто выбирая 0 и получив контроль «немедленно».

1

В моем случае, хотя я был в состоянии сделать то, что предложил Брэндон Роудс для макетной программы (https://stackoverflow.com/questions/16617814/interacting-with-mlab-scene-while-it-is-being-drawn), мне не удалось преобразовать мою уже существующую большую программу.

Тогда я нашел эту ссылку: http://wiki.wxpython.org/LongRunningTasks

Итак, я просто посыпаю много wx.Yield() с внутри моих петель. Таким образом мне не нужно было менять свою структуру программы, и я могу взаимодействовать с окном. Я думаю, что лучшие способы объясняются в ссылке.

 Смежные вопросы

  • Нет связанных вопросов^_^