0

I'm trying to process data within the matplotlib.FuncAnimation function. Anyhow, the data is iterable and I'm struggling to get the animation function in python to iterate over an external variable. In this case the Ball_1 variable.

The error this throws back is the following: 'UnboundLocalError: local variable 'ball_1' referenced before assignment'

I hindsight this isn't the best way to do it. However I would like to know if it is possible?

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
ax.set_xlim(0,100)
ax.set_ylim(0,100)

#         acc,vel,disp (x,y)
ball_1 = [[0,0,40],[0,0,100]]

ball_1_plot, = ax.plot(ball_1[0][2],ball_1[1][2], "o")

# 
def init_DEM():
    ball_1 = [[0,0,40],[0,0,100]]
    return ball_1_plot,

def DEM(step):
    
    TS = step/10
    
    # Ball_1
    # Contact
    grav = -9.81
    
    # Acceleration

    acc_x = 0   
    acc_y = grav  
    
    # Velocity
    vel_x = ball_1[0][1] + acc_x*TS  
    vel_y = ball_1[1][1] + acc_y*TS  
    
    # Position
    pos_x = vel_x * TS + 0.5 * acc_x * TS * TS  + ball_1[0][2]
    pos_y = vel_y * TS + 0.5 * acc_y * TS * TS  + ball_1[1][2]
    
    print(pos_x)
    # Update 
    
    ball_1 = [[acc_x,vel_x,pos_x],[acc_y,vel_y,pos_y]]
    
    # Update animation
    ball_1_plot.set_xdata(ball_1[0][2])
    ball_1_plot.set_xdata(ball_1[1][2])

    return ball_1_plot,
    
animation_run = FuncAnimation(fig,func=DEM, frames=[10,20], init_func=init_DEM, interval=10)
plt.show()

1 Answer 1

1

You can use functools.partial or a lambda function. Let's say you change your code so ball_1 and ball_1_plt are not global anymore, but arguments to DEM. Then you call it like this:

from functools import partial
animation_run = FuncAnimation(
    fig,
    func=partial(DEM, ball_1=ball_1, ball_1_plot=ball_1_plot),
    frames=[10,20],
    interval=10
)

The references would persist between calls, so it should work, but you can not assign them within DEM. In other words, replace this:

ball_1 = [[acc_x,vel_x,pos_x],[acc_y,vel_y,pos_y]]

by this:

ball_1[0] = [acc_x,vel_x,pos_x]
ball_1[1] = [acc_y,vel_y,pos_y]

Explanation

The reason is the same reason your code is failing right now. When you assign ball_1, a new variable is bound. This variable is local. Your current code would run if you add the statement global ball_1 at the top of the function. However, it is better to not use globals, but pass arguments as you suggest in your question.

This is your code without any globals, moving your top-level code into a function, and passing arguments to DEM:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def DEM(step, ball_1, ball_1_plot):
    TS = step/10

    # Ball_1
    # Contact
    grav = -9.81

    # Acceleration
    acc_x = 0
    acc_y = grav

    # Velocity
    vel_x = ball_1[0][1] + acc_x*TS
    vel_y = ball_1[1][1] + acc_y*TS

    # Position
    pos_x = vel_x * TS + 0.5 * acc_x * TS * TS  + ball_1[0][2]
    pos_y = vel_y * TS + 0.5 * acc_y * TS * TS  + ball_1[1][2]

    # Update
    ball_1[0] = [acc_x,vel_x,pos_x]
    ball_1[1] = [acc_y,vel_y,pos_y]

    # Update animation
    ball_1_plot.set_xdata(ball_1[0][2])
    ball_1_plot.set_xdata(ball_1[1][2])

    return ball_1_plot,

def main():
    from functools import partial

    fig, ax = plt.subplots()
    ax.set_xlim(0,100)
    ax.set_ylim(0,100)

    #         acc,vel,disp (x,y)
    ball_1 = [[0,0,40],[0,0,100]]
    ball_1_plot, = ax.plot(ball_1[0][2],ball_1[1][2], "o")

    animation_run = FuncAnimation(fig,func=partial(DEM, ball_1=ball_1, ball_1_plot=ball_1_plot), frames=[10,20], interval=10)
    plt.show()


if __name__ == '__main__':
    main()
Sign up to request clarification or add additional context in comments.

1 Comment

Excellent response thank you. I did not know about the partial class/function. Feels a bit strange running matlplotlib like a pseudo game engine. Though it definitely works. Much appreciated.

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.