如何在动画粒子时与mayavi窗互?(在粒子群优化期间)



我正在尝试使用Python和Mayavi2制作粒子群优化的动画。

动画

工作正常,我的问题是在动画运动时无法与情节交互。具体来说,我想转动图形并缩放。也许有人有做动画的经验?

我的做法是首先计算粒子的位置,然后存储它们。计算完成后,我使用 point3d(( 绘制粒子在第一个时间的位置,然后使用 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 '------------------------------------------------------'

就我而言,即使我在某种程度上能够按照布兰登·罗德斯(Brandon Rhodes(对模拟程序(https://stackoverflow.com/questions/16617814/interacting-with-mlab-scene-while-it-is-being-drawn(的建议进行操作,我也无法设法转换我已经存在的更大的程序。

然后我找到了这个链接:http://wiki.wxpython.org/LongRunningTasks

所以,我只是在我的循环中撒了很多wx.Yield()。这样,我就不需要更改程序结构,并且能够与窗口进行交互。我认为链接中解释了更好的方法。

您的问题是运行Mayavi GUI窗口并侦听鼠标单击和拖动并通过移动场景进行响应的wx事件循环在动画期间没有任何时间运行,因为您将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运行 UI 的毫秒数,但无法真正区分它与仅选择0并"立即"返回控制权之间的区别。

最新更新