feat(clustering): dégradé HSL multi-stop basé sur le score de non-humanité
Remplace la palette par index par un dégradé continu HSL : - risk=0.0 → hue 220° (bleu froid — humain légitime) - risk=0.25 → hue 165° (cyan-vert — légèrement suspect) - risk=0.50 → hue 110° (vert-jaune — comportement mixte) - risk=0.75 → hue 55° (jaune-orange — probable bot) - risk=1.0 → hue 0° (rouge vif — bot confirmé) Saturation : 70%→90%, Lightness : 58%→48% (couleur plus intense = plus alarmant) Légende : barre de dégradé 'Humain ← → Bot' avec stops HSL alignés Suppression de spread_clusters (chevauchement des zones autorisé) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -24,7 +24,7 @@ from ..services.clustering_engine import (
|
||||
FEATURE_KEYS, FEATURE_NAMES, FEATURE_NORMS, N_FEATURES,
|
||||
build_feature_vector, kmeans_pp, pca_2d, compute_hulls,
|
||||
name_cluster, risk_score_from_centroid, standardize,
|
||||
cluster_color, spread_clusters,
|
||||
risk_to_gradient_color,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -196,11 +196,7 @@ def _run_clustering_job(k: int, hours: int, sensitivity: float = 1.0) -> None:
|
||||
# ── 5. PCA-2D sur les features ORIGINALES (normalisées [0,1]) ────
|
||||
coords = pca_2d(X64) # (n, 2), normalisé [0,1]
|
||||
|
||||
# ── 5b. Dispersion — repousse les clusters trop proches ──────────
|
||||
coords = spread_clusters(coords, km.labels, k_actual,
|
||||
n_iter=60, min_dist=0.16)
|
||||
|
||||
# ── 5c. Enveloppes convexes par cluster ──────────────────────────
|
||||
# ── 5b. Enveloppes convexes par cluster ──────────────────────────
|
||||
hulls = compute_hulls(coords, km.labels, k_actual)
|
||||
|
||||
# ── 6. Agrégation par cluster ─────────────────────────────────────
|
||||
@ -237,7 +233,7 @@ def _run_clustering_job(k: int, hours: int, sensitivity: float = 1.0) -> None:
|
||||
raw_stats = {"mean_ttl": mean_ttl, "mean_mss": mean_mss, "mean_scale": mean_scale}
|
||||
label_name = name_cluster(centroids_orig[j], raw_stats)
|
||||
risk = float(risk_score_from_centroid(centroids_orig[j]))
|
||||
color = cluster_color(j)
|
||||
color = risk_to_gradient_color(risk)
|
||||
|
||||
# Centroïde 2D = moyenne des coords du cluster
|
||||
cxy = np.mean(cluster_coords[j], axis=0).tolist() if cluster_coords[j] else [0.5, 0.5]
|
||||
|
||||
Reference in New Issue
Block a user