In [1]:
#require "vg,vg.svg"




In [2]:
open Gg
open Vg




In [3]:
type svg_render = Gg.size2 * Gg.box2 * Vg.image


type svg_render = Gg.size2 * Gg.box2 * Vg.image

In [4]:
let gray = I.const (Gg.Color.gray 0.9)


val gray : Vg.image = <abstr>

In [26]:
let string_of_svg ?(xml_decl=false) (size,view,image) = 
    let buffer = Buffer.create 1024 in
    let r = Vgr.create (Vgr_svg.target ~xml_decl ()) (`Buffer buffer) in
    ignore (Vgr.render r (`Image (size, view, image)));
    ignore (Vgr.render r `End);
    Buffer.contents buffer


val string_of_svg : ?xml_decl:bool -> Gg.size2 * Gg.box2 * Vg.image -> string =
  <fun>

In [32]:
let print_svg fmt svg = 
    Iocaml.display 
        "text/html" 
            ("<object data=" ^ Iocaml.data_uri "image/svg+xml" (string_of_svg svg) ^ "></object>")
;;
#install_printer print_svg


val print_svg : 'a -> Gg.size2 * Gg.box2 * Vg.image -> unit = <fun>

In [33]:
(Size2.v 30. 30., Box2.unit, gray)


- : Gg.size2 * Gg.box2 * Vg.image = 

This is the minimal example modified for the printer


In [34]:
(* 1. Define your image *)

let aspect = 1.618  
let size = Size2.v (aspect *. 100.) 100. (* mm *)
let view = Box2.v P2.o (Size2.v aspect 1.)
let image = I.const (Color.v_srgb 0.314 0.784 0.471)

(* 2. Render *)
let _ = size, view, image


val aspect : float = 1.618
val size : Gg.size2 = (161.8 100)
val view : Gg.box2 = <box2 (0 0) (1.618 1)>
val image : Vg.image = <abstr>
- : Gg.size2 * Gg.box2 * Vg.image = 

This is the pie ambiguity example from the website


In [35]:
let size = (Size2.v 90. 138.) 
  let view = (Box2.v P2.o (Size2.v 1.5 2.3)) 
  let f = begin fun _ ->
    let pie_chart r colors pcts =
      let rv = V2.v r r in
      let sector (acc, start) color pct =
        let stop = start +. (pct /. 100.) *. Float.two_pi in
        let sector = 
          P.empty >> 
          P.line (V2.polar r start) >> P.earc rv (V2.polar r stop) >> 
          P.line P2.o 
        in
        acc >> I.blend (color >> I.cut sector), stop
      in
      fst (List.fold_left2 sector (I.void, Float.pi_div_2) colors pcts)
    in
    let bar_chart bar_size pad colors pcts = 
      let w, h = V2.to_tuple bar_size in
      let font = 
        { Font.name = "Open Sans"; slant = `Normal; weight = `W400; 
          size = (h *. 0.015) } 
      in
      let mgray = I.const (Color.gray 0.3) in 
      let lgray = I.const (Color.gray 0.75) in
      let bar (acc, x) color pct = 
        let bar = 
          let box = Box2.v P2.o (Size2.v w ((pct /. 100.) *. h)) in
          color >> I.cut (P.empty >> P.rect box) 
        in
        let label =
          let text = Printf.sprintf "%g" pct in
          let pos = P2.v (0.275 *. w) (-1.4 *. font.Font.size) in 
          mgray >> I.cut_glyphs ~text font [] >> I.move pos
        in
        let x = x +. pad in 
        acc >> I.blend (bar >> I.blend label >> I.move (V2.v x 0.)), x +. w
      in
      let bars, xmax = List.fold_left2 bar (I.void, 0.) colors pcts in
      let floor = 
        let ln = P.empty >> P.sub (P2.v pad 0.) >> P.line (P2.v xmax 0.) in
        lgray >> I.cut ~area:(`O { P.o with P.width = h *. 0.001 }) ln
      in
      bars >> I.blend floor
    in 
    let distribs = [[ 23.; 22.; 20.; 18.; 17.];
                    [ 20.; 20.; 19.; 21.; 20.];
                    [ 17.; 18.; 20.; 22.; 23.]]
    in
    let colors =                   (* Brewer's Set2, http://colorbrewer.org/ *)
      let c r g b = I.const (Color.v_srgbi r g b) in 
      [c 102 194 165; c 252 141 98; c 141 160 203; c 231 138 195; c 166 216 84]
    in
    let bar_and_pie (acc, y) pcts = 
      let pie = pie_chart 0.25 colors pcts in
      let bars = bar_chart (Size2.v 0.08 2.) 0.04 colors pcts in
      let bp = bars >> I.blend (pie >> I.move (V2.v 1.0 0.25)) in
      acc >> I.blend (bp >> I.move (V2.v 0. y)), y +. 0.75
    in
    let white = I.const Color.white in
    let charts = fst (List.fold_left bar_and_pie (white, 0.) distribs) in
    charts >> I.move (V2.v 0.125 0.15)
  end


val size : Gg.size2 = (90 138)
val view : Gg.box2 = <box2 (0 0) (1.5 2.3)>
val f : 'a -> Vg.image = <fun>

In [36]:
(size,view,f())


- : Gg.size2 * Gg.box2 * Vg.image = 

Daniel suggests that legalizing the SVG for HTML is a better approach. Indeed the data-uri scheme seems to cause problems with nbviewer.


In [37]:
#require "cow,cow.syntax"




In [46]:
let svg = string_of_svg ~xml_decl:false (size, view, image)
let xml = Cow.Xml.of_string svg


val svg : string =
  "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:l=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"90mm\" height=\"138mm\" viewBox=\"0 0 90 138\" color-profile=\"auto\" color-interpolation=\"linearRGB\" color-interpolation-filters=\"linearRGB\"><g fill=\"none\" stroke-miterlimit=\"9.98123\" transform=\"matrix(60 0 0 -60 -0 138)\"><defs><path id=\"i1\" d=\"M0 0L1.5 0L1.5 2.3L0 2.3Z\"/></defs><use l:href=\"#i1\" fill=\"#50C878\"/></g></svg>"
val xml : Cow.Xml.t =
  [`El
     ((("http://www.w3.org/2000/svg", "svg"),
       [(("http://www.w3.org/2000/xmlns/", "xmlns"),
         "http://www.w3.org/2000/svg");
        (("http://www.w3.org/2000/xmlns/", "l"),
         "http://www.w3.org/1999/xlink");
        (("", "version"), "1.1"); (("", "width"), "90mm");
        (("", "height"), "138mm"); (("", "viewBox"), "0 0 90 138");
        (("", "color-profile"), "auto");
        (("", "color-interpolation"), "linearRGB");
        (("", "color-interpolation-filters"), "linearRGB")]),
      [`El
         ((("http://www.w3.org/2000/svg", "g"),
           [(("", "fill"), "none"); (("", "stroke-miterlimit"), "9.98123");
            (("", "transform"), "matrix(60 0 0 -60 -0 138)")]),
          [`El
             ((("http://www.w3.org/2000/svg", "defs"), []),
              [`El
                 ((("http://www.w3.org/2000/svg", "path"),
                   [(("", "id"), "i1");
                    (("", "d"), "M0 0L1.5 0L1.5 2.3L0 2.3Z")]),
                  [])]);
           `El
             ((("http://www.w3.org/2000/svg", "use"),
               [(("http://www.w3.org/1999/xlink", "href"), "#i1");
                (("", "fill"), "#50C878")]),
              [])])])]

In [47]:
let converted = Cow.Xml.to_string xml


val converted : string =
  "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:l=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"90mm\" height=\"138mm\" viewBox=\"0 0 90 138\" color-profile=\"auto\" color-interpolation=\"linearRGB\" color-interpolation-filters=\"linearRGB\"><g fill=\"none\" stroke-miterlimit=\"9.98123\" transform=\"matrix(60 0 0 -60 -0 138)\"><defs><path id=\"i1\" d=\"M0 0L1.5 0L1.5 2.3L0 2.3Z\"/></defs><use l:href=\"#i1\" fill=\"#50C878\"/></g></svg>"