1

I am attempting to animate a scatter plot in Python 3.6 (in Spyder IDE), for which there are several tutorials/examples (a, b, c, and many others), however my update function is somehow receiving a very different set of coordinates from what I think I'm providing.

The following is a reduced example code wherein 4 points proceed toward the center. I plot it twice, first as a line, second as an animation. The line plot looks right, but the animation shows very different behavior, both in terms of the locations of the points and their trajectories. I infer that I'm incorrectly supplying coordinate information to the update function, but I cannot seem to determine why/how.

I can supply figures showing what does vs. should happen, though I'll simply supply this sample code for now for brevity's sake.

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.animation as anim

npt=4
ntime=101
solx=np.zeros((npt,ntime))
soly=np.zeros((npt,ntime))
solx[0,0:]=np.linspace(0,40,ntime)
solx[1,0:]=solx[0,0:];
solx[2,0:]=100-solx[0,0:];
solx[3,0:]=solx[2,0:]
soly[0,0:]=np.linspace(0,80,ntime)
soly[1,0:]=200-soly[0,0:]
soly[2,0:]=soly[0,0:]
soly[3,0:]=soly[1,0:]


#%% Plots
colord=mpl.cm.gist_ncar(np.linspace(0,0.9,npt))
of2,oa2=plt.subplots(1)
for cnt in range(0,npt): oa2.plot(solx[cnt,0:],soly[cnt,0:],c=colord[cnt])

of3,oa3=plt.subplots()
osc3=oa3.scatter(solx[0:,0],soly[0:,0],c=colord,marker='+')
def aninit():
    osc3.set_offsets(np.stack((solx[0:,0],soly[0:,0]),axis=0))
    return osc3,
def aniupdate(i):
    osc3.set_offsets(np.stack((solx[0:,i],soly[0:,i]),axis=0))
    return osc3,

ani=anim.FuncAnimation(of3,aniupdate,init_func=aninit,frames=range(0,ntime),interval=100,blit=True,repeat=True,repeat_delay=1000)
plt.show()
TTT
  • 1,175
  • 2
  • 14
  • 32
  • Hi TTT, it would help if you could supply the code as a MWE (Minimal Working Example). I can't run the code you've supplied as-is to reproduce your error. Also, it might be relevant which version of python you are using (2.7 vs 3.x). – Dominique Fuchs Nov 09 '17 at 14:37
  • @DominiqueFuchs Sorry, I'd tested it but apparently had not successfully reset my workspace (Spyder is tricky that way). Code fixed (I hope). – TTT Nov 09 '17 at 15:03

1 Answers1

1

If you replace

np.stack((solx[0:,0],soly[0:,0]),axis=0)
np.stack((solx[0:,i],soly[0:,i]),axis=0)

with:

list(zip(solx[0:,0],soly[0:,0]))
list(zip(solx[0:,i],soly[0:,i]))

or (if you want to use numpy arrays instead of lists:

np.array([solx[0:,0],soly[0:,0]]).T
np.array([solx[0:,i],soly[0:,i]]).T

in the aninit() and aniupdate(i) functions the behaviour should be as expected.

Here's the code I used to make the plots:

def aninit():
    offsetlist = np.array([solx[0:,0],soly[0:,0]]).T
    osc3.set_offsets(offsetlist)
    return osc3,

def aniupdate(i):
    offsetlist = np.array([solx[0:,i],soly[0:,i]]).T
    osc3.set_offsets(offsetlist)
    return osc3,
  • Copy-pasting your code gave this error: `return array(a, dtype, copy=False, order=order, subok=True) TypeError: float() argument must be a string or a number, not 'zip'`. You are right to point out a mistake in my code, though. Fixing it doesn't alter the behavior, but I'll fix it in my question. – TTT Nov 10 '17 at 19:37
  • My bad, didn't check the Python version you are using. `zip()` was redefined returning an iterator instead of returning a list. I have changed the solution to work in python 3.6 – Dominique Fuchs Nov 13 '17 at 12:36
  • You are my hero. I tried several different syntactic variants to find something that might work without success. Can you point me to where one finds documentation on the data format that `set_offsets` requests? I might make a separate question for this, since I haven't had any luck figuring it out on my own. – TTT Nov 13 '17 at 14:02
  • 1
    From your code I conluded that the coordinates weren't parsed correctly (since the point was moving, but along the wrong coordinates). Zipping the coordinate lists was a lucky guess, to combine the (x,y) coordinates into tuples (instead of subarrays). Then I looked into the 'rain' examples: https://matplotlib.org/examples/animation/rain.html which shows an implementation using numpy arrays to manage coordinates & attributes (quite elegantly IMHO). That got me on the right track to do the same with the np.arrays. You're right in that the documentation is lacking in this regard. – Dominique Fuchs Nov 13 '17 at 14:10
  • So I suppose the two ways (that I found to work) in which to input coordinates are: "list of tuples (x,y)", or "array shaped `m` x `2`, where `m` is the number of coordinates". – Dominique Fuchs Nov 13 '17 at 14:13
  • 1
    I found a tutorial that shows the use of (x,y) tuples as coordinates in the matplotlib documentation: https://matplotlib.org/1.3.1/examples/old_animation/dynamic_collection.html?highlight=set_offsets – Dominique Fuchs Nov 13 '17 at 14:18