Source file real_plot.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
module C = Command
module P = Picture
type ('a, 'b) node = { values : 'b; node : 'a }
type 'a curve = ('a, (float -> float option) list) node
type 'a graph = 'a curve list
let curve_l fl node = { values = fl; node }
let curve_opt f node = curve_l [ f ] node
let curve f node = curve_opt (fun x -> Some (f x)) node
let graph x = x
let rec calc_one_value nb_f ((which_f, acc) as w_acc) x = function
| [] -> (nb_f, None :: acc)
| f :: lf -> (
match f x with
| None -> calc_one_value (nb_f + 1) w_acc x lf
| Some y ->
if which_f = nb_f then (nb_f, Some (x, y) :: acc)
else (nb_f, Some (x, y) :: None :: acc) )
let calc xmin xmax pitch { values = cf; node } =
let rec aux acc = function
| x when x <= xmin -> calc_one_value 0 acc xmin cf
| x -> aux (calc_one_value 0 acc x cf) (x -. pitch)
in
{ values = snd (aux (0, []) xmax); node }
open MetaPath
let cons_opt x l = match x with None -> l | Some x -> to_path x :: l
let rec pathn_opt acc current = function
| [] -> cons_opt current acc
| v :: l -> (
match (v, current) with
| None, _ -> pathn_opt (cons_opt current acc) None l
| Some v, None -> pathn_opt acc (Some (start (knotn v))) l
| Some v, Some c ->
pathn_opt acc (Some (concat ~style:jLine c (knotn v))) l )
let draw_aux ?label:_ values =
C.seq
(List.map
(fun (values, brush) ->
let line = pathn_opt [] None values in
C.seq (List.map (Path.draw ~brush) line))
values)
let ysep = 10
let tick pitch xmax nb =
let rec aux acc x = function
| n when n <= 0 -> acc
| n -> aux (x :: acc) (x -. pitch) (n - 1)
in
aux [] xmax nb
let tick_log xmax =
let rec aux acc = function
| x when x > xmax -> acc
| x -> aux (x :: acc) (x *. 10.)
in
aux [] 1.
let tick_logneg xmin =
let rec aux acc = function
| x when x < xmin -> acc
| x -> aux (x :: acc) (x *. 10.)
in
aux [] (-1.)
let vtick =
let t = Point.bpp (2.5, 0.) in
fun v -> (Point.sub v t, Point.add v t)
let draw_axes ~logarithmic:_ ~ytick ~xmin ~xmax ~ymin ~ymax ~yzero ~xzero
~pitch:_ =
let ytick = C.seq ytick in
let vert =
Arrow.simple (Path.pathn ~style:Path.jLine [ (xzero, ymin); (xzero, ymax) ])
in
let hori =
Arrow.simple (Path.pathn ~style:Path.jLine [ (xmin, yzero); (xmax, yzero) ])
in
C.seq [ ytick; vert; hori ]
let count_max iter =
let y = ref neg_infinity in
iter (fun x -> y := max !y x);
!y
let count_min iter =
let y = ref infinity in
iter (fun x -> y := min !y x);
!y
let filter_opt f l =
{
l with
values =
List.map (function Some (_, y) as p when f y -> p | _ -> None) l.values;
}
let draw ?(logarithmic = false) ?curve_brush:_ ?label ?ymin ?ymax ~xmin ~xmax
~pitch ~width ~height graph =
let values = List.map (calc xmin xmax pitch) graph in
let values =
match (ymin, ymax) with
| None, None -> values
| _ ->
let f =
match (ymin, ymax) with
| None, None -> assert false
| Some ymin, None -> fun f -> f >= ymin
| Some ymin, Some ymax -> fun f -> f >= ymin && f <= ymax
| None, Some ymax -> fun f -> f <= ymax
in
List.map (filter_opt f) values
in
let yvalues f =
List.iter
(fun x -> List.iter (function Some (_, y) -> f y | None -> ()) x.values)
values
in
let ymax = match ymax with None -> count_max yvalues | Some ymax -> ymax in
let ymin = match ymin with None -> count_min yvalues | Some ymin -> ymin in
let ymax = if ymin = ymax then ymin +. 1. else ymax in
let conv =
if logarithmic then fun v ->
if abs_float v < 1. then v
else (log10 (abs_float v) +. 1.) *. (v /. abs_float v)
else fun v -> v
in
let scaley = Num.divn height (Num.bp (conv ymax -. conv ymin)) in
let scalex = Num.divn width (Num.bp (xmax -. xmin)) in
let scalex x = Num.multn (Num.bp (x -. xmin)) scalex in
let scaley y = Num.multn (Num.bp (conv y -. conv ymin)) scaley in
let scale (x, y) = (scalex x, scaley y) in
let scale_opt = function
| Some (x, y) -> Some (scale (x, y))
| None -> None
in
let xzero, yzero = scale (0., 0.) in
let ymm = ymax -. ymin in
let ypitchl =
if logarithmic then
let l1 = tick_log ymax in
let l2 = tick_logneg ymin in
l1 @ l2
else
let ypitch = 10. ** floor (log10 (ymm /. float ysep)) in
let ymax2 = ypitch *. floor (ymax /. ypitch) in
let ysep = int_of_float (ymm /. ypitch) in
tick ypitch ymax2 ysep
in
let ypitchl = (ymin :: ypitchl) @ [ ymax ] in
let ypitchl =
if not Concrete.supported then List.map (fun y -> (y, scaley y)) ypitchl
else
let ex2 = 2. *. Num.ex_factor () in
let _, ypitchl =
List.fold_left
(fun (last, acc) y ->
let yn = scaley y in
let f = Concrete.float_of_num yn in
if abs_float (last -. f) > ex2 then (f, (y, yn) :: acc)
else (last, acc))
(infinity, []) ypitchl
in
ypitchl
in
let zero = scalex 0. in
let ytick =
List.map
(fun (y, yn) ->
let p = Point.pt (zero, yn) in
let p1, p2 = vtick p in
let label = Format.sprintf "{%2.1f}" y in
C.seq
[
C.label ~pos:`West (Picture.tex label) p1;
Path.draw (Path.pathp ~style:Path.jLine [ p1; p2 ]);
])
ypitchl
in
let values =
List.map (fun x -> { x with values = List.map scale_opt x.values }) values
in
let color = Color.color_gen 1. 1. in
let curve_brush _ = Brush.t () in
let colors =
List.map
(fun x ->
let b = curve_brush x.node in
let b, c =
match Brush.color b with
| Some c -> (b, c)
| None ->
let c = color () in
(Brush.t ~color:c ~brush:b (), c)
in
(b, c, x))
values
in
let legend =
match label with
| None -> C.nop
| Some label ->
let legend =
Legend.legend (List.map (fun (_, c, x) -> (c, label x.node)) colors)
in
C.label ~pos:`East legend
(Point.pt (scale (xmax, (ymax +. ymin) /. 2.)))
in
let values = List.map (fun (b, _, x) -> (x.values, b)) colors in
let xmin, ymin = scale (xmin, ymin) in
let xmax, ymax = scale (xmax, ymax) in
let axes =
draw_axes ~logarithmic ~ytick ~xmin ~xmax ~ymin ~ymax ~yzero ~xzero ~pitch
in
C.seq [ axes; draw_aux ?label values; legend ]