Eigenvalue Finder

A square SVG plane that visualizes the eigen-decomposition of a 2x2 matrix. The unit circle is drawn as a dashed reference; the image of that circle under the matrix is overlaid as an ellipse in accent color. When the eigenvalues are real, each unit eigenvector is rendered as an arrow from the origin scaled by its eigenvalue — geometrically, the directions where the transform aligns (input and output are collinear). When the discriminant is negative, the component falls back to a complex readout and skips the eigenvector arrows.

2 by 2 matrix eigenvalue finder. Real eigenvalues 3.00 and 1.00. Eigenvector 1: (-0.71, -0.71). Eigenvector 2: (-0.71, 0.71).
real eigenvalues
lambda1= 3.00v = (-0.71, -0.71)lambda2= 1.00v = (-0.71, 0.71)
Customize
Row 1 (a, b)
2
1
Row 2 (c, d)
1
2
Display

Installation

npx shadcn@latest add https://craftbits.dev/r/eigenvalue-finder.json

Usage

import { EigenvalueFinder } from "@craft-bits/core";
 
<EigenvalueFinder
  defaultMatrix={[
    [2, 1],
    [1, 2],
  ]}
/>

Drive the matrix as a controlled value:

const [matrix, setMatrix] = useState<EigenvalueMatrix2D>([
  [2, 1],
  [1, 2],
]);
 
<EigenvalueFinder matrix={matrix} onMatrixChange={setMatrix} />

A rotation matrix — complex conjugate eigenvalues, no real eigenvectors:

<EigenvalueFinder
  matrix={[
    [Math.cos(Math.PI / 4), -Math.sin(Math.PI / 4)],
    [Math.sin(Math.PI / 4),  Math.cos(Math.PI / 4)],
  ]}
/>

Hide the unit circle to focus on the ellipse:

<EigenvalueFinder
  matrix={[[3, 0], [0, 0.5]]}
  showUnitCircle={false}
/>

Understanding the component

  1. Closed-form 2x2 eigen-decomposition. Eigenvalues are the roots of the characteristic polynomial lambda squared minus trace times lambda plus det = 0. The discriminant trace squared minus 4 det decides the branch — non-negative gives two real eigenvalues, negative gives a conjugate pair.
  2. Unit eigenvectors from the null space. For each real eigenvalue, the eigenvector is solved from A minus lambda I times v equals 0 and normalized. A numerically safe branch picks whichever row of A minus lambda I has larger magnitude — that avoids dividing by a near-zero pivot at scalar multiples of the identity.
  3. Unit circle as the input space. Every point on the dashed circle is a unit input vector. The image of the circle under the matrix is an ellipse drawn alongside the eigenvector arrows.
  4. Eigenvectors as fixed directions. Each unit eigenvector is drawn as a dashed faint segment of length one; the same direction scaled by lambda is drawn as a solid arrow. When the matrix acts on an eigenvector the result lies on the same line — the dashed input and solid output share a direction.
  5. Two tones for two eigenvectors. lambda 1 (sorted as the larger) draws in var(--cb-accent); lambda 2 draws in var(--cb-warning). Color matches the readout chip below.
  6. Auto-fit viewport. The viewport is sized so the largest of the eigenvalue magnitudes and the matrix's row norms comfortably fits, with a 30 percent margin.
  7. Complex case fallback. When the discriminant is negative the component skips the eigenvector arrows (no real direction exists) and surfaces a complex readout under the plot. The ellipse still renders, so rotations still make visual sense.
  8. Spring transitions. The ellipse polyline and the eigenvector arrows animate with SPRINGS.smooth between matrix changes. prefers-reduced-motion: reduce collapses every spring to duration: 0.

Props

PropTypeDefaultDescription
matrixEigenvalueMatrix2DControlled 2x2 matrix. Pair with onMatrixChange.
defaultMatrixEigenvalueMatrix2DidentityUncontrolled initial matrix.
onMatrixChange(next: EigenvalueMatrix2D) => voidFires when the matrix changes.
showUnitCirclebooleantrueRender the dashed input unit circle.
showTransformedEllipsebooleantrueRender the image of the unit circle (ellipse).
showEigenvectorsbooleantrueRender eigenvector arrows when real.
rangereadonly [number, number]autoVisible math-space domain on both axes.
sizenumber320SVG side length in pixels (the plane is square).
transitionTransitionSPRINGS.smoothSpring for ellipse / eigenvector transitions.
classNamestringMerged onto the root <div> via cn().

The EigenvalueMatrix2D shape is a row-major tuple — [[a, b], [c, d]] represents

| a  b |
| c  d |

Accessibility

  • The SVG is role="img" with an aria-labelledby heading also rendered as a visually hidden aria-live="polite" summary — assistive tech announces the eigenvalues and eigenvectors as the matrix changes.
  • The visualization is read-only; there are no interactive handles inside the plot, so no keyboard or pointer behaviour to enumerate.
  • The eigenvalue readout uses tabular numerals so the columns stay aligned as values change.
  • Animation respects prefers-reduced-motion: reduce — every spring collapses to an instant swap.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/EigenvalueFinder.tsx). The source paired a polynomial-plot dragger with a column-vector parallelism check and a snap-to-root narration state machine. The library extract is the pure visualization primitive — the unit circle, its image ellipse, the eigenvectors as arrows, and the eigenvalue readout.