import React, { useState } from "react"; const ProbabilityTreeWidget: React.FC = () => { const [replacement, setReplacement] = useState(false); const [initR, setInitR] = useState(3); const [initB, setInitB] = useState(4); const [hoverPath, setHoverPath] = useState(null); // 'RR', 'RB', 'BR', 'BB' const total = initR + initB; // Level 1 Probs const pR = initR / total; const pB = initB / total; // Level 2 Probs (Given R) const r_R = replacement ? initR : Math.max(0, initR - 1); const r_Total = replacement ? total : total - 1; const pR_R = r_Total > 0 ? r_R / r_Total : 0; const pB_R = r_Total > 0 ? 1 - pR_R : 0; // Level 2 Probs (Given B) const b_B = replacement ? initB : Math.max(0, initB - 1); const b_Total = replacement ? total : total - 1; const pB_B = b_Total > 0 ? b_B / b_Total : 0; const pR_B = b_Total > 0 ? 1 - pB_B : 0; // Final Probs const pRR = pR * pR_R; const pRB = pR * pB_R; const pBR = pB * pR_B; const pBB = pB * pB_B; const fraction = (num: number, den: number) => { if (den === 0) return "0"; return ( {num}/{den} ); }; const getPathColor = ( segment: | "top" | "bottom" | "top-top" | "top-bottom" | "bottom-top" | "bottom-bottom", ) => { const defaultColor = "#cbd5e1"; // Slate 300 if (!hoverPath) { // Default coloring based on branch type if (segment.includes("top")) return "#f43f5e"; // Red branches if (segment.includes("bottom")) return "#3b82f6"; // Blue branches return defaultColor; } // Highlighting logic based on hoverPath if (segment === "top") return hoverPath === "RR" || hoverPath === "RB" ? "#f43f5e" : "#f1f5f9"; if (segment === "bottom") return hoverPath === "BR" || hoverPath === "BB" ? "#3b82f6" : "#f1f5f9"; if (segment === "top-top") return hoverPath === "RR" ? "#f43f5e" : "#f1f5f9"; if (segment === "top-bottom") return hoverPath === "RB" ? "#3b82f6" : "#f1f5f9"; if (segment === "bottom-top") return hoverPath === "BR" ? "#f43f5e" : "#f1f5f9"; if (segment === "bottom-bottom") return hoverPath === "BB" ? "#3b82f6" : "#f1f5f9"; return defaultColor; }; const getStrokeWidth = (segment: string) => { if (!hoverPath) return 2; if (segment === "top") return hoverPath === "RR" || hoverPath === "RB" ? 4 : 1; if (segment === "bottom") return hoverPath === "BR" || hoverPath === "BB" ? 4 : 1; if (segment === "top-top") return hoverPath === "RR" ? 4 : 1; if (segment === "top-bottom") return hoverPath === "RB" ? 4 : 1; if (segment === "bottom-top") return hoverPath === "BR" ? 4 : 1; if (segment === "bottom-bottom") return hoverPath === "BB" ? 4 : 1; return 2; }; return (
{/* Controls */}
{initR}
{initB}
{/* Root */} {/* Level 1 Branches */} {/* Level 1 Labels */}
{initR}/{total}
{initB}/{total}
{/* Level 1 Nodes */} R B {/* Level 2 Branches (Top) */} {/* Level 2 Top Labels */}
{r_R}/{r_Total}
{initB}/{r_Total}
{/* Level 2 Branches (Bottom) */} {/* Level 2 Bottom Labels */}
{initR}/{b_Total}
{b_B}/{b_Total}
{/* Outcomes (Interactive Targets) */} setHoverPath("RR")} onMouseLeave={() => setHoverPath(null)} > RR: {(pRR * 100).toFixed(1)}% setHoverPath("RB")} onMouseLeave={() => setHoverPath(null)} > RB: {(pRB * 100).toFixed(1)}% setHoverPath("BR")} onMouseLeave={() => setHoverPath(null)} > BR: {(pBR * 100).toFixed(1)}% setHoverPath("BB")} onMouseLeave={() => setHoverPath(null)} > BB: {(pBB * 100).toFixed(1)}%
{/* Calculation Panel */}
{!hoverPath ? (

Hover over an outcome (e.g., RR) to see the calculation.

) : ( <>

Calculation for{" "} {hoverPath} ({hoverPath[0] === "R" ? "Red" : "Blue"} then{" "} {hoverPath[1] === "R" ? "Red" : "Blue"}):

{/* First Draw */} P({hoverPath[0]}) × P({hoverPath[1]} | {hoverPath[0]}) = {/* Numbers */} {fraction(hoverPath[0] === "R" ? initR : initB, total)} × {fraction( hoverPath === "RR" ? r_R : hoverPath === "RB" ? initB : hoverPath === "BR" ? initR : b_B, hoverPath[0] === "R" ? r_Total : b_Total, )} = {/* Result */} {fraction( (hoverPath[0] === "R" ? initR : initB) * (hoverPath === "RR" ? r_R : hoverPath === "RB" ? initB : hoverPath === "BR" ? initR : b_B), total * (hoverPath[0] === "R" ? r_Total : b_Total), )}
{!replacement && hoverPath[0] === hoverPath[1] && (

⚠ Notice: The numerator decreased because we kept the first{" "} {hoverPath[0] === "R" ? "Red" : "Blue"} item!

)} )}
); }; export default ProbabilityTreeWidget;