1

I’m aiming to animate a scatter plot using the df below. I’m trying to pass the plot and groups function to the animate function. I’m trying to return the values from each function are pass them to subsequent functions but I’m getting aNameError as these values aren't being registered.

The script works if I remove the plot and groups functions and pass objects to animate from the global workspace but then I have to write these out all the time. Rather than house in separate functions.

import pandas as pd import matplotlib.pyplot as plt import numpy as np import matplotlib as mpl from matplotlib import animation df1 = pd.DataFrame({ 'Time' : [1,1,1,2,2,2,3,3,3], 'GroupA_X' : [3, 4, 5, 2, 5, 6, 1, 6, 7], 'GroupA_Y' : [2, 4, 5, 2, 5, 5, 2, 6, 5], 'GroupB_X' : [2, 5, 3, 2, 4, 2, 2, 3, 1], 'GroupB_Y' : [2, 4, 3, 3, 3, 4, 4, 2, 5], }) def plot(): fig, ax = plt.subplots() ax.grid(False) xy = 0,0 Oval = mpl.patches.Ellipse(xy, 160, 130, lw = 2, edgecolor = 'black', color = 'blue', alpha = 0.2) ax.add_patch(Oval) return fig, ax def groups(): plot() Group_A = df1[['Time','GroupA_X','GroupA_Y']] Group_B = df1[['Time','GroupB_X','GroupB_Y']] GA_X = np.array(Group_A.groupby(['Time'])['GroupA_X'].apply(list)) GA_Y = np.array(Group_A.groupby(['Time'])['GroupA_Y'].apply(list)) GB_X = np.array(Group_B.groupby(['Time'])['GroupB_X'].apply(list)) GB_Y = np.array(Group_B.groupby(['Time'])['GroupB_Y'].apply(list)) GA = ax.scatter(GA_X[0], GA_Y[0], c = ['blue'], marker = 'o', s = 10, edgecolor = 'black') GB = ax.scatter(GB_X[0], GB_Y[0], c = ['brown'], marker = 'o', s = 10, edgecolor = 'black') return GA, GB def animate(i) : plot() groups() GA.set_offsets(np.c_[GA_X[0+i], GA_Y[0+i]]) GB.set_offsets(np.c_[GB_X[0+i], GB_Y[0+i]]) plot() groups() ani = animation.FuncAnimation(fig, animate, np.arange(0,3), interval = 1000, blit = False) 

Error Output:

GA = ax.scatter(GA_X[0], GA_Y[0], c = ['blue'], marker = 'o', s = 10, edgecolor = 'black') NameError: name 'ax' is not defined 
4
  • The functions return values. You should pass those values as arguments to the function. Commented Mar 12, 2020 at 0:02
  • Please provide the entire error message. Isn’t the issue that you’re throwing away the values returned by the functions? Commented Mar 12, 2020 at 1:29
  • Yep, thats the issue. Commented Mar 12, 2020 at 1:36
  • I've updated the question to reflect this Commented Mar 12, 2020 at 4:28

2 Answers 2

1
+50

animation draws/repeats on the global figure, so you need to create subplots in global scope. If you define subplots inside plot function, every call of plot will create a new subplots

import pandas as pd import matplotlib.pyplot as plt import numpy as np import matplotlib as mpl from matplotlib import animation df1 = pd.DataFrame({ 'Time' : [1,1,1,2,2,2,3,3,3], 'GroupA_X' : [3, 4, 5, 2, 5, 16, 21, 36, 47], 'GroupA_Y' : [2, 4, 5, 2, 5, 15, 22, 36, 45], 'GroupB_X' : [2, 5, 3, 2, 4, 12, 22, 33, 41], 'GroupB_Y' : [2, 4, 3, 3, 3, 14, 24, 32, 45], }) fig, ax = plt.subplots() def plot(): # fig, ax = plt.subplots() #declared in global scope ax.grid(False) xy = 0,0 Oval = mpl.patches.Ellipse(xy, 160, 130, lw = 2, edgecolor = 'black', color = 'blue', alpha = 0.2) ax.add_patch(Oval) # return fig, ax #no need return since `fig, ax` are in global scope def groups(): # plot() #no need since this function use nothing from `plot` Group_A = df1[['Time','GroupA_X','GroupA_Y']] Group_B = df1[['Time','GroupB_X','GroupB_Y']] GA_X = np.array(Group_A.groupby(['Time'])['GroupA_X'].apply(list)) GA_Y = np.array(Group_A.groupby(['Time'])['GroupA_Y'].apply(list)) GB_X = np.array(Group_B.groupby(['Time'])['GroupB_X'].apply(list)) GB_Y = np.array(Group_B.groupby(['Time'])['GroupB_Y'].apply(list)) GA = ax.scatter(GA_X[0], GA_Y[0], c = ['blue'], marker = 'o', s = 10, edgecolor = 'black') GB = ax.scatter(GB_X[0], GB_Y[0], c = ['brown'], marker = 'o', s = 10, edgecolor = 'black') return GA, GB, GA_X, GA_Y, GB_X, GB_Y def animate(i) : # plot() GA, GB, GA_X, GA_Y, GB_X, GB_Y = groups() GA.set_offsets(np.c_[GA_X[0+i], GA_Y[0+i]]) GB.set_offsets(np.c_[GB_X[0+i], GB_Y[0+i]]) plot() # groups() ani = animation.FuncAnimation(fig, animate, np.arange(0,3), interval = 1000, blit = False) 

Note: I changed values in df1 to make the values changing between each animation clearer. Codes fixing above works. I tested it. However, I don't know whether it is efficient. I basically just fix your codes to make it run.

You said animation runs fine if you declare everything in global scope. Therefore, I assume your system already had ffmpeg installed and you codes is able to call/find ffmpeg.exe to display the repreating/looping animation

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

Comments

0

Have you tried modifying the function to pass the returned ax to a variable inside groups function as below:

def groups(): _,ax = plot() 

As the error states the name ax is not defined in groups function. It has to be defined by capturing the value returned from plot()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.