From daf4a6b851bd5cfe21b1b8feb016c430a9c3d5bc Mon Sep 17 00:00:00 2001 From: Jonas Brock-Hanash <1080933+jonas-bh@users.noreply.github.com> Date: Mon, 5 Jan 2026 12:21:35 +0100 Subject: [PATCH 1/2] Add support for defining data trace marker color --- jsoo/jsoo.ml | 12 ++++++++++++ python/python.ml | 13 +++++++++++++ src/base.ml | 19 +++++++++++++++++++ src/base.mli | 15 +++++++++++++++ src/plotly.ml | 4 ++++ src/plotly.mli | 29 +++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+) diff --git a/jsoo/jsoo.ml b/jsoo/jsoo.ml index 4811848..f964f80 100644 --- a/jsoo/jsoo.ml +++ b/jsoo/jsoo.ml @@ -12,6 +12,18 @@ 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 + | 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 + | `Float f -> Js.Unsafe.inject f + | `Bool b -> Js.Unsafe.inject b + | `Null -> Js.Unsafe.inject Js.null + | `A vs -> Js.Unsafe.inject @@ Js.array (Array.of_list (List.map of_json_value vs)) + | `O kvs -> + 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 @@ diff --git a/python/python.ml b/python/python.ml index 2ec1ef4..cc13e86 100644 --- a/python/python.ml +++ b/python/python.ml @@ -7,6 +7,19 @@ let rec of_value v = | Value (String, s) -> Py.String.of_string s | Value (Array ty, vs) -> Py.List.of_array @@ Array.map (fun v -> of_value (Value (ty, v))) vs + | Value (Object, obj) -> of_json_value (obj : Ezjsonm.value) + +and of_json_value (j : Ezjsonm.value) : Py.Object.t = + match (j : Ezjsonm.value) with + | `String s -> Py.String.of_string s + | `Float f -> Py.Float.of_float f + | `Bool b -> Py.Bool.of_bool b + | `Null -> Py.none + | `A vs -> Py.List.of_list_map of_json_value vs + | `O kvs -> + let py_dict = Py.Dict.create () in + List.iter (fun (k, v) -> Py.Dict.set_item_string py_dict k (of_json_value v)) kvs; + py_dict let of_attribute (s, v : Attribute.t) = (s, of_value v) diff --git a/src/base.ml b/src/base.ml index c6e534a..156cf5b 100644 --- a/src/base.ml +++ b/src/base.ml @@ -5,6 +5,7 @@ module Type = struct | Float : float t | String : string t | Array : 'a t -> 'a array t + | Object : Ezjsonm.value t type type_ = Type : 'a t -> type_ @@ -12,6 +13,7 @@ module Type = struct match a, b with | Float, Float -> Some Eq | String, String -> Some Eq + | Object, Object -> Some Eq | Array a, Array b -> (match eq a b with | Some Eq -> Some Eq @@ -28,11 +30,13 @@ module Value = struct let float f : float t = Type.Float, f let string s : string t = Type.String, s let array ty vs : 'a array t = Type.Array ty, vs + let object_ obj : Ezjsonm.value t = Type.Object, obj let rec to_json v : Ezjsonm.value = match v with | Value (Type.Float, f) -> `Float f | Value (String, s) -> `String s + | Value (Object, obj) -> obj | Value (Array ty, xs) -> `A (List.map (fun x -> to_json (Value (ty, x))) @@ Array.to_list xs) let rec of_json v = @@ -40,6 +44,7 @@ module Value = struct match v with | `Float f -> Some (Value (float f)) | `String s -> Some (Value (string s)) + | `O _ as obj -> Some (Value (object_ obj)) | `A vs -> let* vs = mapM of_json vs in (match vs with @@ -82,3 +87,17 @@ module Attributes = struct (k, res)) kvs | _ -> None end + +module Marker = struct + open Attributes + + type t = Attribute.t list + + let color c = string "color" c + let colors cs = array "color" Type.String cs + + let marker ats = ats + + let to_json = Attributes.to_json + let of_json = Attributes.of_json +end diff --git a/src/base.mli b/src/base.mli index bfd8819..c1ee678 100644 --- a/src/base.mli +++ b/src/base.mli @@ -3,6 +3,7 @@ module Type : sig | Float : float t | String : string t | Array : 'a t -> 'a array t + | Object : Ezjsonm.value t type type_ = Type : _ t -> type_ end @@ -14,6 +15,7 @@ module Value : sig val float : float -> float t val string : string -> string t val array : 'a Type.t -> 'a array -> 'a array t + val object_ : Ezjsonm.value -> Ezjsonm.value t val to_json : value -> Ezjsonm.value val of_json : Ezjsonm.value -> value option @@ -33,3 +35,16 @@ module Attributes : sig val to_json : t -> Ezjsonm.value val of_json : Ezjsonm.value -> t option end + +module Marker : sig + type t = private Attribute.t list + + val color : string -> t + + val colors : string array -> t + + val marker : Attribute.t list -> t + + val to_json : t -> Ezjsonm.value + val of_json : Ezjsonm.value -> t option +end diff --git a/src/plotly.ml b/src/plotly.ml index 417adb9..195d500 100644 --- a/src/plotly.ml +++ b/src/plotly.ml @@ -26,6 +26,10 @@ module Data = struct let zs = Array.map (fun (_,_,z) -> z) xyzs in x xs @ y ys @ z zs + let marker (marker_attrs : Marker.t) : t = + let marker_obj = Attributes.to_json (marker_attrs :> Attribute.t list) in + ["marker", Value.Value (Value.object_ marker_obj)] + let data ds = ds let to_json = Attributes.to_json diff --git a/src/plotly.mli b/src/plotly.mli index 3e9033a..10e818d 100644 --- a/src/plotly.mli +++ b/src/plotly.mli @@ -3,6 +3,7 @@ module Type : sig | Float : float t | String : string t | Array : 'a t -> 'a array t + | Object : Ezjsonm.value t type type_ = Type : _ t -> type_ end @@ -13,6 +14,7 @@ module Value : sig val float : float -> float t val string : string -> string t val array : 'a Type.t -> 'a array -> 'a array t + val object_ : Ezjsonm.value -> Ezjsonm.value t val to_json : value -> Ezjsonm.value val of_json : Ezjsonm.value -> value option @@ -33,6 +35,30 @@ module Attributes : sig val of_json : Ezjsonm.value -> t option end +module Marker : sig + type t = private Attribute.t list + + (** + Set a single color for all data points. + + The color may be specified by its color name (e.g., ["LightBlue"]), hex code (e.g., ["#ADD8E6"]), or RGB(A) string (e.g., ["rgba(173, 216, 230, 1)"]). + The latter allows for specifying transparency. + *) + val color : string -> t + + (** + Set the colors for each of the data points, such that each color corresponds to a data point. + + The colors may be specified by their color name (e.g., ["LightBlue"]), hex codes (e.g., ["#ADD8E6"]), or RGB(A) strings (e.g., ["rgba(173, 216, 230, 1)"]). + The latter allows for specifying transparency. + *) + val colors : string array -> t + val marker : Attribute.t list -> t + + val to_json : t -> Ezjsonm.value + val of_json : Ezjsonm.value -> t option +end + module Data : sig type t = private Attribute.t list @@ -52,6 +78,9 @@ module Data : sig (* The argument is splitted to build attributes [x], [y], and [z] *) val xyz : (float * float * float) array -> t + (* Attach marker configuration to the trace *) + val marker : Marker.t -> t + (* Build custom data attributes *) val data : Attribute.t list -> t From 0a4df80e150ba7a4075459f55143b40ea6fabdc5 Mon Sep 17 00:00:00 2001 From: Jonas Brock-Hanash <1080933+jonas-bh@users.noreply.github.com> Date: Thu, 8 Jan 2026 16:38:10 +0100 Subject: [PATCH 2/2] Take a list of marker attributes, such that more marker attributes can be easily added. --- src/base.ml | 2 +- src/base.mli | 6 +++--- src/plotly.ml | 5 +++-- src/plotly.mli | 9 ++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/base.ml b/src/base.ml index 156cf5b..090d982 100644 --- a/src/base.ml +++ b/src/base.ml @@ -96,7 +96,7 @@ module Marker = struct let color c = string "color" c let colors cs = array "color" Type.String cs - let marker ats = ats + let marker ats = List.concat ats let to_json = Attributes.to_json let of_json = Attributes.of_json diff --git a/src/base.mli b/src/base.mli index c1ee678..9f7cec9 100644 --- a/src/base.mli +++ b/src/base.mli @@ -39,11 +39,11 @@ end module Marker : sig type t = private Attribute.t list - val color : string -> t + val color : string -> Attribute.t list - val colors : string array -> t + val colors : string array -> Attribute.t list - val marker : Attribute.t list -> t + val marker : Attribute.t list list -> t val to_json : t -> Ezjsonm.value val of_json : Ezjsonm.value -> t option diff --git a/src/plotly.ml b/src/plotly.ml index 195d500..25f135a 100644 --- a/src/plotly.ml +++ b/src/plotly.ml @@ -26,8 +26,9 @@ module Data = struct let zs = Array.map (fun (_,_,z) -> z) xyzs in x xs @ y ys @ z zs - let marker (marker_attrs : Marker.t) : t = - let marker_obj = Attributes.to_json (marker_attrs :> Attribute.t list) in + let marker (marker_attrs : Attribute.t list list) : t = + let combined = Marker.marker marker_attrs in + let marker_obj = Attributes.to_json (combined :> Attribute.t list) in ["marker", Value.Value (Value.object_ marker_obj)] let data ds = ds diff --git a/src/plotly.mli b/src/plotly.mli index 10e818d..075dbce 100644 --- a/src/plotly.mli +++ b/src/plotly.mli @@ -44,7 +44,7 @@ module Marker : sig The color may be specified by its color name (e.g., ["LightBlue"]), hex code (e.g., ["#ADD8E6"]), or RGB(A) string (e.g., ["rgba(173, 216, 230, 1)"]). The latter allows for specifying transparency. *) - val color : string -> t + val color : string -> Attribute.t list (** Set the colors for each of the data points, such that each color corresponds to a data point. @@ -52,8 +52,8 @@ module Marker : sig The colors may be specified by their color name (e.g., ["LightBlue"]), hex codes (e.g., ["#ADD8E6"]), or RGB(A) strings (e.g., ["rgba(173, 216, 230, 1)"]). The latter allows for specifying transparency. *) - val colors : string array -> t - val marker : Attribute.t list -> t + val colors : string array -> Attribute.t list + val marker : Attribute.t list list -> t val to_json : t -> Ezjsonm.value val of_json : Ezjsonm.value -> t option @@ -78,8 +78,7 @@ module Data : sig (* The argument is splitted to build attributes [x], [y], and [z] *) val xyz : (float * float * float) array -> t - (* Attach marker configuration to the trace *) - val marker : Marker.t -> t + val marker : Attribute.t list list -> t (* Build custom data attributes *) val data : Attribute.t list -> t