1

I am trying to code the Vicsek Model and have created arrays containing the x and y coordinates for each point at specific times. I then call the x and y values for each of the time intervals and place them in lists. The data is in the form of two lists, one for x and one for y. I am trying to animate it as follows:

fig = plt.figure()
ax = fig.add_subplot(111)
scat = plt.scatter(x, y, c = x)
scat.set_alpha(0.8)

ax.set_xlim(-L/2, L/2)
ax.set_ylim(-L/2, L/2)

def animate_frames(i, fig, scat):
    a = P[i]
    xi = []
    yi = []
    for v in range(N):
        xi.append(a[v,0])
        yi.append(a[v,1])
    A = np.transpose([xi,yi])
    scat.set_offsets((A))
    return scat 

animation = FuncAnimation(fig, func=animate_frames, fargs=(fig,scat), frames= tmax, interval = 1000)
plt.show()

Where P[i] calls the array in which I have stored the x and y values of my points at each time interval i . (there are tmax entries in P)

What I get is a scatter plot than then flashes to another one every so often but not an animation.

I am a beginner in Python and would be grateful for any help I could get.

Paul
  • 13
  • 2
  • Hi Paul, welcome to SO. What is the expected/desired behaviour? Is there an example animation that you could link to? – Paul Brodersen Feb 24 '20 at 10:30
  • Hi. I uploaded an example from Matlab to drive so you can see what I'm expecting @PaulBrodersen. [The Video](https://drive.google.com/open?id=1VtFwAvprdB-OdAQQvJB8zxbWOLXdDp37). I would be very grateful for any help. – Paul Feb 24 '20 at 12:58

1 Answers1

0

There seems to be nothing wrong with the way that you are trying to animate the scatter plot (apart from some minor issues such as passing around variables that you don't need to pass around). I suspect that either your velocity parameter or your noise parameter is too large (when computing the updated point positions), such that there appears to be no continuity between plots.

Below is a reference implementation. If you play around with the noise parameter eta, you will see that updates appear discontinuous.

enter image description here

#!/usr/bin/env python
"""
Simple scatter plot animation.
"""
import numpy as np
import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation
from scipy.spatial import cKDTree


# def update_positions(x, y, v=0.01):
#     # random diffusion
#     dx, dy = np.random.randn(2, 100)
#     x += v*dx
#     y += v*dy
#     return x, y


def get_mean_angle(angles):
    # https://stackoverflow.com/a/491769/2912349
    # convert to unit vectors
    x = np.cos(angles)
    y = np.sin(angles)
    X = np.c_[x, y]
    U = X / np.linalg.norm(X)
    # get mean unit vector
    x, y = np.mean(X, axis=0)
    return np.arctan2(y, x)


def update_positions(x, y, theta, eta=0.1, r=0.1, v=0.01):
    # https://en.wikipedia.org/wiki/Vicsek_model
    X = np.c_[x,y]
    tree = cKDTree(X)
    neighbours = tree.query_ball_tree(tree, r=r)
    for ii, nn in enumerate(neighbours):
        theta[ii] = get_mean_angle(theta[nn]) + 2*np.pi*np.random.rand()*eta

    X += v * np.c_[np.cos(theta), np.sin(theta)]
    x, y = X.T
    return x, y, theta


if __name__ == '__main__':

    total_points = 100
    x, y = np.random.rand(2, total_points)
    theta = 2*np.pi*np.random.rand(total_points)

    fig, ax = plt.subplots(1,1)
    scatter = ax.scatter(x, y)

    def animate_frames(ii, x, y, theta):
        x, y, theta = update_positions(x, y, theta)
        scatter.set_offsets(np.c_[x, y])
        return scatter

    animation = FuncAnimation(fig, fargs=(x,y,theta), func=animate_frames, frames=20)
    animation.save('vicsek.gif', writer='imagemagick',  savefig_kwargs={'facecolor':'white'}, fps=5)
    plt.show()
Paul Brodersen
  • 11,221
  • 21
  • 38
  • I managed to adapt your code to my problem so that it would work with the functions I had created. Thank you very much for your help. – Paul Feb 24 '20 at 17:16