4

我正在尝试使用 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 '------------------------------------------------------'
4

2 回答 2

1

就我而言,即使我能够做到 Brandon Rhodes 建议的模拟程序(https://stackoverflow.com/questions/16617814/interacting-with-mlab-scene-while-it-is-being-drawn ),我无法转换我已经存在的较大程序。

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

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

于 2013-06-01T21:18:28.740 回答
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!"

我使用了稍高的值,例如运行 UI1的毫秒数wx,但无法真正区分这与仅选择0并“立即”返回控件之间的区别。

于 2013-01-05T07:35:21.253 回答