(* ================================================================ graphiques.ml – Génération de graphiques SVG Fonctions : courbe_entrainement -> courbe(s) d'apprentissage carte_chaleur -> heatmap pour les filtres convolutifs nuage -> nuage de points 2D avec classes barres -> diagramme en barres ================================================================ *) (* ----------------------------------------------------------------- *) (* Types *) (* ----------------------------------------------------------------- *) type courbe = { points : (float * float) list; legende : string } (* ----------------------------------------------------------------- *) (* Dimensions et couleurs *) (* ----------------------------------------------------------------- *) let largeur = 800 let hauteur = 600 let marge_g = 80 let marge_d = 40 let marge_h = 40 let marge_b = 60 let zone_l = largeur - marge_g - marge_d (* 680 *) let zone_h = hauteur - marge_h - marge_b (* 500 *) let palette = [| "#e41a1c"; "#377eb8"; "#4daf4a"; "#984ea3"; "#ff7f00"; "#ffff33"; "#a65628"; "#f781bf" |] let couleur_val v = let r = max 0 (min 255 (int_of_float (v *. 255.5))) in Printf.sprintf "#%02x%02x%02x" r 0 (255 - r) (* ----------------------------------------------------------------- *) (* Primitives SVG *) (* ----------------------------------------------------------------- *) let balise oc = Printf.fprintf oc "\n\ \n" largeur hauteur largeur hauteur let fermer oc = Printf.fprintf oc "\n" let texte oc x y ancrage taille couleur s = Printf.fprintf oc "%s\n" x y ancrage taille couleur s let ligne oc x1 y1 x2 y2 epaisseur couleur = Printf.fprintf oc "\n" x1 y1 x2 y2 couleur epaisseur let cercle oc cx cy r couleur = Printf.fprintf oc "\n" cx cy r couleur let polygone oc points couleur = Printf.fprintf oc "\n" couleur couleur let polyline oc pts couleur epaisseur = Printf.fprintf oc "\n" couleur epaisseur let rect oc x y w h remplissage = Printf.fprintf oc "\n" x y w h remplissage (* ----------------------------------------------------------------- *) (* Axes *) (* ----------------------------------------------------------------- *) let echelle minv maxv = if maxv = minv then (minv -. 0.5, minv +. 0.5, 0.5) else let r = maxv -. minv in let e = 10. ** floor (log10 r) in let pas = if r /. e >= 5. then e else if r /. e >= 2. then e /. 2. else e /. 5. in let debut = floor (minv /. pas) *. pas in let fin = ceil (maxv /. pas) *. pas in (debut, fin, pas) let trace_axes oc xmin xmax ymin ymax xtitre ytitre = let ax = float marge_g in let bx = float (largeur - marge_d) in let ay = float hauteur -. float marge_b in let by = float marge_h in let (xd, xf, xp) = echelle xmin xmax in let (yd, yf, yp) = echelle ymin ymax in let mx x = ax +. (x -. xd) /. (xf -. xd) *. (bx -. ax) in let my y = ay -. (y -. yd) /. (yf -. yd) *. (ay -. by) in (* cadre *) ligne oc ax ay bx ay 1 "black"; ligne oc ax ay ax by 1 "black"; (* graduation x *) let rec aux_x v = if v > xf +. 1e-9 then () else let px = mx v in ligne oc px ay px (ay +. 6.) 1 "black"; texte oc px (ay +. 20.) "middle" 12 "black" (Printf.sprintf "%.1f" v); aux_x (v +. xp) in aux_x xd; (* graduation y *) let rec aux_y v = if v > yf +. 1e-9 then () else let py = my v in ligne oc ax py (ax -. 6.) py 1 "black"; texte oc (ax -. 8.) (py +. 4.) "end" 12 "black" (Printf.sprintf "%.1f" v); aux_y (v +. yp) in aux_y yd; (* titres *) texte oc (ax +. (bx -. ax) /. 2.) (ay +. 45.) "middle" 14 "black" xtitre; texte oc (ax -. 60.) (ay -. (ay -. by) /. 2.) "middle" 14 "black" ytitre; (* rotation du titre y via transform *) Printf.fprintf oc "%s\n" (ax -. 55.) (ay -. (ay -. by) /. 2.) (ax -. 55.) (ay -. (ay -. by) /. 2.) ytitre; (mx, my, xd, xf, yd, yf) (* ----------------------------------------------------------------- *) (* 1. Courbe d'entraînement *) (* ----------------------------------------------------------------- *) let courbe_entrainement ?(fichier = "courbe.svg") ?(titre = "") ?(xlab = "Itération") ?(ylab = "Erreur") courbes = let oc = open_out fichier in balise oc; let (mx, my, _, _, _, _) = if courbes = [] then ((fun x -> 0.), (fun y -> 0.), 0., 1., 0., 1.) else let xs = List.concat_map (fun c -> List.map fst c.points) courbes in let ys = List.concat_map (fun c -> List.map snd c.points) courbes in let xmin = List.fold_left min max_float xs in let xmax = List.fold_left max (-.max_float) xs in let ymin = List.fold_left min max_float ys in let ymax = List.fold_left max (-.max_float) ys in let xpad = (xmax -. xmin) *. 0.05 in let ypad = (ymax -. ymin) *. 0.1 in trace_axes oc (xmin -. xpad) (xmax +. xpad) (max 0. (ymin -. ypad)) (ymax +. ypad) xlab ylab in if titre <> "" then texte oc (float largeur /. 2.) 25. "middle" 18 "black" titre; List.iteri (fun i c -> let pts = List.map (fun (x, y) -> (mx x, my y)) c.points in polyline oc pts palette.(i mod Array.length palette) 2 ) courbes; let y_leg = float marge_h +. 10. in List.iteri (fun i c -> let x_leg = float (largeur - marge_d + 10) in ligne oc x_leg (y_leg +. float i *. 20.) (x_leg +. 20.) (y_leg +. float i *. 20.) 2 palette.(i mod Array.length palette); texte oc (x_leg +. 25.) (y_leg +. 5. +. float i *. 20.) "start" 12 "black" c.legende ) courbes; fermer oc; close_out oc; Printf.printf " -> graphique sauvegardé : %s\n%!" fichier (* ----------------------------------------------------------------- *) (* 2. Carte de chaleur (heatmap) *) (* ----------------------------------------------------------------- *) let carte_chaleur ?(fichier = "heatmap.svg") ?(titre = "") matrice = let oc = open_out fichier in balise oc; let n_lignes = List.length matrice in let n_cols = if n_lignes = 0 then 0 else List.length (List.hd matrice) in let cote = min (zone_l / max 1 n_cols) (zone_h / max 1 n_lignes) in let cote = min cote 60 in let larg = n_cols * cote in let haut = n_lignes * cote in let ox = float (marge_g + (zone_l - larg) / 2) in let oy = float (marge_h + (zone_h - haut) / 2) in if titre <> "" then texte oc (float largeur /. 2.) 25. "middle" 18 "black" titre; (* valeurs min/max *) let toutes = List.flatten matrice in let vmin = List.fold_left min max_float toutes in let vmax = List.fold_left max (-.max_float) toutes in let plage = if vmax = vmin then 1. else vmax -. vmin in List.iteri (fun i ligne -> List.iteri (fun j v -> let vn = (v -. vmin) /. plage in let r = int_of_float (vn *. 255.) in let b = int_of_float ((1. -. vn) *. 255.) in let col = Printf.sprintf "#%02x%02x%02x" r 0 b in rect oc (ox +. float j *. float cote) (oy +. float i *. float cote) (float cote) (float cote) col ) ligne ) matrice; (* quadrillage *) for i = 0 to n_lignes do ligne oc ox (oy +. float i *. float cote) (ox +. float n_cols *. float cote) (oy +. float i *. float cote) 1 "#ccc" done; for j = 0 to n_cols do ligne oc (ox +. float j *. float cote) oy (ox +. float j *. float cote) (oy +. float n_lignes *. float cote) 1 "#ccc" done; fermer oc; close_out oc; Printf.printf " -> graphique sauvegardé : %s\n%!" fichier (* ----------------------------------------------------------------- *) (* 3. Nuage de points 2D avec classes *) (* ----------------------------------------------------------------- *) let nuage ?(fichier = "nuage.svg") ?(titre = "") ?(xlab = "x") ?(ylab = "y") points_par_classe = let oc = open_out fichier in balise oc; let tous = List.concat points_par_classe in let xs = List.map fst tous in let ys = List.map snd tous in let xmin = List.fold_left min max_float xs in let xmax = List.fold_left max (-.max_float) xs in let ymin = List.fold_left min max_float ys in let ymax = List.fold_left max (-.max_float) ys in let xpad = (xmax -. xmin) *. 0.1 in let ypad = (ymax -. ymin) *. 0.1 in let (mx, my, _, _, _, _) = trace_axes oc (xmin -. xpad) (xmax +. xpad) (ymin -. ypad) (ymax +. ypad) xlab ylab in if titre <> "" then texte oc (float largeur /. 2.) 25. "middle" 18 "black" titre; List.iteri (fun i pts -> let col = palette.(i mod Array.length palette) in List.iter (fun (x, y) -> cercle oc (mx x) (my y) 4. col) pts ) points_par_classe; (* légende *) let y_leg = float marge_h +. 10. in let x_leg = float (largeur - marge_d + 10) in List.iteri (fun i _ -> cercle oc (x_leg +. 5.) (y_leg +. 5. +. float i *. 22.) 4. palette.(i mod Array.length palette); texte oc (x_leg +. 15.) (y_leg +. 8. +. float i *. 22.) "start" 12 "black" (Printf.sprintf "Classe %d" i) ) points_par_classe; fermer oc; close_out oc; Printf.printf " -> graphique sauvegardé : %s\n%!" fichier (* ----------------------------------------------------------------- *) (* 4. Diagramme en barres *) (* ----------------------------------------------------------------- *) let barres ?(fichier = "barres.svg") ?(titre = "") ?(xlab = "") ?(ylab = "") etiquettes valeurs = let oc = open_out fichier in balise oc; let n = List.length valeurs in let ymin = 0. in let ymax = List.fold_left max (-.max_float) valeurs in let ypad = ymax *. 0.1 in let (mx, my, _, _, _, _) = trace_axes oc (-0.5) (float (n - 1) +. 0.5) (ymin -. ypad) (ymax +. ypad) xlab ylab in let ax = float marge_g in let bx = float (largeur - marge_d) in let larg_barre = (bx -. ax) /. float (max 1 n) *. 0.6 in if titre <> "" then texte oc (float largeur /. 2.) 25. "middle" 18 "black" titre; List.iteri (fun i v -> let cx = mx (float i) in let cy = my v in let ay = float hauteur -. float marge_b in let col = palette.(i mod Array.length palette) in rect oc (cx -. larg_barre /. 2.) cy larg_barre (ay -. cy) col; texte oc cx (ay +. 18.) "middle" 11 "black" (try List.nth etiquettes i with _ -> "") ) valeurs; fermer oc; close_out oc; Printf.printf " -> graphique sauvegardé : %s\n%!" fichier (* ----------------------------------------------------------------- *) (* 5. Exemple : courbes depuis un fichier de données *) (* ----------------------------------------------------------------- *) (* Lit des paires (x, y) depuis un fichier, une paire par ligne *) let lit_donnees fichier = let ic = open_in fichier in let rec aux acc = try let ligne = input_line ic in match List.filter (fun s -> s <> "") (String.split_on_char ' ' ligne) with | [x; y] -> aux ((float_of_string x, float_of_string y) :: acc) | _ -> aux acc with _ -> List.rev acc in let res = aux [] in close_in ic; res