import React, { useState } from 'react'; const BoxPlotComparisonWidget: React.FC = () => { // Box Plot A is fixed const statsA = { min: 10, q1: 18, med: 24, q3: 30, max: 42 }; // Box Plot B is adjustable const [shift, setShift] = useState(0); // Shift median const [spread, setSpread] = useState(1); // Scale spread const statsB = { min: 10 + shift - (5 * (spread - 1)), // Just approximating visual expansion q1: 16 + shift - (2 * (spread - 1)), med: 26 + shift, q3: 34 + shift + (2 * (spread - 1)), max: 38 + shift + (4 * (spread - 1)) }; const scaleX = (val: number) => (val / 60) * 100; // 0 to 60 range mapping to % const BoxPlot = ({ stats, color, label }: { stats: any, color: string, label: string }) => { const leftW = scaleX(stats.min); const rightW = scaleX(stats.max); const boxL = scaleX(stats.q1); const boxR = scaleX(stats.q3); const med = scaleX(stats.med); return (
{label}
{/* Main Line (Whisker to Whisker) */}
{/* Whiskers */}
{/* Box */}
{/* Median Line */}
{/* Labels on Hover */}
Min:{stats.min.toFixed(0)} Q1:{stats.q1.toFixed(0)} Med:{stats.med.toFixed(0)} Q3:{stats.q3.toFixed(0)} Max:{stats.max.toFixed(0)}
); }; const iqrA = statsA.q3 - statsA.q1; const iqrB = statsB.q3 - statsB.q1; const rangeA = statsA.max - statsA.min; const rangeB = statsB.max - statsB.min; return (
{/* Axis */}
0102030405060
setShift(parseInt(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600"/>
setSpread(parseFloat(e.target.value))} className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600"/>
Median Comparison
{statsA.med} {statsA.med > statsB.med ? '>' : statsA.med < statsB.med ? '<' : '='} {statsB.med}
IQR Comparison
{iqrA.toFixed(0)} {iqrA > iqrB ? '>' : iqrA < iqrB ? '<' : '='} {iqrB.toFixed(0)}
The box length represents the IQR (Middle 50%). The whiskers represent the full Range.
); }; export default BoxPlotComparisonWidget;