Spaces:
Sleeping
Sleeping
Download frontend/src/components/TuningPanel.js from Ilaa-1505/Error-Clustering-System: direct link, hf CLI and curl.
- Browser
- Download file 9.18 kB
-
https://huggingface.co/spaces/Ilaa-1505/Error-Clustering-System/resolve/main/frontend/src/components/TuningPanel.js
- Command line
-
hf download hf://spaces/Ilaa-1505/Error-Clustering-System/frontend/src/components/TuningPanel.js
-
curl -L -o TuningPanel.js https://huggingface.co/spaces/Ilaa-1505/Error-Clustering-System/resolve/main/frontend/src/components/TuningPanel.js
9.18 kB
| import { useState } from 'react'; | |
| import { BarChart, Bar, XAxis, YAxis, Tooltip, Cell, ResponsiveContainer } from 'recharts'; | |
| export default function TuningPanel({ | |
| tuningResult, | |
| tuning, | |
| loading, | |
| bestSize, | |
| setBestSize, | |
| onRun, | |
| }) { | |
| const [showFormula, setShowFormula] = useState(false); | |
| const best = tuningResult?.reduce((prev, curr) => | |
| curr.silhouette_score > prev.silhouette_score ? curr : prev | |
| ); | |
| const CustomTooltip = ({ active, payload }) => { | |
| if (!active || !payload?.length) return null; | |
| const d = payload[0].payload; | |
| return ( | |
| <div className="tooltip-box"> | |
| <div style={{ color: 'var(--accent)', marginBottom: 4 }}> | |
| min_cluster_size = {d.min_cluster_size} | |
| </div> | |
| <div>Clusters: {d.n_clusters}</div> | |
| <div>Noise points: {d.n_noise}</div> | |
| <div>Silhouette: {d.silhouette_score}</div> | |
| {d.min_cluster_size === best?.min_cluster_size && ( | |
| <div style={{ color: 'var(--low)', marginTop: 4 }}>β Best</div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| return ( | |
| <div className="panel fade-in"> | |
| <div className="panel-header"> | |
| <span className="panel-title">CLUSTER SIZE TUNING</span> | |
| <div className="panel-actions"> | |
| <button | |
| className="btn-ghost" | |
| onClick={() => setShowFormula(!showFormula)} | |
| > | |
| {showFormula ? 'Hide Formula' : 'Silhouette Formula'} | |
| </button> | |
| </div> | |
| </div> | |
| {showFormula && ( | |
| <div className="formula-box"> | |
| <div className="formula-title">SILHOUETTE SCORE β s(i)</div> | |
| <div className="formula"> | |
| s(i) = ( b(i) β a(i) ) / max( a(i), b(i) ) | |
| </div> | |
| <div className="formula-legend"> | |
| <div className="formula-item"> | |
| <span className="formula-var">a(i)</span> | |
| <span className="formula-desc">mean distance from point i to all other points in its own cluster β measures cohesion. Lower = tighter cluster.</span> | |
| </div> | |
| <div className="formula-item"> | |
| <span className="formula-var">b(i)</span> | |
| <span className="formula-desc">mean distance from point i to all points in the nearest other cluster β measures separation. Higher = more distinct clusters.</span> | |
| </div> | |
| <div className="formula-item"> | |
| <span className="formula-var">s β +1</span> | |
| <span className="formula-desc">point is well inside its cluster, far from others. Good.</span> | |
| </div> | |
| <div className="formula-item"> | |
| <span className="formula-var">s β 0</span> | |
| <span className="formula-desc">point is on the boundary between two clusters. Ambiguous.</span> | |
| </div> | |
| <div className="formula-item"> | |
| <span className="formula-var">s β -1</span> | |
| <span className="formula-desc">point is closer to another cluster than its own. Misclassified.</span> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| {tuning && ( | |
| <div style={{ padding: '16px', color: 'var(--text-dim)', fontFamily: 'var(--font-mono)', fontSize: 12 }}> | |
| Testing cluster sizes 2, 3, 5, 8, 10, 15, 20, 30... | |
| </div> | |
| )} | |
| {tuningResult && !tuning && ( | |
| <div className="tuning-results"> | |
| <div className="tuning-best"> | |
| <span className="tuning-best-label">BEST SIZE</span> | |
| <input | |
| type="number" | |
| className="setting-input" | |
| value={bestSize ?? ''} | |
| min={2} | |
| max={50} | |
| onChange={e => setBestSize(Number(e.target.value))} | |
| style={{ width: 64, textAlign: 'center' }} | |
| /> | |
| <span className="tuning-best-meta"> | |
| {best.n_clusters} clusters Β· {best.n_noise} noise Β· silhouette {best.silhouette_score} | |
| </span> | |
| <button | |
| className="btn-primary" | |
| onClick={onRun} | |
| disabled={loading || bestSize == null} | |
| style={{ marginLeft: 'auto' }} | |
| > | |
| {loading ? 'Running...' : 'Run Clustering'} | |
| </button> | |
| </div> | |
| <ResponsiveContainer width="100%" height={200}> | |
| <BarChart | |
| data={tuningResult} | |
| margin={{ top: 8, right: 24, bottom: 8, left: 0 }} | |
| > | |
| <XAxis | |
| dataKey="min_cluster_size" | |
| tick={{ fill: 'var(--text-dim)', fontSize: 10, fontFamily: 'var(--font-mono)' }} | |
| axisLine={{ stroke: 'var(--border)' }} | |
| tickLine={false} | |
| label={{ value: 'min_cluster_size', position: 'insideBottom', offset: -4, fill: 'var(--text-dim)', fontSize: 9 }} | |
| /> | |
| <YAxis | |
| domain={[0, 1]} | |
| tick={{ fill: 'var(--text-dim)', fontSize: 10, fontFamily: 'var(--font-mono)' }} | |
| axisLine={{ stroke: 'var(--border)' }} | |
| tickLine={false} | |
| label={{ value: 'silhouette', angle: -90, position: 'insideLeft', fill: 'var(--text-dim)', fontSize: 9 }} | |
| /> | |
| <Tooltip content={<CustomTooltip />} /> | |
| <Bar dataKey="silhouette_score" radius={[3, 3, 0, 0]}> | |
| {tuningResult.map((entry, i) => ( | |
| <Cell | |
| key={i} | |
| fill={entry.min_cluster_size === best.min_cluster_size | |
| ? 'var(--low)' | |
| : 'var(--bg-3)'} | |
| stroke={entry.min_cluster_size === best.min_cluster_size | |
| ? 'var(--low)' | |
| : 'var(--border)'} | |
| strokeWidth={1} | |
| /> | |
| ))} | |
| </Bar> | |
| </BarChart> | |
| </ResponsiveContainer> | |
| <div className="tuning-table"> | |
| <div className="tuning-row tuning-header"> | |
| <span>SIZE</span> | |
| <span>CLUSTERS</span> | |
| <span>NOISE</span> | |
| <span>SILHOUETTE</span> | |
| </div> | |
| {tuningResult.map(r => ( | |
| <div | |
| key={r.min_cluster_size} | |
| className="tuning-row" | |
| style={{ | |
| background: r.min_cluster_size === best.min_cluster_size | |
| ? 'rgba(34, 197, 94, 0.05)' | |
| : 'transparent', | |
| borderLeft: r.min_cluster_size === best.min_cluster_size | |
| ? '2px solid var(--low)' | |
| : '2px solid transparent', | |
| }} | |
| > | |
| <span style={{ color: r.min_cluster_size === best.min_cluster_size ? 'var(--low)' : 'var(--text)' }}> | |
| {r.min_cluster_size} | |
| {r.min_cluster_size === best.min_cluster_size && ' β '} | |
| </span> | |
| <span>{r.n_clusters}</span> | |
| <span>{r.n_noise}</span> | |
| <span>{r.silhouette_score}</span> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } |