VectorMotion
AI/ML

Confusion Matrix Card - ML Model Performance

Visualize ML model classification performance with confusion matrices. Analyze true positives, false positives, and model accuracy metrics interactively.

Confusion Matrix Card

The Confusion Matrix Card displays a confusion matrix visualization showing true positives, false positives, true negatives, and false negatives for classification model evaluation.

Preview

Installation

npx shadcn@latest add https://www.vectormotion.dev/registry/confusion-matrix-card.json
Confusion Matrix Card
'use client'import React from 'react';import { Grid } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, ScatterChart, Scatter, XAxis, YAxis, Tooltip, Cell, ZAxis } from 'recharts';function cn(...inputs: ClassValue[]) {   return twMerge(clsx(inputs))}interface MatrixData {   x: number;   y: number;   value: number;   label: string;   fill: string;   [key: string]: any;}interface ConfusionMatrixCardProps {   className?: string;   title?: string;   subtitle?: string;   data?: MatrixData[];}const DEFAULT_DATA: MatrixData[] = [   { x: 1, y: 1, value: 850, label: 'TP', fill: '#10b981' }, // True Positive (Emerald)   { x: 2, y: 1, value: 42, label: 'FP', fill: '#f43f5e' },  // False Positive (Rose)   { x: 1, y: 2, value: 15, label: 'FN', fill: '#f43f5e' },  // False Negative (Rose)   { x: 2, y: 2, value: 910, label: 'TN', fill: '#10b981' }, // True Negative (Emerald)];const DEFAULT_TITLE = "Confusion Matrix";const DEFAULT_SUBTITLE = "Predicted vs Actual";export const ConfusionMatrixCard: React.FC<ConfusionMatrixCardProps> = ({   className = "",   title = DEFAULT_TITLE,   subtitle = DEFAULT_SUBTITLE,   data = DEFAULT_DATA,}) => {   return (      <motion.div         initial={{ opacity: 0, y: 20 }}         animate={{ opacity: 1, y: 0 }}         transition={{ duration: 0.5, delay: 0.1 }}         className={cn(            "relative overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-sm transition-all hover:border-blue-300 dark:hover:border-blue-700 hover:shadow-md flex flex-col h-full",            className         )}      >         <div className="p-5 flex flex-col h-full relative z-10">            <div className="mb-4 flex items-start justify-between">               <div>                  <h3 className="font-bold text-lg text-foreground">                     {title}                  </h3>                  <p className="text-sm text-muted-foreground font-medium">                     {subtitle}                  </p>               </div>               <div className="rounded-lg border-2 border-blue-100 dark:border-blue-800 p-2 text-blue-500 dark:text-blue-400 flex items-center justify-center">                  <Grid className="h-5 w-5" />               </div>            </div>            <div className="flex-1 w-full min-h-[160px] relative">               <ResponsiveContainer width="100%" height="100%">                  <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>                     <XAxis type="number" dataKey="x" name="Predicted" hide domain={[0, 3]} />                     <YAxis type="number" dataKey="y" name="Actual" hide domain={[0, 3]} reversed />                     <ZAxis type="number" dataKey="value" range={[4000, 4000]} />                     <Tooltip                        cursor={{ strokeDasharray: '3 3' }}                        content={({ active, payload }) => {                           if (active && payload && payload.length) {                              return (                                 <div className="rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 p-2 shadow-sm text-xs">                                    <span className="font-bold">{payload[0]?.payload?.label ?? ''}:</span> {payload[0]?.payload?.value ?? 0}                                 </div>                              );                           }                           return null;                        }}                     />                     <Scatter data={data} shape={(props: any) => {                        const { cx, cy, payload } = props;                        return (                           <g>                              <rect                                 x={cx - 60}                                 y={cy - 40}                                 width={120}                                 height={80}                                 rx={8}                                 fill={payload.fill}                                 opacity={0.2}                              />                              <text x={cx} y={cy - 10} textAnchor="middle" dominantBaseline="middle" className="text-xs font-bold fill-zinc-700 dark:fill-zinc-300">                                 {payload.label}                              </text>                              <text x={cx} y={cy + 15} textAnchor="middle" dominantBaseline="middle" className="text-lg font-bold fill-zinc-900 dark:fill-zinc-50">                                 {payload.value}                              </text>                           </g>                        );                     }}>                     </Scatter>                  </ScatterChart>               </ResponsiveContainer>            </div>            <div className="absolute -bottom-4 -right-4 z-0 opacity-5 pointer-events-none">               <Grid className="w-40 h-40 text-blue-500" />            </div>         </div>      </motion.div>   );};

Props

Prop

Type

Usage

This component is a demo card displaying confusion matrix data with animated visualizations and dark mode support.

On this page

Free block

Need this in production?

Unlock install commands, source access, commercial use, and AI prompts for all VectorMotion blocks.