import { useState } from 'react'; import { Play, AlertTriangle, CheckCircle2, Layers, BarChart3, Grid3x3, Settings2, Network } from 'lucide-react'; import { api } from '../../api/client'; import { useStore } from '../../store/useStore'; import { Panel } from '../common/Panel'; import { LoadingSpinner } from '../common/LoadingSpinner'; import { ClusterVisualization } from './ClusterVisualization'; import { CorrelationHeatmap } from './CorrelationHeatmap'; import { XGBoostResults } from './XGBoostResults'; import { DistributionChart } from './DistributionChart'; import { CramersVExplorer } from './CramersVExplorer'; import type { AnalysisResponse, XGBoostResult } from '../../types'; type TabId = 'clusters' | 'correlation' | 'xgboost' | 'distribution' | 'association'; export function AnalysisPage() { const { data, dataLoaded, analysisResults, setAnalysisResults, analysisRunning, setAnalysisRunning, setPage } = useStore(); const [selected, setSelected] = useState([]); const [error, setError] = useState(null); const [activeTab, setActiveTab] = useState('clusters'); // XGBoost feature importance handed over from the Cramér's V explorer. const [assocXgboost, setAssocXgboost] = useState | null>(null); const handleAssocXgboost = (r: Record) => { setAssocXgboost(r); setActiveTab('xgboost'); }; // Cluster pipeline tuning (mirrors analyzing.py controls) const [showParams, setShowParams] = useState(false); const [enableTfidf, setEnableTfidf] = useState(false); const [minClusterSize, setMinClusterSize] = useState(15); const [nNeighbors, setNNeighbors] = useState(15); const [minDist, setMinDist] = useState(0.1); const columns = data?.columns ?? []; const results: AnalysisResponse | null = analysisResults; const toggleColumn = (col: string) => { setSelected((prev) => prev.includes(col) ? prev.filter((c) => c !== col) : [...prev, col] ); }; const runAnalysis = async () => { if (selected.length === 0) return; setError(null); setAnalysisRunning(true); try { const res = await api.runAnalysis(selected, { enable_tfidf: enableTfidf, min_cluster_size: minClusterSize, n_neighbors: nNeighbors, min_dist: minDist, }); setAnalysisResults(res); } catch (e: unknown) { setError(e instanceof Error ? e.message : 'Analysis failed'); setAnalysisRunning(false); } }; if (!dataLoaded) { return (

Load a dataset first from the{' '} {' '} or{' '} .

); } const tabs: { id: TabId; label: string; icon: typeof Layers; needsResults: boolean }[] = [ { id: 'clusters', label: 'Clusters', icon: Layers, needsResults: true }, { id: 'correlation', label: 'Correlation', icon: Grid3x3, needsResults: true }, { id: 'xgboost', label: 'Feature Importance', icon: BarChart3, needsResults: true }, { id: 'distribution', label: 'Distribution', icon: BarChart3, needsResults: true }, { id: 'association', label: "Cramér's V Explorer", icon: Network, needsResults: false }, ]; return (
{/* Column selector */}
} >
{columns.map((col) => ( ))}
{selected.length > 0 && (

{selected.length} column{selected.length > 1 ? 's' : ''} selected

)} {showParams && (
setMinClusterSize(Number(e.target.value))} className="w-full accent-accent" />
setNNeighbors(Number(e.target.value))} className="w-full accent-accent" />
setMinDist(Number(e.target.value))} className="w-full accent-accent" />
)} {analysisRunning && } {error && (
{error}
)} {/* Success message */} {results && ( <>
Analysis complete for {Object.keys(results.results).length} column(s)
{results.mock_mode && (
Mock analysis mode is enabled. Outputs are for demo/debugging, not scientific conclusions.
)} )} {/* Tab bar — always available; the Cramér's V explorer needs no analysis run */}
{tabs.map(({ id, label, icon: Icon }) => ( ))}
{/* Association explorer — independent of the cluster pipeline. Its XGBoost run is handed to the Feature Importance tab via handleAssocXgboost. */} {activeTab === 'association' && ( )} {/* Feature importance — independent of the cluster pipeline: it shows the explorer-driven results when present, otherwise the pipeline's. */} {activeTab === 'xgboost' && (() => { const xgb = assocXgboost && Object.keys(assocXgboost).length > 0 ? assocXgboost : results?.xgboost ?? null; if (xgb && Object.keys(xgb).length > 0) { return (
{assocXgboost && Object.keys(assocXgboost).length > 0 && (
Computed directly from your Cramér's V column selection — each column predicted from the others.
)}
); } return (

No feature-importance results yet. Run the cluster pipeline above, or open the{' '} , select columns, and click Feature Importance →.

); })()} {/* Result-dependent tabs */} {activeTab !== 'association' && activeTab !== 'xgboost' && !results && (

Select columns above and click Run Analysis to populate clustering, correlation, feature-importance and distribution views. The{' '} {' '} works directly on raw columns without running the pipeline.

)} {results && ( <> {/* Cluster visualizations */} {activeTab === 'clusters' && (
{Object.entries(results.cluster_viz).map(([col, viz]) => ( ))}
)} {/* Correlation heatmap */} {activeTab === 'correlation' && results.cramers_v && ( )} {activeTab === 'correlation' && !results.cramers_v && (

Select at least 2 columns to compute correlation analysis.

)} {/* Distribution */} {activeTab === 'distribution' && (
{Object.entries(results.results).map(([col, analysis]) => ( ))}
)} )} ); }