Source

gp / src / gp.ml

Full commit
(*
   
   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 endSignal f = fprintf f "e\n%!"
    
let sendColumns 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;
    endSignal f
    
    
    (* for some reason, gnuplot wants a double "e" at the end
     of the stream for matrix data given to [splot()] ... *)
    
let sendMatrix m f =
    sendColumns m f;
    fprintf f "e\n%!"
    
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,_) -> sendColumns (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;
    sendMatrix 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