"use client"; import { motion } from "framer-motion"; import { COLORS, VizFrame } from "./common"; /** * 2D scatter with a separating hyperplane and explicit margin lines. The * support vectors (points sitting on the margin) are highlighted. */ export function SVMMargin({ width = 720, height = 420, }: { width?: number; height?: number; }) { const padX = 40; const padY = 30; const sx = (x: number) => padX + x * (width - padX * 2); const sy = (y: number) => height - padY - y * (height - padY * 2); // Two clusters of points, well separated const class0 = [ [0.18, 0.32], [0.22, 0.46], [0.30, 0.30], [0.36, 0.5], [0.28, 0.62], [0.40, 0.28], [0.16, 0.54], [0.32, 0.74], [0.44, 0.40], [0.24, 0.22], ]; const class1 = [ [0.62, 0.74], [0.70, 0.62], [0.78, 0.50], [0.74, 0.86], [0.66, 0.92], [0.84, 0.66], [0.58, 0.58], [0.92, 0.74], [0.80, 0.34], [0.68, 0.46], ]; // Hyperplane: y = -x + 1 (slope -1, intercept 1) → normal (1, 1)/sqrt(2) // Decision line passes through (0, 1) and (1, 0). // Margin offset perpendicular to normal. const margin = 0.15; const support = [ [0.40, 0.40], // class 0 on left margin (≈ x+y = 0.85) [0.30, 0.55], [0.62, 0.55], // class 1 on right margin (≈ x+y = 1.15) [0.55, 0.62], ]; return ( {/* Margin band fill */} {/* Decision boundary */} {/* Margin lines */} {/* Points */} {class0.map(([x, y], i) => ( ))} {class1.map(([x, y], i) => ( ))} {/* Support vectors */} {support.map(([x, y], i) => ( ))} {/* Labels */} class −1 class +1 w·x + b = 0 ); }