package mlpost

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file hist.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
(**************************************************************************)
(*                                                                        *)
(*  Copyright (C) Johannes Kanig, Stephane Lescuyer                       *)
(*  Jean-Christophe Filliatre, Romain Bardou and Francois Bobot           *)
(*                                                                        *)
(*  This software is free software; you can redistribute it and/or        *)
(*  modify it under the terms of the GNU Library General Public           *)
(*  License version 2.1, with the special exception on linking            *)
(*  described in file LICENSE.                                            *)
(*                                                                        *)
(*  This software is distributed in the hope that it will be useful,      *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  *)
(*                                                                        *)
(**************************************************************************)

open Command
open Color
open Box
open Num
open Point
open Path

type 'a labels = Values | User of 'a list

type path_3D =
  | Prems of (Path.t * Path.t * Color.t)
  | PasPrems of (Path.t * Color.t)

module Q = Misc.Q

let max l =
  let rec max_aux acc = function
    | [] -> acc
    | x :: res -> if x > acc then max_aux x res else max_aux acc res
  in
  max_aux (List.hd l) l

let maxlist l =
  let rec max_aux acc = function
    | [] -> acc
    | x :: res ->
        let m = max x in
        if m > acc then max_aux m res else max_aux acc res
  in
  max_aux (max (List.hd l)) l

(* Valeur maximale dans un histogramme cumulé *)
let maxcumul l =
  let rec list_aux acc l =
    match l with
    | [] -> acc
    | x :: res ->
        list_aux (List.fold_left (fun acc x -> acc +. x) 0. x :: acc) res
  in
  max (list_aux [] l)

(* Ne fonctionne que si b est une hbox qui contient au moins une boite *)
let move_hbox _cumul cpt scalex b =
  let p = Box.south_west b in
  Box.shift
    (Point.pt (multf (float cpt) scalex, zero))
    (Box.shift (Point.sub Point.origin p) b)

let default_vlabel i _ = Some (Picture.tex (string_of_int i))

let laxe ~nbcol ?(vlabel = default_vlabel) padding scalex scaley hcaption
    vcaption valmax nbval =
  let hlabel _ _ = None in
  let axe =
    Plot.mk_skeleton (nbval / nbcol) (int_of_float valmax)
      (addn (multf (float nbcol) scalex) padding)
      scaley
  in
  Plot.draw_axes ?hcaption ?vcaption ~vlabel ~hlabel ~ticks:None axe

let rec draw_perspect acc = function
  | Prems (p1, p2, c) :: r ->
      draw_perspect
        ( fill ~color:c p1 ++ fill ~color:c p2 ++ Command.draw p1
        ++ Command.draw p2 ++ acc )
        r
  | PasPrems (p, c) :: r ->
      draw_perspect (fill ~color:c p ++ Command.draw p ++ acc) r
  | [] -> acc

