1. Guillaume Hennequin
  2. gp

Source

gp / src / gp.ml

(*
   
   Copyright (C) 2010 Guillaume Hennequin
   
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see http://www.gnu.org/licenses
   
   *)


open Printf

let gnuplot = "gnuplot" (* command name *)
  
type t = out_channel
  
let figure ?device () =
  let f = Unix.open_process_out gnuplot in
  begin match device with
    | None -> output_string f "set term wxt enhanced persist\n"
    | Some (terminal,"") -> output_string f (sprintf "set term %s\n" terminal);
    | Some (terminal,file) -> (
          output_string f (sprintf "set term %s\n" terminal) ;
          output_string f (sprintf "set output '%s'\n" file))
  end;
  f
  
let send list (f:t) = List.iter (fun s -> output_string f (s^"\n")) list
  
let flush = flush
  
let close f = ignore (Unix.close_process_out f)
  
let end_signal f = fprintf f "e\n%!"
  
let send_columns m f =
  let cols = Array.length m in
  let rows = Array.fold_left max (-1) (Array.map Array.length m) in
  for i=0 to rows-1 do
    for j=0 to cols-1 do
      let mj = m.(j) in
      if i<Array.length mj
      then fprintf f "%f " mj.(i)
      else fprintf f "- ";
    done; fprintf f "\n%!";
  done;
  end_signal f
  
  
  (* for some reason, gnuplot wants a double "e" at the end
     of the stream for matrix data given to [splot()] ... *)
  
let send_matrix m f =
  send_columns m f;
  end_signal f
  
let plot data f =
  let cmds = List.map (fun (_,opts) -> sprintf "'-' %s" opts) data in
  let cmd = "plot " ^ String.concat ", " cmds in
  send [cmd] f;
  List.iter (fun (d,_) -> send_columns (Array.of_list d) f) data
  
  
let splot data f =
  let mat,opts = data in
  send ["set pm3d map"; "set key noautotitle"] f;
  let n = Array.length mat and m = Array.length mat.(0) in
  send [
    sprintf "set xrange [%f:%f]" (-0.5) (float n -. 0.5);
    sprintf "set yrange [%f:%f] reverse" (-0.5) (float m -. 0.5);
    sprintf "splot '-' %s" opts
  ] f;
  send_matrix mat f
  
let margins ?t ?b ?l ?r f =
  let setm s x = match x with
    | Some m -> send [sprintf "set %smargin at screen %f" s m] f
    | None -> () in
  setm "t" t; setm "b" b; setm "l" l; setm "r" r
  
let xrange a b f =
  send [sprintf "set xrange [%f:%f]" a b] f
  
let yrange a b f =
  send [sprintf "set yrange [%f:%f]" a b] f
  
let title s f =
  send [sprintf "set title '%s'" s] f
  
let multiplot rows cols vspace hspace list f =
  send [sprintf "set multiplot layout %i,%i" rows cols] f;
  let plots = Array.of_list list in
  let hrem = 2. *. hspace *. float cols
  and vrem = 2. *. vspace *. float rows in
  let width = (1. -. hrem) /. float cols
  and height = (1. -. vrem) /. float rows in
  for k=0 to Array.length plots - 1 do
    let row = k/cols and col = k mod cols in
    let t = 1. -. hspace -. 2. *. hspace *. float row -. height *. float row in
    let b = t -. height in
    let l = 1. -. (1. -. vspace -. 2. *. vspace *. float col -. width *. float col) in
    let r = l +. width in
    margins ~t ~b ~l ~r f;
    plots.(k) f;
  done;
  send ["unset multiplot"] f
  
  
let quick doThis =
  let f = figure() in
  doThis f;
  close f