/** * Parameter Importance Chart * Shows which design parameters have the most impact on objectives * Uses correlation analysis between parameters and objective values */ import { useMemo } from 'react'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell } from 'recharts'; interface Trial { trial_number: number; values: number[]; params: Record; } interface DesignVariable { name: string; parameter?: string; unit?: string; } interface ParameterImportanceChartProps { trials: Trial[]; designVariables: DesignVariable[]; objectiveIndex?: number; objectiveName?: string; } // Calculate Pearson correlation coefficient function pearsonCorrelation(x: number[], y: number[]): number { if (x.length !== y.length || x.length < 2) return 0; const n = x.length; const sumX = x.reduce((a, b) => a + b, 0); const sumY = y.reduce((a, b) => a + b, 0); const sumXY = x.reduce((acc, xi, i) => acc + xi * y[i], 0); const sumX2 = x.reduce((acc, xi) => acc + xi * xi, 0); const sumY2 = y.reduce((acc, yi) => acc + yi * yi, 0); const numerator = n * sumXY - sumX * sumY; const denominator = Math.sqrt((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY)); if (denominator === 0) return 0; return numerator / denominator; } export function ParameterImportanceChart({ trials, designVariables, objectiveIndex = 0, objectiveName = 'Objective' }: ParameterImportanceChartProps) { const importanceData = useMemo(() => { if (!trials || trials.length < 3 || !designVariables || designVariables.length === 0) { return []; } // Extract objective values const objectiveValues = trials .filter(t => t.values && t.values.length > objectiveIndex) .map(t => t.values[objectiveIndex]); if (objectiveValues.length < 3) return []; // Calculate correlation for each parameter const importances = designVariables.map(dv => { const paramName = dv.parameter || dv.name; const paramValues = trials .filter(t => t.params && paramName in t.params && t.values && t.values.length > objectiveIndex) .map(t => t.params[paramName]); const corrObjectiveValues = trials .filter(t => t.params && paramName in t.params && t.values && t.values.length > objectiveIndex) .map(t => t.values[objectiveIndex]); if (paramValues.length < 3) return { name: dv.name, importance: 0, correlation: 0 }; const correlation = pearsonCorrelation(paramValues, corrObjectiveValues); // Use absolute correlation as importance (sign indicates direction) const importance = Math.abs(correlation); return { name: dv.name, importance: importance * 100, // Convert to percentage correlation, direction: correlation > 0 ? 'positive' : 'negative' }; }); // Sort by importance (descending) return importances.sort((a, b) => b.importance - a.importance); }, [trials, designVariables, objectiveIndex]); if (importanceData.length === 0) { return (

Parameter Importance

Need at least 3 trials for correlation analysis
); } // Color based on correlation direction const getBarColor = (entry: typeof importanceData[0]) => { if (entry.correlation > 0) { // Positive correlation (increasing param increases objective) - red for minimization return '#f87171'; } else { // Negative correlation (increasing param decreases objective) - green for minimization return '#34d399'; } }; return (

Parameter Importance

Correlation with {objectiveName} ({trials.length} trials)

`${v.toFixed(0)}%`} tick={{ fill: '#94a3b8', fontSize: 11 }} stroke="#334155" /> { const corr = props.payload.correlation; return [ `${value.toFixed(1)}% (r=${corr.toFixed(3)})`, 'Importance' ]; }} contentStyle={{ backgroundColor: '#1e293b', border: '1px solid #334155', borderRadius: '8px', boxShadow: '0 4px 6px rgba(0,0,0,0.3)' }} labelStyle={{ color: '#e2e8f0' }} /> {importanceData.map((entry, index) => ( ))}
{/* Legend */}
Negative correlation (helps minimize)
Positive correlation (hurts minimize)
); }