An eigenvector animation¶

In this notebook we construct an animation to illustrate the definition of eigenvectors, using the matrix $A=\begin{pmatrix} 2&-4 \\ -3&1\end{pmatrix}$ as an example. The animation will show a vector $v$ (shown in red) moving around the unit circle (shown in green). As $v$ moves around the unit circle, the vector $Av$ (shown in blue) traces out an ellipse (shown in orange). Usually, $Av$ points in a different direction to $\pm v$. Occasionally, however, $Av$ points in the same direction as $v$ or the opposite direction, so $Av=\lambda v$ for some scalar $\lambda$ (which may be positive or negative). In this situation, we say that $v$ is an eigenvector with eigenvalue $\lambda$. The eigenvector directions are shown on the diagram as black lines.

In [2]:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

%matplotlib qt

The code below finds the eigenvalues and eigenvectors of $A$. Note that any nonzero scalar times an eigenvector is still an eigenvector. In particular, if we have found an eigenvector, we can divide it by its norm to get an eigenvector that is a unit vector. The function np.linalg.eig() actually does this automatically, so it always gives us eigenvectors that are unit vectors. It also packages the eigenvectors as a $2\times 2$ matrix, which we call $U$: the eigenvectors are the columns of $U$.

In [4]:
A0 = [[2,-4],[-3,1]]
A = np.array(A0)
L, U = np.linalg.eig(A)
print(f"The eigenvectors of the matrix A={A0} are {U[:,0]} and {U[:,1]}, with eigenvalues {L[0]} and {L[1]} respectively.")
The eigenvectors of the matrix A=[[2, -4], [-3, 1]] are [ 0.8 -0.6] and [0.70710678 0.70710678], with eigenvalues 5.0 and -2.0 respectively.
In [5]:
N = 200
ts = np.linspace(0,2*np.pi,N)
xs = np.cos(ts)                       # x coordinates of points on the unit circle
ys = np.sin(ts)                       # y coordinates of points on the unit circle
C = np.array([np.cos(ts),np.sin(ts)]) # matrix whose columns are the points on the unit circle
E = A @ C                             # matrix whose columns are points on the ellipse
Axs = E[0]                            # x coordinates of points on the ellipse
Ays = E[1]                            # y coordinates of points on the ellipse
In [6]:
fig, ax = plt.subplots()
ax.axis('equal')
ax.axis('off')
ax.plot(C[0],C[1],color='green')   # draw the unit circle
ax.plot(E[0],E[1],color='orange')  # draw the ellipse
# draw black lines for the eigenvector directions
ax.plot([-L[0] * U[0,0], L[0] * U[0,0]], [-L[0] * U[1,0], L[0] * U[1,0]],'k-')
ax.plot([-L[1] * U[0,1], L[1] * U[0,1]], [-L[1] * U[1,1], L[1] * U[1,1]],'k-')
# The object v_line will be the line joining the origin to the point v on he unit circle
# At this stage we just set v_line to be an empty line.  The first call to repaint()
# will set v_line to be the line from (0,0) to (1,0), and then subsequent calls to
# repaint() will move it around the unit circle.  Similarly, v_blob will be the point
# v, and Av_blob will be the point Av on the ellipse, and Av_line will be the line
# from (0,0) to Av.
v_line,  = ax.plot([], [], 'r-')
v_blob,  = ax.plot([], [], 'ko')
Av_line, = ax.plot([], [], 'b-')
Av_blob, = ax.plot([], [], 'ko')
text = ax.text(3, 3, '0')

def repaint(i):    
    v_line.set_data([0, xs[i]], [0, ys[i]])
    v_blob.set_data([xs[i]], [ys[i]])
    Av_line.set_data([0, Axs[i]], [0, Ays[i]])
    Av_blob.set_data([Axs[i]], [Ays[i]])
    text.set_text(f'{i}')
    # For the animation to work correctly, repaint() needs to return a tuple of the
    # objects that have been changed.
    return (v_line, v_blob, Av_line, Av_blob, text)

anim = None
# For the animation framework to work correctly, the object returned by FuncAnimation()
# must be assigned to a variable, otherwise it will be garbage collected and the animation
# will not work.
anim = FuncAnimation(fig, repaint, frames=N, interval=20, blit=True)
In [ ]: