From 3518a9d0cf1731dd1e9acef988cad583e5ae1653 Mon Sep 17 00:00:00 2001 From: Jonas Brock-Hanash <1080933+jonas-bh@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:16:28 +0100 Subject: [PATCH 1/2] Add axis configuration --- jsoo/jsoo.ml | 5 ++++- python/python.ml | 4 ++++ src/base.ml | 29 ++++++++++++++++++----------- src/base.mli | 4 +++- src/demo/demo.ml | 14 ++++++++++++++ src/plotly.ml | 12 ++++++++++++ src/plotly.mli | 35 ++++++++++++++++++++++++++++++++++- 7 files changed, 89 insertions(+), 14 deletions(-) diff --git a/jsoo/jsoo.ml b/jsoo/jsoo.ml index d21267d..1a0e4ea 100644 --- a/jsoo/jsoo.ml +++ b/jsoo/jsoo.ml @@ -13,8 +13,10 @@ let rec conv_value v = | Value (Array ty, vs) -> let vs = Array.map (fun v -> conv_value (Value (ty, v))) vs in Js.Unsafe.inject @@ Js.array vs + | Object kvs -> + let obj = Js.Unsafe.obj (Array.of_list @@ List.map (fun (k, v) -> (k, conv_value v)) kvs) in + Js.Unsafe.inject obj | Value (Object, obj) -> of_json_value (obj : Ezjsonm.value) - and of_json_value (j : Ezjsonm.value) : _ Js.t = match (j : Ezjsonm.value) with | `String s -> Js.Unsafe.inject @@ Js.string s @@ -26,6 +28,7 @@ and of_json_value (j : Ezjsonm.value) : _ Js.t = Js.Unsafe.obj @@ Array.of_list @@ List.map (fun (k, v) -> (k, of_json_value v)) kvs + let obj_of_attributes (xs : Attribute.t list) : _ Js.t = Js.Unsafe.obj @@ Array.of_list @@ diff --git a/python/python.ml b/python/python.ml index 7afe95c..41c3950 100644 --- a/python/python.ml +++ b/python/python.ml @@ -8,6 +8,10 @@ let rec of_value v = | Value (Bool, b) -> Py.Bool.of_bool b | Value (Array ty, vs) -> Py.List.of_array @@ Array.map (fun v -> of_value (Value (ty, v))) vs + | Object kvs -> + let d = Py.Dict.create () in + List.iter (fun (k, v) -> Py.Dict.set_item d (Py.String.of_string k) (of_value v)) kvs; + d | Value (Object, obj) -> of_json_value (obj : Ezjsonm.value) and of_json_value (j : Ezjsonm.value) : Py.Object.t = diff --git a/src/base.ml b/src/base.ml index 2d3b7a3..ec6f997 100644 --- a/src/base.ml +++ b/src/base.ml @@ -27,7 +27,9 @@ end module Value = struct type 'a t = 'a Type.t * 'a - type value = Value : 'a t -> value + type value = + | Value : 'a t -> value + | Object : (string * value) list -> value let float f : float t = Type.Float, f let string s : string t = Type.String, s @@ -42,6 +44,7 @@ module Value = struct | Value (Bool, b) -> `Bool b | Value (Object, obj) -> obj | Value (Array ty, xs) -> `A (List.map (fun x -> to_json (Value (ty, x))) @@ Array.to_list xs) + | Object kvs -> `O (List.map (fun (k, v) -> k, to_json v) kvs) let rec of_json v = let open Option in @@ -55,16 +58,20 @@ module Value = struct (match vs with | [] -> None | v::vs -> - let Value (ty, _) = v in - let rec check acc = function - | [] -> Some (Value (Type.Array ty, Array.of_list @@ List.rev acc)) - | v'::vs -> - let Value (ty', v') = v' in - match Type.eq ty ty' with - | Some Eq -> check (v'::acc) vs - | None -> None - in - check [] (v::vs)) + (match v with + | Value (ty, _) -> + let rec check acc = function + | [] -> Some (Value (Type.Array ty, Array.of_list @@ List.rev acc)) + | v'::vs -> + (match v' with + | Value (ty', v') -> + (match Type.eq ty ty' with + | Some Eq -> check (v'::acc) vs + | None -> None) + | Object _ -> None) + in + check [] (v::vs) + | Object _ -> None)) | _ -> None end diff --git a/src/base.mli b/src/base.mli index 19157f8..ff57697 100644 --- a/src/base.mli +++ b/src/base.mli @@ -11,7 +11,9 @@ end module Value : sig type 'a t = 'a Type.t * 'a - type value = Value : 'a t -> value + type value = + | Value : 'a t -> value + | Object : (string * value) list -> value val float : float -> float t val string : string -> string t diff --git a/src/demo/demo.ml b/src/demo/demo.ml index 0e9f491..d2f578e 100644 --- a/src/demo/demo.ml +++ b/src/demo/demo.ml @@ -3,6 +3,8 @@ open Data open Graph open Figure open Layout +open Axis + let scatter_ = figure @@ -109,6 +111,17 @@ let histogram_ = [ histogram [ x (Array.init 500 (fun _ -> Random.float 1.0)) ] ] [ title "Histogram" ] +let scatter_with_axes = + let x_data = [| 1.0; 2.0; 3.0; 4.0; 5.0 |] in + let y_data = [| 1.0; 4.0; 9.0; 16.0; 25.0 |] in + figure + [ scatter [ x x_data; y y_data; mode "lines+markers" ] ] + [ + title "Data with Custom Axis Labels"; + xaxis [axis_title "Time (seconds)"; axis_type "linear"]; + yaxis [axis_title "Distance (meters)"; axis_range 0. 30.]; + ] + let figures = [ scatter_; scatter_markers; @@ -121,4 +134,5 @@ let figures = bar_stack_horizontal; pie_; histogram_; + scatter_with_axes; ] diff --git a/src/plotly.ml b/src/plotly.ml index a17c5d1..57dc3d0 100644 --- a/src/plotly.ml +++ b/src/plotly.ml @@ -47,6 +47,18 @@ module Layout = struct let title = string "title" let barmode = string "barmode" let showlegend = bool "showlegend" + module Axis = struct + let axis_title s = ("title", Base.Value.Value (Base.Value.string s)) + let axis_type s = ("type", Base.Value.Value (Base.Value.string s)) + let axis_range low high = ("range", Base.Value.Value (Base.Value.array Base.Type.Float [|low; high|])) + let axis_showgrid b = ("showgrid", Base.Value.Value (Base.Value.bool b)) + let axis_zeroline b = ("zeroline", Base.Value.Value (Base.Value.bool b)) + let axis_tickformat s = ("tickformat", Base.Value.Value (Base.Value.string s)) + end + + let xaxis ax = [("xaxis", Base.Value.Object ax)] + let yaxis ay = [("yaxis", Base.Value.Object ay)] + let zaxis az = [("zaxis", Base.Value.Object az)] let layout ats = ats diff --git a/src/plotly.mli b/src/plotly.mli index 72e5a43..9dc66ec 100644 --- a/src/plotly.mli +++ b/src/plotly.mli @@ -11,7 +11,10 @@ end module Value : sig type 'a t = 'a Type.t * 'a - type value = Value : 'a t -> value + type value = + | Value : 'a t -> value + | Object : (string * value) list -> value + val float : float -> float t val string : string -> string t val bool : bool -> bool t @@ -99,6 +102,36 @@ module Layout : sig val barmode : string -> t val showlegend : bool -> t + (** Axis configuration module for x-, y-, and z-axes *) + module Axis : sig + (** Set axis title *) + val axis_title : string -> string * Base.Value.value + + (** Set axis type (e.g., "linear", "log") *) + val axis_type : string -> string * Base.Value.value + + (** Set axis range as (min, max) *) + val axis_range : float -> float -> string * Base.Value.value + + (** Toggle grid display *) + val axis_showgrid : bool -> string * Base.Value.value + + (** Toggle zero line display *) + val axis_zeroline : bool -> string * Base.Value.value + + (** Set tick label format *) + val axis_tickformat : string -> string * Base.Value.value + end + + (** Configure the x-axis from a list of axis properties *) + val xaxis : (string * Base.Value.value) list -> t + + (** Configure the y-axis from a list of axis properties *) + val yaxis : (string * Base.Value.value) list -> t + + (** Configure the z-axis from a list of axis properties *) + val zaxis : (string * Base.Value.value) list -> t + (* Build custom layout attributes *) val layout : Attribute.t list -> t From b89f17593c127f195365c0265ba95928686e4fc4 Mon Sep 17 00:00:00 2001 From: Jonas Brock-Hanash <1080933+jonas-bh@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:50:42 +0100 Subject: [PATCH 2/2] Update ocamldoc --- jsoo/jsoo.ml | 1 - src/plotly.mli | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/jsoo/jsoo.ml b/jsoo/jsoo.ml index 1a0e4ea..85081bf 100644 --- a/jsoo/jsoo.ml +++ b/jsoo/jsoo.ml @@ -28,7 +28,6 @@ and of_json_value (j : Ezjsonm.value) : _ Js.t = Js.Unsafe.obj @@ Array.of_list @@ List.map (fun (k, v) -> (k, of_json_value v)) kvs - let obj_of_attributes (xs : Attribute.t list) : _ Js.t = Js.Unsafe.obj @@ Array.of_list @@ diff --git a/src/plotly.mli b/src/plotly.mli index 9dc66ec..952e0d7 100644 --- a/src/plotly.mli +++ b/src/plotly.mli @@ -102,15 +102,18 @@ module Layout : sig val barmode : string -> t val showlegend : bool -> t - (** Axis configuration module for x-, y-, and z-axes *) module Axis : sig (** Set axis title *) val axis_title : string -> string * Base.Value.value - (** Set axis type (e.g., "linear", "log") *) + (** + Set axis type (e.g. ["linear"] or ["log"]) + + See https://plotly.com/python/axes/ for more details. + *) val axis_type : string -> string * Base.Value.value - (** Set axis range as (min, max) *) + (** Set axis data range as (min, max) *) val axis_range : float -> float -> string * Base.Value.value (** Toggle grid display *) @@ -119,20 +122,23 @@ module Layout : sig (** Toggle zero line display *) val axis_zeroline : bool -> string * Base.Value.value - (** Set tick label format *) + (** + Set tick label format + + See https://plotly.com/python/tick-formatting/ for more details. + *) val axis_tickformat : string -> string * Base.Value.value end - (** Configure the x-axis from a list of axis properties *) + (** Set the x-axis properties *) val xaxis : (string * Base.Value.value) list -> t - (** Configure the y-axis from a list of axis properties *) + (** Set the y-axis properties *) val yaxis : (string * Base.Value.value) list -> t - (** Configure the z-axis from a list of axis properties *) + (** Set the z-axis properties *) val zaxis : (string * Base.Value.value) list -> t - (* Build custom layout attributes *) val layout : Attribute.t list -> t val to_json : t -> Ezjsonm.value