PCA Projection Viz

A square SVG plane that visualizes principal component analysis on a 2D point cloud. The cloud's centroid is computed, the two-by-two covariance matrix is eigen-decomposed analytically, and the principal axes are drawn from the centroid — each scaled by the square root of its eigenvalue, so the dominant direction is visually loudest. With showProjections, perpendicular drops from each point onto PC1 reveal how PCA flattens the cloud to one dimension.

Principal component analysis on 20 points. PC1 variance fraction 0.91, PC2 variance fraction 0.09.
PC1 0.91PC2 0.09
Customize
Data
elongated
Axes
both

Installation

npx shadcn@latest add https://craftbits.dev/r/pca-projection-viz.json

Usage

import { PCAProjectionViz } from "@craft-bits/core";
 
<PCAProjectionViz
  points={[
    { x: 1.2, y: 0.5 },
    { x: 2.4, y: 1.1 },
    { x: -1.0, y: -0.4 },
  ]}
/>

Show only the dominant axis with each point projected onto it:

<PCAProjectionViz
  points={cloud}
  pcMode="pc1"
  showProjections
/>

Hide the axes entirely for a plain scatter:

<PCAProjectionViz points={cloud} showAxes={false} />

Understanding the component

  1. Centroid first. The cloud mean is computed once and everything else is centered there — the axes are drawn from the centroid, the covariance is computed about it, and the auto-fit viewport is centered on it.
  2. Analytical two-by-two eigen-decomposition. The covariance matrix is two-by-two, so the eigenvalues are the closed-form roots of the characteristic polynomial. The eigenvector for the larger eigenvalue is derived from the singular system with a numerically safe branch when the off-diagonal entry is near zero. PC2 is the 90° rotation of PC1.
  3. Axes scaled by the square root of lambda. The arrow length is axisScale times the standard deviation along that direction. Doubling the spread doubles the arrow.
  4. Two tones. PC1 draws in var(--cb-accent) with the bold edge token; PC2 draws in var(--cb-fg-muted) with the normal edge token — so the dominant axis is visually loudest.
  5. Optional projection drops. When showProjections is on, a dotted segment connects each point to its foot on the PC1 axis. The foot is the standard scalar-projection formula applied to the centered points.
  6. Auto-fit viewport. The SVG viewport is centered on the centroid and sized to fit both the cloud extents and the axis arrows, with a 15 percent margin. No range prop — the viewport adapts so any cloud shape looks right.
  7. Variance fractions below. PC1 / PC2 contribution to total variance is shown as the eigenvalue ratio beneath the plot, in tabular numerals.
  8. Spring transitions. Axes, projection lines, and the centroid follow with SPRINGS.smooth. prefers-reduced-motion: reduce collapses every spring to duration: 0.

Props

PropTypeDefaultDescription
pointsreadonly PCAPoint[]required2D points to analyze.
showAxesbooleantrueRender the PC1 / PC2 axes from the centroid.
showProjectionsbooleanfalseDrop a perpendicular from each point onto PC1.
pcMode"pc1" | "pc2" | "both""both"Which principal axes to draw.
axisScalenumber2Multiplier for arrow length.
sizenumber320SVG side length in pixels (the plane is square).
transitionTransitionSPRINGS.smoothSpring for axis / projection transitions.
classNamestringMerged onto the root <div> via cn().

The PCAPoint shape:

FieldTypeDescription
xnumberx coordinate in math space.
ynumbery coordinate in math space.

Accessibility

  • The SVG is role="figure" with an aria-labelledby heading also rendered as a visually hidden aria-live="polite" summary — screen readers hear the variance fractions whenever points change.
  • The visualization is read-only — no interactive handles to enumerate.
  • Variance-fraction readouts use 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/viz/PCAProjectionViz.tsx). The source paired the visualization with a draggable rotating-axis explorer, Explore / Predict / Challenge mode strip, narration heuristics, history-undo state machine, and preset bookmarks. The library extract is the pure visualization primitive — a 2D cloud, its analytically computed principal axes, and an optional projection drop. Mode strips, score dots, and narration belong in the consuming lesson, not the primitive.