(* Construit les composantes 3D à partir d'un vecteur, d'une boite et d'une couleur *)
let perspect scale derns b c =
  let c = match c with None -> Color.white | Some i -> i in
  let nw = north_west b in
  let ne = north_east b in
  let se = south_east b in
  let dep = divf scale 3. in
  let p1 =
    [
      nw;
      ne;
      pt (addn (xpart ne) dep, addn (ypart ne) dep);
      pt (addn (xpart nw) dep, addn (ypart nw) dep);
    ]
  in
  let p2 =
    [
      ne;
      se;
      pt (addn (xpart se) dep, addn (ypart se) dep);
      pt (addn (xpart ne) dep, addn (ypart ne) dep);
    ]
  in
  let path1 = pathp ~cycle:jLine ~style:jLine p1 in
  let path2 = pathp ~cycle:jLine ~style:jLine p2 in
  (* (fill ~color:c path1) ++ (fill ~color:c path2) ++  *)
  (*       (Command.draw path1) ++ (Command.draw path2) *)
  if derns then Prems (path1, path2, c) else PasPrems (path2, c)

let rec mk_perspect2 acc prems scale hb i j l =
  match l with
  | _ :: res ->
      let b = Box.nth j (Box.nth i hb) in
      let paths = perspect scale prems b (get_fill b) in
      mk_perspect2 (paths :: acc) false scale hb i (j + 1) res
  | [] -> acc

let box_perspect scale hb l =
  let rec mk_perspect acc scale hb i l =
    match l with
    | x :: res ->
        mk_perspect
          (mk_perspect2 [] true scale hb i 0 x @ acc)
          scale hb (i + 1) res
    | [] -> acc
  in
  mk_perspect [] scale hb 0 l

(* Gère la position du label pour qu'elle soit cohérente *)
let label_direction poslab x =
  match Types.vreduce poslab with
  | `North -> if x < 0. then (`South, Box.south) else (`South, Box.north)
  | `South -> if x < 0. then (`North, Box.south) else (`South, Box.north)
  | `Center -> (`Center, Box.ctr)

let rec mk_labels2 acc poslab i j hb l l2 =
  match (l, l2) with
  | x :: res, x2 :: res2 ->
      let sens, haut = label_direction poslab x2 in
      let b = Box.nth j (Box.nth i hb) in
      mk_labels2
        (acc ++ Command.label ~pos:sens x (haut b))
        poslab i (j + 1) hb res res2
  | [], [] -> acc
  | _, _ -> failwith "Both datas and labels lists must have the same size"

(* Positionne les labels sur chaque élément de l'histogramme *)
let box_labels lab hb l =
  let rec mk_labels acc poslab i hb l l2 =
    match (l, l2) with
    | x :: res, x2 :: res2 ->
        mk_labels
          ( acc
          ++ mk_labels2 Command.nop poslab i 0 hb (List.rev x) (List.rev x2) )
          poslab (i + 1) hb res res2
    | [], [] -> acc
    | _, _ -> failwith "Both datas and labels lists must have the same size"
  in
  match lab with
  | poslab, Values ->
      let picl2 l = List.map (fun x -> Picture.tex (string_of_float x)) l in
      let picl l = List.map (fun x -> picl2 x) l in
      mk_labels nop poslab 0 hb (picl l) l
  | poslab, User pl -> mk_labels nop poslab 0 hb pl l

(* Positionne les labels sous chaque barre *)
let hist_labels hlab hb =
  let rec mk_labels acc i hlab =
    match hlab with
    | x :: res ->
        mk_labels
          (acc ++ (Command.label ~pos:`South x) (Box.south (Box.nth i hb)))
          (i + 1) res
    | [] -> acc
  in
  mk_labels nop 0 hlab

(* Fonction de dessin d'histogramme *)
let hist ~cumul _width _height padding fill perspective scalex scaley ?histlabel
    ?hlabel cpt l =
  let rec consvbox boxs = function
    | [], cq -> (vbox boxs, cq)
    | x :: res, cq ->
        let c, cq = Q.pop cq in
        let b =
          set_fill c
            (set_stroke black (empty ~width:scalex ~height:(multf x scaley) ()))
        in
        consvbox (b :: boxs) (res, Q.push c cq)
  in
  let rec fct_hist boxs = function
    | [], _ -> hbox ~pos:`South ~padding (List.rev boxs)
    | x :: res, collist ->
        let lavbox, listcol = consvbox [] (x, collist) in
        fct_hist (lavbox :: boxs) (res, if cumul then collist else listcol)
  in
  let fcth = fct_hist [] (l, fill) in
  let hb = move_hbox cumul cpt scalex fcth in
  let persp =
    if perspective then draw_perspect nop (box_perspect scalex hb l) else nop
  in
  let labels =
    match histlabel with None -> nop | Some lab -> box_labels lab hb l
  in
  persp ++ Box.draw hb ++ labels
  ++ match hlabel with None -> nop | Some hlab -> hist_labels hlab hb

let drawing_parameters width height ?padding nbval valmax nbcol =
  let padding =
    match padding with None -> divf width (4. *. float nbval) | Some i -> i
  in
  let scalex =
    divf
      (subn width (multf (float ((nbval - 1) / nbcol)) padding))
      (float nbval)
  in
  let scaley = divf height valmax in
  (scalex, scaley, padding)

(* Histogramme classique *)
let simple ?(width = bp 100.) ?(height = bp 200.) ?padding
    ?(fill = [ lightblue ]) ?(perspective = false) ?hcaption ?vcaption
    ?histlabel ?vlabel ?hlabel l =
  let histlabel =
    match histlabel with
    | None -> None
    | Some (_, Values) as h -> h
    | Some (p, User l) -> Some (p, User (List.map (fun x -> [ x ]) l))
  in
  let valmax = max l in
  let nbval = List.length l in
  let scalex, scaley, padding =
    drawing_parameters width height ?padding nbval valmax 1
  in
  let cq = Q.of_list fill in
  let l = List.map (fun x -> [ x ]) l in
  hist ~cumul:false width height padding cq perspective scalex scaley ?histlabel
    ?hlabel 0 l
  ++ laxe ~nbcol:1 padding scalex scaley hcaption vcaption valmax nbval ?vlabel

(* Histogramme de comparaison *)
let compare ?(width = bp 100.) ?(height = bp 200.) ?padding
    ?(fill = [ lightblue; red ]) ?(perspective = false) ?hcaption ?vcaption
    ?histlabel ?vlabel ?hlabel l =
  let nblist = List.length l in
  let valmax = maxlist l in
  let nbval = List.fold_left (fun acc x -> List.length x + acc) 0 l in
  let scalex, scaley, padding =
    drawing_parameters width height ?padding nbval valmax nblist
  in
  let rec fct_hist bhlabel c cpt = function
    | [], _ -> c
    | x :: res, cq ->
        let col, rescol = Q.pop cq in
        let x = List.map (fun x -> [ x ]) x in
        if bhlabel then
          fct_hist false
            ( c
            ++ hist ?hlabel ?histlabel ~cumul:false width height
                 (addn padding (multn (bp (float_of_int (nblist - 1))) scalex))
                 (Q.push col Q.empty) perspective scalex scaley cpt x )
            (cpt + 1)
            (res, Q.push col rescol)
        else
          fct_hist false
            ( c
            ++ hist ?histlabel ~cumul:false width height
                 (addn padding (multn (bp (float_of_int (nblist - 1))) scalex))
                 (Q.push col Q.empty) perspective scalex scaley cpt x )
            (cpt + 1)
            (res, Q.push col rescol)
  in
  fct_hist true nop 0 (l, Q.of_list fill)
  ++ laxe ~nbcol:nblist padding scalex scaley hcaption vcaption valmax nbval
       ?vlabel

(* Histogramme cumulé *)
let stack ?(width = bp 100.) ?(height = bp 200.) ?padding
    ?(fill = [ lightblue; red; green ]) ?(perspective = false) ?hcaption
    ?vcaption ?histlabel ?vlabel ?hlabel l =
  let nblist = List.length l in
  let valmax = maxcumul l in
  let nbval = nblist in
  let scalex, scaley, padding =
    drawing_parameters width height ?padding nbval valmax 1
  in
  hist ~cumul:true width height padding (Q.of_list fill) perspective scalex
    scaley ?histlabel ?hlabel 0 l
  ++ laxe ~nbcol:1 padding scalex scaley hcaption vcaption valmax nbval ?vlabel