0

I am facing issues with the implementation of the method animation from the class wave bellow. The animation method aims to create an animation of a wave propagation. I do not want that the animation method modify the state instance variable u of the Wave object, and because of that I am trying to create a local variable u inside the method animation. Nevertheless, I do not know how to pass the local variable u from the animation method for the animate function that is defined inside the animation method. In the way that I tried to implement, from my conception, the local variable u of the method animation should be a king of global variable for the animate method (that is defined inside the animation method). But, this assumption is cleary wrong, otherwise I would not get an error. As a complementary information the error I am getting is: UnboundLocalError: local variable 'u' referenced before assignment. I will be glad if someone indicate to me the way for the implementation that I want.

thanks in advance

class Wave(object):


    def __init__(self, phenomenon):
        '''
        nx: Number of spatial grid points
        dx: Distance between any pair of adjacent grid points
        nt: Number of steps in time
        nu: Diffusion coefficient
        dt: Value of the step in time
        c: wave velocity
        u: grid vector of the wave
        '''

        if phenomenon == 'convection':
            self.phenomenon = phenomenon
            self.nx = 81
            self.dx = 2.0/(self.nx - 1) # Distance between any pair of adjacent grid
            self.nt = 100
            self.dt = 0.002
            self.c = 3

            self.x = numpy.linspace(0,4,self.nx)
            self.u =  numpy.ones(self.nx)
            self.lbound = numpy.where(self.x >= 0.5)
            self.ubound = numpy.where(self.x <= 1.0)
            self.bounds = numpy.intersect1d(self.lbound[0], self.ubound[0])
            self.u[self.bounds] = 2

        if phenomenon == 'diffusion':
            ...

        if phenomenon == 'burgers':
            ...


    def _convection(self, u):
        un = u.copy()
        u[1:] = un[1:] - self.c*self.dt/self.dx*(un[1:] - un[:-1])
        u[0] = 1.0
        return u


    def integration(self):
        if self.phenomenon == 'convection':
            for n in range(1,self.nt):
                self.u = self._convection(u=self.u)

        if self.phenomenon == 'diffusion':
            ...

        if self.phenomenon == 'burgers':
            ...


    def animation(self):
        fig = plt.figure()
        ax = plt.axes(xlim=(0,4), ylim=(0,3))
        ax.grid()

        line, = ax.plot([], [], 'o-', lw=2)
        time_template = 'time = %.2fs'
        time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)

        def init():
            line.set_data([], [])
            time_text.set_text('')
            return line, time_text

        x = self.x
        u = self.u.copy()
        def animate(i):

            if self.phenomenon == 'convection':
                u = self._convection(u=u)

            if self.phenomenon == 'diffusion':
                ...    
            if self.phenomenon == 'burgers':
                ...

            line.set_data(x,u)
            time_text.set_text(time_template % (i*self.dt))
            return line, time_text

        anim = animation.FuncAnimation(fig, animate, frames=500, init_func=init, interval=10, blit=True)
        plt.show()

EDIT

Complete trace error:

Exception in Tkinter callback Traceback (most recent call last): File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in call return self.func(*args) File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 536, in callit func(*args) File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 141, in _on_timer TimerBase._on_timer(self) File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1203, in _on_timer ret = func(*args, **kwargs) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 876, in _step still_going = Animation._step(self, *args) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 735, in _step self._draw_next_frame(framedata, self._blit) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 754, in _draw_next_frame self._draw_frame(framedata) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 1049, in _draw_frame self._drawn_artists = self._func(framedata, *self._args) File "wave.py", line 201, in animate un = u.copy() UnboundLocalError: local variable 'u' referenced before assignment Exception in Tkinter callback Traceback (most recent call last): File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in call return self.func(*args) File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 536, in callit func(*args) File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 141, in _on_timer TimerBase._on_timer(self) File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1203, in _on_timer ret = func(*args, **kwargs) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 876, in _step still_going = Animation._step(self, *args) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 735, in _step self._draw_next_frame(framedata, self._blit) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 754, in _draw_next_frame self._draw_frame(framedata) File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 1049, in _draw_frame self._drawn_artists = self._func(framedata, *self._args) File "wave.py", line 201, in animate un = u.copy() UnboundLocalError: local variable 'u' referenced before assignment

2
  • Can we have the complete stack trace ? Commented Mar 28, 2016 at 19:18
  • Can we have the complete stack trace in a format that's possible to read? Commented Mar 28, 2016 at 20:03

1 Answer 1

2

When you capture a variable with a closure in Python, you are not allowed to assign to it. If Python sees you assign to it, then it isn't allowed to be captured from the enclosing scope; it must be a new function-local variable (local to your animate function). But since you're trying to use the captured u to initialize it, you need that u's value, but in this context Python has decided that u must be local to animate, so it isn't looking at animate's enclosing scope. That's why you're getting that error.

A simple way to get around that in your case is just to define animate as

def animate(i, u=u):
    ...

This explicitly passes a copy of u into animate.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I did not know about this condition when working with capture variables in clsure. Do you know some reading reference about this subject?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.