summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chart.ml113
-rw-r--r--src/chart.mli5
-rw-r--r--src/marker.ml45
-rw-r--r--src/marker.mli4
-rw-r--r--src/options.ml15
-rw-r--r--src/options.mli4
-rw-r--r--src/utils.ml32
7 files changed, 103 insertions, 115 deletions
diff --git a/src/chart.ml b/src/chart.ml
index 0826092..de79082 100644
--- a/src/chart.ml
+++ b/src/chart.ml
@@ -1,61 +1,66 @@
1let to_string c = String.make 1 c 1let to_string c = String.make 1 c
2
2let space = to_string ' ' 3let space = to_string ' '
4
3let axis = "┬" 5let axis = "┬"
6
4let axis_spc = "─" 7let axis_spc = "─"
5 8
6type t = { vals: int list; opts: Options.t } 9type t = { vals : int list; opts : Options.t }
10
7let default = { vals = []; opts = Options.default } 11let default = { vals = []; opts = Options.default }
8let plot v c = { c with vals = v; } 12
9let with_options v c = { v with opts = c; } 13let plot v c = { c with vals = v }
10let pp channel {vals: int list; opts: Options.t } = 14
11 let open Utils in 15let with_options v c = { c with opts = v }
12 let height = opts.height in 16
13 let min_val = list_min vals in 17let pp formatter { vals : int list; opts : Options.t } =
14 let max_val = list_max vals in 18 let open Utils in
15 let range = max_val - min_val in 19 let height = opts.height in
16 let scale v = ((v - min_val) * height) / range in 20 let min_val = list_min vals in
17 let new_vals = List.map scale vals in 21 let max_val = list_max vals in
18 let rec pad left right s = 22 let range = max_val - min_val in
19 if left = 0 23 let scale v = (v - min_val) * height / range in
20 then s :: repeat right space 24 let new_vals = List.map scale vals in
21 else space :: pad (left - 1) right s 25 let rec pad left right s =
22 in 26 if left = 0 then s :: repeat right space
23 let new_vals' = zip new_vals (List.tl new_vals) in 27 else space :: pad (left - 1) right s
24 let make_marker prefix left right s = 28 in
25 prefix :: 29 let new_vals' = zip new_vals (List.tl new_vals) in
26 (if left = 0 30 let make_marker prefix left right s =
27 then s :: repeat right space 31 prefix
28 else space :: pad (left - 1) right s) 32 ::
29 in 33 (if left = 0 then s :: repeat right space
30 let make_connector s e = 34 else space :: pad (left - 1) right s)
31 match Stdlib.compare s e with 35 in
32 | 0 -> make_marker axis_spc s (height - s) "-" 36 let make_connector s e =
33 | x -> 37 match Stdlib.compare s e with
34 let (ltr_chr, rtl_chr) = 38 | 0 -> make_marker axis_spc s (height - s) "-"
35 match x with 39 | x ->
36 | 1 -> ("└", "┐") 40 let ltr_chr, rtl_chr =
37 | _ -> ("┘", "┌") 41 match x with 1 -> ("└", "┐") | _ -> ("┘", "┌")
38 in
39 let (st, en) = Stdlib.((min s e, max s e)) in
40 let l = en - st |> saturating_sub 1 in
41 let (left, right) = (repeat st space, repeat (height - l - st) space) in
42 List.flatten [[axis_spc]; left; [ltr_chr]; repeat l "│"; [rtl_chr]; right]
43 in 42 in
44 let m = Printf.sprintf opts.marker in 43 let st, en = Stdlib.(min s e, max s e) in
45 let rec make_graph = function 44 let l = en - st |> saturating_sub 1 in
46 | [] -> [] 45 let left, right = (repeat st space, repeat (height - l - st) space) in
47 | (s, e) :: [] -> 46 List.flatten
48 make_marker axis s (height - s) m 47 [
49 :: make_connector s e 48 [ axis_spc ]; left; [ ltr_chr ]; repeat l "│"; [ rtl_chr ]; right;
50 :: make_marker axis e (height - e) m 49 ]
51 :: [] 50 in
52 | (s, e) :: tl -> 51 let m = Format.asprintf "%a" Marker.pp opts.marker in
53 make_marker axis s (height - s) m 52 let rec make_graph = function
54 :: make_connector s e 53 | [] -> []
55 :: make_graph tl 54 | [ (s, e) ] ->
56 in 55 [
57 make_graph new_vals' 56 make_marker axis s (height - s) m;
58 |> rot_left 57 make_connector s e;
59 |> List.map (String.concat "") 58 make_marker axis e (height - e) m;
60 |> String.concat "\n" 59 ]
61 |> Printf.fprintf channel "%s" 60 | (s, e) :: tl ->
61 make_marker axis s (height - s) m :: make_connector s e :: make_graph tl
62 in
63 make_graph new_vals' |> rot_left
64 |> List.map (String.concat "")
65 |> String.concat "\n"
66 |> Format.fprintf formatter "%s"
diff --git a/src/chart.mli b/src/chart.mli
deleted file mode 100644
index 3c758c4..0000000
--- a/src/chart.mli
+++ /dev/null
@@ -1,5 +0,0 @@
1type t
2val default : t
3val plot : int list -> t -> t
4val with_options : Options.t -> t -> t
5val pp : out_channel -> t -> unit
diff --git a/src/marker.ml b/src/marker.ml
index 0c59804..7d37e2a 100644
--- a/src/marker.ml
+++ b/src/marker.ml
@@ -1,27 +1,26 @@
1type t = Point 1type t =
2 | Pixel 2 | Point
3 | Circle 3 | Pixel
4 | TriangleDown 4 | Circle
5 | TriangleUp 5 | TriangleDown
6 | TriangleLeft 6 | TriangleUp
7 | TriangleRight 7 | TriangleLeft
8 | Custom of string 8 | TriangleRight
9 | Custom of string
9 10
10exception Invalid_marker_length 11exception Invalid_marker_length
11let of_string s =
12 if String.length s <> 1
13 then raise Invalid_marker_length
14 else Custom(s)
15 12
16let pp channel n = 13let of_string s =
17 (match n with 14 if String.length s <> 1 then raise Invalid_marker_length else Custom s
18 | Point -> "."
19 | Pixel -> ","
20 | Circle -> "o"
21 | TriangleDown -> "v"
22 | TriangleUp -> "^"
23 | TriangleLeft -> ">"
24 | TriangleRight -> "<"
25 | Custom(s) -> s)
26 |> Printf.fprintf channel "%s"
27 15
16let pp formatter n =
17 (match n with
18 | Point -> "."
19 | Pixel -> ","
20 | Circle -> "o"
21 | TriangleDown -> "v"
22 | TriangleUp -> "^"
23 | TriangleLeft -> ">"
24 | TriangleRight -> "<"
25 | Custom s -> s)
26 |> Format.fprintf formatter "%s"
diff --git a/src/marker.mli b/src/marker.mli
deleted file mode 100644
index 391916b..0000000
--- a/src/marker.mli
+++ /dev/null
@@ -1,4 +0,0 @@
1type t
2val of_string : string -> t
3val pp : out_channel -> t -> unit
4
diff --git a/src/options.ml b/src/options.ml
index a57c28b..341c0bb 100644
--- a/src/options.ml
+++ b/src/options.ml
@@ -1,8 +1,7 @@
1type t = { height: int; ascii: bool; marker: Marker.t} 1type t = { height : int; ascii : bool; marker : Marker.t }
2let default = 2
3 { height = 14 3let default = { height = 14; ascii = false; marker = Marker.Circle }
4 ; ascii = false 4
5 ; marker = Marker.Point 5let with_height v c = { c with height = v }
6 } 6
7let with_height v c = { c with height = v; } 7let with_marker v c = { c with marker = v }
8let with_marker v c = { c with marker = v; }
diff --git a/src/options.mli b/src/options.mli
deleted file mode 100644
index 64bee51..0000000
--- a/src/options.mli
+++ /dev/null
@@ -1,4 +0,0 @@
1type t
2val default : t
3val with_height : int -> t -> t
4val with_marker : Marker.t -> t -> t
diff --git a/src/utils.ml b/src/utils.ml
index 62ae3a5..833c972 100644
--- a/src/utils.ml
+++ b/src/utils.ml
@@ -1,33 +1,31 @@
1exception Empty_list 1exception Empty_list
2
2let fold fn = function 3let fold fn = function
3 | [] -> raise Empty_list 4 | [] -> raise Empty_list
4 | head :: tail -> List.fold_left fn head tail 5 | head :: tail -> List.fold_left fn head tail
5 6
6let list_min ls = fold Stdlib.min ls 7let list_min ls = fold Stdlib.min ls
8
7let list_max ls = fold Stdlib.max ls 9let list_max ls = fold Stdlib.max ls
8 10
9let rec repeat n a = 11let rec repeat n a = if n <= 0 then [] else a :: repeat (n - 1) a
10 if n <= 0
11 then []
12 else a :: repeat (n - 1) a
13 12
14let empty ls = (ls = []) 13let empty ls = ls = []
15 14
16let rec zip l1 l2 = 15let rec zip l1 l2 =
17 match (l1, l2) with 16 match (l1, l2) with
18 | ([], _) -> [] 17 | [], _ -> []
19 | (_, []) -> [] 18 | _, [] -> []
20 | (h1 :: t1, h2 :: t2) -> (h1, h2) :: zip t1 t2 19 | h1 :: t1, h2 :: t2 -> (h1, h2) :: zip t1 t2
21 20
22let rec transpose = function 21let rec transpose = function
23 | [] :: _ -> [] 22 | [] :: _ -> []
24 | ls -> List.(map hd ls) :: transpose List.(map tl ls) 23 | ls -> List.(map hd ls) :: transpose List.(map tl ls)
25 24
26let flip f a b = f b a 25let flip f a b = f b a
27 26
28let rot_right ls = List.(rev ls |> transpose) 27let rot_right ls = List.(rev ls |> transpose)
29let rot_left ls = List.(transpose ls |> rev)
30 28
31let saturating_sub b a = 29let rot_left ls = List.(transpose ls |> rev)
32 if a < b then 0 30
33 else a - b 31let saturating_sub b a = if a < b then 0 else a - b