Кажется, нет ничего плохого в том, как вы пытаетесь анимировать график рассеяния (кроме некоторых незначительных проблем, таких как передача переменных, которые вам не нужно передавать). Я подозреваю, что либо ваш параметр скорости, либо ваш параметр шума слишком велик (при вычислении обновленных положений точек), так что, похоже, нет непрерывности между графиками.
Ниже приведена справочная реализация. Если вы поиграете с параметром шума eta, вы увидите, что обновления появляются с перерывами.
#!/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()