"use client"; import { motion } from "framer-motion"; import { COLORS, VizFrame } from "./common"; const LABELS = ["gate", "drone", "post", "background"]; const MATRIX: number[][] = [ [212, 3, 1, 18], [2, 87, 0, 7], [4, 1, 64, 12], [9, 4, 6, 0], ]; export function ConfusionMatrix({ width = 640, height = 480, }: { width?: number; height?: number; }) { const N = LABELS.length; const cell = 64; const offsetX = (width - cell * N) / 2 + 20; const offsetY = 70; const max = Math.max(...MATRIX.flat()); // Region label positions const tlBox = { x: offsetX, y: offsetY, w: cell * (N - 1), h: cell * (N - 1) }; const fpRow = { x: offsetX, y: offsetY + (N - 1) * cell, w: cell * (N - 1), h: cell }; const fnCol = { x: offsetX + (N - 1) * cell, y: offsetY, w: cell, h: cell * (N - 1) }; return ( {/* Region highlights */} {/* Column labels */} {LABELS.map((l, j) => ( {l} ))} predicted {/* Row labels */} {LABELS.map((l, i) => ( {l} ))} ground truth {/* Cells */} {MATRIX.flatMap((row, i) => row.map((v, j) => { const t = v / max; return ( 0.4 ? COLORS.surface : COLORS.ink} > {v} ); }), )} {/* Region annotations */} ← false negatives (missed) ← false positives (hallucinated) true positives along the diagonal ); }