Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate+Smoothly interpolate between matrices

I have a matrix of points like:

import numpy as np
import seaborn as sns; sns.set()
import matplotlib.pyplot as plt
%matplotlib inline

originalPoints = np.asarray([[1,2,3,4,5,6],[2,4,6,8,10,12]])
newPoints = np.asarray([[1,2,3,4,5,6],[2,4,6,8,10,12]]) + 20
plt.scatter(originalPoints[0,:],originalPoints[1,:], color='red');
plt.scatter(newPoints[0,:],newPoints[1,:], color='blue');

And that gives me:

enter image description here

I am trying to generate a gif/animation showing the points moving along some smooth path from red to blue. I have been trying to use something like what is discussed here and scipy's interpolate discussed here but I can't seem to figure it out.

Any help would be great.

Bonus: a solution that would work in 3D as well

EDIT: To be clear, what I would like is some nonlinear smooth path along which each blue point moves to reach the red points. Note - the example above is made up. In reality there are just a bunch of blue points and a bunch of red points. Think about animating between two different scatter plots.

like image 320
user79950 Avatar asked Feb 17 '17 20:02

user79950


1 Answers

You can just create the linear path between each of the pairs of points; combining that with matplotlib.animation.FuncAnimation would look like

import matplotlib.animation as animation

def update_plot(t):
    interpolation = originalPoints*(1-t) + newPoints*t
    scat.set_offsets(interpolation.T)
    return scat,

fig = plt.gcf()
plt.scatter(originalPoints[0,:],originalPoints[1,:], color='red')
plt.scatter(newPoints[0,:],newPoints[1,:], color='blue')
scat = plt.scatter([], [], color='green')
animation.FuncAnimation(fig, update_plot, frames=np.arange(0, 1, 0.01))

Linear path between points

Edit: The edited question now asks for a non-linear interpolation instead; replacing update_plot with

noise = np.random.normal(0, 3, (2, 6))
def update_plot(t):
    interpolation = originalPoints*(1-t) + newPoints*t + t*(1-t)*noise
    scat.set_offsets(interpolation.T)
    return scat,

you get instead

Nonsensical path between points

Edit #2: Regarding the query on interpolation of colors in the comment below, you can handle that through matplotlib.collections.Collection.set_color; concretely, replacing the above update_plot with

def update_plot(t):
    interpolation = originalPoints*(1-t) + newPoints*t + t*(1-t)*noise
    scat.set_offsets(interpolation.T)
    scat.set_color([1-t, 0, t, 1])
    return scat,

we end up with

Interpolation with colors

Regarding the "bonus": The 3D case is mostly similar;

a = np.random.multivariate_normal([-3, -3, -3], np.identity(3), 20)
b = np.random.multivariate_normal([3, 3, 3], np.identity(3), 20)

def update_plot(t):
    interpolation = a*(1-t) + b*t
    scat._offsets3d = interpolation.T
    scat._facecolor3d = [1-t, 0, t, 1]
    return scat,

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(a[:, 0], a[:, 1], a[:, 2], c='r')
ax.scatter(b[:, 0], b[:, 1], b[:, 2], c='b')
scat = ax.scatter([], [], [])
ani = animation.FuncAnimation(fig, update_plot, frames=np.arange(0, 1, 0.01))
ani.save('3d.gif', dpi=80, writer='imagemagick')

3D example

Edit regarding the comment below on how to do this in stages: One can achieve this by incorporating the composition of paths directly in update_plot:

a = np.random.multivariate_normal([-3, -3, -3], np.identity(3), 20)
b = np.random.multivariate_normal([3, 3, 3], np.identity(3), 20)
c = np.random.multivariate_normal([-3, 0, 3], np.identity(3), 20)

def update_plot(t):
    if t < 0.5:
        interpolation = (1-2*t)*a + 2*t*b
        scat._facecolor3d = [1-2*t, 0, 2*t, 1]
    else:
        interpolation = (2-2*t)*b + (2*t-1)*c
        scat._facecolor3d = [0, 2*t-1, 2-2*t, 1]
    scat._offsets3d = interpolation.T
    return scat,

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(a[:, 0], a[:, 1], a[:, 2], c='r')
ax.scatter(b[:, 0], b[:, 1], b[:, 2], c='b')
ax.scatter(c[:, 0], c[:, 1], c[:, 2], c='g')
scat = ax.scatter([], [], [])
ani = animation.FuncAnimation(fig, update_plot, frames=np.arange(0, 1, 0.01))
ani.save('3d.gif', dpi=80, writer='imagemagick')

Example using path composition

like image 131
fuglede Avatar answered Nov 12 '22 08:11

fuglede