Development Log

Building an interactive visualization to accompany Week 8 course notes on regularization (ISL Ch. 6, ESL Ch. 3). The goal: make it visually obvious why L1 (Lasso) drives coefficients to exactly zero while L2 (Ridge) does not.

Iteration History

v1 — Initial build

Request: Find or create a figure explaining the L1/L2 difference, emphasizing exact zeros for L1.

Approach: Classic geometric figure (after ISL Fig. 6.7 / ESL Fig. 3.11): loss ellipses centered on the OLS estimate, constraint region (sphere for Ridge, diamond for Lasso), regularized solution at first contact point. Interactive slider controlling α.

Bug OLS point placed too symmetrically at (0.55, 0.45). L1 solution never visibly hit a corner across the slider range.

v2 — Reposition OLS point

Request: Make the coefficient actually go to zero for L1.

Fix Moved OLS to (0.75, 0.12), skewing toward the β₁ axis so the L1 projection would land on the corner (β₂ = 0).

Bug Still not working — the dot wasn't moving to zero as α increased.

v3 — Fix L1 projection math

Request: The red dot position is not being computed correctly.

Diagnosis: L1 projection used radial scaling — scale = r / (|β₁| + |β₂|) — which moves the dot along the ray from origin to OLS. This never hits an axis unless the OLS point was already on one.

Fix Replaced with correct soft-thresholding: find λ such that Σ max(|βᵢ| − λ, 0) = r, then set each coordinate to sign(βᵢ) · max(|βᵢ| − λ, 0). Drives the smaller coefficient to exactly zero when λ exceeds it.

Bug Still not working visually.

v4 — Fix gradient arrow direction

Request: The gradient arrow for L1 should be perpendicular to the diamond boundary — it isn't.

Diagnosis: Penalty arrow pointed from solution toward origin — correct for L2, wrong for L1. For L1, ∇‖β‖₁ = sign(β), which points perpendicular to the diamond face.

Fix L1 arrow direction set to (-sign(β₁), -sign(β₂)) in data coordinates.

Bug Arrow correct, but dot still not moving right — position and gradient logic were inconsistent.

v5 — Full rewrite for consistency ("Doesn't happen :-(" version)

Request: The dot needs to move in the gradient direction as α changes.

Root cause: Residual inline position logic in the Panel component, inconsistent with the projection functions.

Fix attempt Full rewrite with single clean data flow: project → canvas coords → draw arrows → render.

Bug User reported: "Doesn't happen… :-(" — dot still not reaching the axis. The broken version is preserved on the Broken Version tab for comparison.

v6 — Add numerical readout (first working version)

Request: The problem persists.

Fix Added live β̂₁ / β̂₂ numerical readout above each panel plus a "← zero!" indicator. Also adjusted OLS y to 0.22 and redesigned the r formula around the known threshold: OLS L1 norm = 0.75 + 0.22 = 0.97; β₂ zeroes when r < 0.53, i.e. α > 0.52; set r = 0.87 − α × 0.65 to place the threshold mid-slider.

Post-hoc analysis: The math was likely correct in v5. The readout and bold "β₂ = 0 ✓" annotation made the zero event legible for the first time.

v7 — Extend slider to α = 0

Request: At α = 0 the dots should coincide with the OLS estimate.

Fix Changed r = 1.0 − α × 0.65 (r ≥ 0.97 at α = 0, containing OLS in both norms). Slider min changed from 0.05 to 0.

v8 — Package for GitHub Pages

Request: Single HTML file including summary and both versions of the visualization.

Output This file. React + Babel loaded from CDN — no build step needed. Push index.html to a GitHub repo, enable Pages under Settings → Pages → main / root.

Key Concepts Illustrated

ConceptVisualization
L2 constraint regionSphere — smooth, no corners
L1 constraint regionDiamond — corners on coordinate axes
Regularized solutionWhere loss ellipses first touch constraint region
Why L2 never zerosSphere tangent point is generically off-axis
Why L1 zerosDiamond corners sit on axes; ellipses likely hit a corner first
Optimality condition∇RSS and α∇penalty are equal and opposite (shown as arrows)
L1 penalty gradientsign(β) — perpendicular to diamond face, not toward origin
Soft-thresholdingCorrect L1 projection; smaller coefficient zeroed when λ exceeds it

References