Testing of the @doc-json output
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

tessera-viz: implement pca_to_rgba

Convert 3-component PCA matrix to false-color RGBA image with
per-component percentile clipping and 0-255 scaling. Optional args
moved before positional to satisfy OCaml's optional-arg resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+97 -5
+30 -3
tessera-viz/lib/viz.ml
··· 17 17 18 18 type color = { r : int; g : int; b : int } 19 19 20 - let pca_to_rgba _mat ~width:_ ~height:_ ?low_pct:_ ?high_pct:_ = 21 - failwith "TODO: pca_to_rgba" 20 + let pca_to_rgba ?(low_pct = 2.0) ?(high_pct = 98.0) ~width ~height mat = 21 + let n_pixels = height * width in 22 + let data = Bigarray.Array1.create Bigarray.int8_unsigned Bigarray.c_layout (n_pixels * 4) in 23 + (* Extract each component column into a float array *) 24 + let comp_values = Array.init 3 (fun c -> 25 + Array.init n_pixels (fun i -> Linalg.mat_get mat i c) 26 + ) in 27 + (* Compute percentile bounds for each component *) 28 + let bounds = Array.init 3 (fun c -> 29 + let lo = percentile comp_values.(c) low_pct in 30 + let hi = percentile comp_values.(c) high_pct in 31 + (lo, hi) 32 + ) in 33 + (* Write pixels *) 34 + for i = 0 to n_pixels - 1 do 35 + let off = i * 4 in 36 + for c = 0 to 2 do 37 + let (lo, hi) = bounds.(c) in 38 + let v = Linalg.mat_get mat i c in 39 + let v = Float.max lo (Float.min hi v) in 40 + let scaled = 41 + if hi -. lo < 1e-12 then 0 42 + else int_of_float ((v -. lo) /. (hi -. lo) *. 255.0) 43 + in 44 + Bigarray.Array1.set data (off + c) (min 255 (max 0 scaled)) 45 + done; 46 + Bigarray.Array1.set data (off + 3) 255 47 + done; 48 + { data; width; height } 22 49 23 50 let color_of_hex _s = 24 51 failwith "TODO: color_of_hex" 25 52 26 - let classification_to_rgba ~predictions:_ ~colors:_ ~width:_ ~height:_ ?alpha:_ = 53 + let classification_to_rgba ?alpha:_ ~predictions:_ ~colors:_ ~width:_ ~height:_ = 27 54 failwith "TODO: classification_to_rgba"
+2 -2
tessera-viz/lib/viz.mli
··· 19 19 20 20 (** {1 PCA visualization} *) 21 21 22 - val pca_to_rgba : Linalg.mat -> width:int -> height:int -> ?low_pct:float -> ?high_pct:float -> rgba_image 22 + val pca_to_rgba : ?low_pct:float -> ?high_pct:float -> width:int -> height:int -> Linalg.mat -> rgba_image 23 23 (** Convert a 3-component PCA result to a false-color RGBA image. 24 24 25 25 Input: mat with shape [(height*width, 3)] from [Linalg.pca_transform]. ··· 38 38 (** Parse a hex color string like ["#ff0000"] or ["ff0000"]. *) 39 39 40 40 val classification_to_rgba : 41 + ?alpha:int -> 41 42 predictions:int array -> 42 43 colors:(int * color) list -> 43 44 width:int -> 44 45 height:int -> 45 - ?alpha:int -> 46 46 rgba_image 47 47 (** Convert class predictions to a colored RGBA image. 48 48
+65
tessera-viz/test/test_viz.ml
··· 20 20 ; Alcotest.test_case "unsorted input" `Quick test_percentile_unsorted 21 21 ] 22 22 23 + let check_pixel msg expected_r expected_g expected_b expected_a (img : Viz.rgba_image) idx = 24 + let off = idx * 4 in 25 + let r = Bigarray.Array1.get img.data off in 26 + let g = Bigarray.Array1.get img.data (off + 1) in 27 + let b = Bigarray.Array1.get img.data (off + 2) in 28 + let a = Bigarray.Array1.get img.data (off + 3) in 29 + Alcotest.(check int) (msg ^ " R") expected_r r; 30 + Alcotest.(check int) (msg ^ " G") expected_g g; 31 + Alcotest.(check int) (msg ^ " B") expected_b b; 32 + Alcotest.(check int) (msg ^ " A") expected_a a 33 + 34 + (* Helper to create a Linalg.mat from float array array (rows x cols) *) 35 + let mat_of_rows rows = 36 + let n_rows = Array.length rows in 37 + let n_cols = Array.length rows.(0) in 38 + let m = Linalg.create_mat ~rows:n_rows ~cols:n_cols in 39 + Array.iteri (fun i row -> 40 + Array.iteri (fun j v -> Linalg.mat_set m i j v) row 41 + ) rows; 42 + m 43 + 44 + let test_pca_all_zero () = 45 + (* 2x2 image, 3 components all zero *) 46 + let mat = mat_of_rows [| [|0.0; 0.0; 0.0|]; [|0.0; 0.0; 0.0|]; 47 + [|0.0; 0.0; 0.0|]; [|0.0; 0.0; 0.0|] |] in 48 + let img = Viz.pca_to_rgba ~width:2 ~height:2 mat in 49 + Alcotest.(check int) "width" 2 img.width; 50 + Alcotest.(check int) "height" 2 img.height; 51 + Alcotest.(check int) "data length" (2 * 2 * 4) (Bigarray.Array1.dim img.data); 52 + for i = 0 to 3 do 53 + check_pixel (Printf.sprintf "pixel %d" i) 0 0 0 255 img i 54 + done 55 + 56 + let test_pca_varying_r () = 57 + (* 2x2 image: component 0 varies, components 1,2 constant *) 58 + let mat = mat_of_rows [| [|0.0; 50.0; 50.0|]; [|100.0; 50.0; 50.0|]; 59 + [|50.0; 50.0; 50.0|]; [|75.0; 50.0; 50.0|] |] in 60 + let img = Viz.pca_to_rgba ~low_pct:0.0 ~high_pct:100.0 ~width:2 ~height:2 mat in 61 + (* R channel should vary, G and B should be uniform *) 62 + let r0 = Bigarray.Array1.get img.data 0 in 63 + let r1 = Bigarray.Array1.get img.data 4 in 64 + Alcotest.(check bool) "R varies" true (r0 <> r1); 65 + (* G should be same for all pixels (component 1 is constant) *) 66 + let g0 = Bigarray.Array1.get img.data 1 in 67 + let g1 = Bigarray.Array1.get img.data 5 in 68 + let g2 = Bigarray.Array1.get img.data 9 in 69 + let g3 = Bigarray.Array1.get img.data 13 in 70 + Alcotest.(check int) "G uniform 0-1" g0 g1; 71 + Alcotest.(check int) "G uniform 1-2" g1 g2; 72 + Alcotest.(check int) "G uniform 2-3" g2 g3 73 + 74 + let test_pca_data_length () = 75 + let mat = mat_of_rows [| [|1.0; 2.0; 3.0|]; [|4.0; 5.0; 6.0|]; 76 + [|7.0; 8.0; 9.0|]; [|10.0; 11.0; 12.0|]; 77 + [|13.0; 14.0; 15.0|]; [|16.0; 17.0; 18.0|] |] in 78 + let img = Viz.pca_to_rgba ~width:3 ~height:2 mat in 79 + Alcotest.(check int) "data length" (3 * 2 * 4) (Bigarray.Array1.dim img.data) 80 + 81 + let pca_tests = 82 + [ Alcotest.test_case "all zero" `Quick test_pca_all_zero 83 + ; Alcotest.test_case "varying R channel" `Quick test_pca_varying_r 84 + ; Alcotest.test_case "data length" `Quick test_pca_data_length 85 + ] 86 + 23 87 let () = 24 88 Alcotest.run "tessera-viz" 25 89 [ ("percentile", percentile_tests) 90 + ; ("pca_to_rgba", pca_tests) 26 91 ]