mlGrace Tutorial

(for use with mlGrace 0.1.x)



mlGrace is a high-level OCaml interface to the Grace 2D plotting program. All of the raw Grace functionality is provided through a low-level interface to the Grace scripting language, but the primary goal is to make many common plotting operations very easy for the scientifically-minded OCaml user. mlGrace comes with API reference documentation that explains all options; please refer to those docs for detailed usage information. But first, to get a feel for the module, how about we take a quick tour?

First off, let's initialize an interactive Grace session. Since I'm generating graphics for inclusion in a webpage, I'll set the viewport size to 650x500 pixels.
$ ./mlgrace
        Objective Caml version 3.08.1
# open Grace;;
# let gv = new grace_view ~layout:(`Size (650, 500)) ();;
val gv : Grace.grace_view = <obj>
At this point, you should have noticed an xmgrace window popping up. gv will always be associated with this window. If you instantiate another grace_view object, you'll get another xmgrace window associated with it.

Now, how about we come up with some data to make a simple plot of the square root function. We can use the plot method for this purpose. It requires an array of x values and an array of y values to plot against x. The linspace command is useful for creating the x array. If we want to plot our function for x in [0, 10], and use 1000 samples to get a smooth curve, we could do something like this:
# let x = linspace 0.0 10.0 1000;;
val x : float array = [|0.; 0.0100100100100100099; 0.0200200200200200198; ...|]
# let y = Array.map sqrt x;;
val y : float array = [|0.; 0.100050037531277364; 0.141492119992669613; ...|]
# gv#plot x y;;
- : unit = ()
# gv#redraw ();;
- : unit = ()
After calling redraw, the xmgrace window should be displaying our plot:
basic square root plot

Hey, not bad. But maybe a title and some labels would be good:
# gv#label `Title "My First Plot";;
- : unit = ()
# gv#label ~font:3 `XAxis "x";;
- : unit = ()
# gv#label ~font:3 `YAxis "y";;
- : unit = ()
# gv#redraw ();;
- : unit = ()

square root with labels

There we go. Notice that I passed the font number as a labeled argument to the label method. You will find that mlGrace uses a lot of optional labeled arguments. They have two advantages: you can skip them if you're happy with the defaults, and you can put such arguments in any order (as long as you end with an unlabeled argument).

At this point I'm starting to get tired of the constant redraw calls. For interactive use, it's more convenient to turn on auto-redraw:
# gv#set_auto_redraw true;;
- : unit = ()
That'll save some typing. Now suppose I want to make some adjustments to the axes. I want to zoom in a bit:
# gv#axes ~xmin:0.0 ~ymin:0.0 ~xmax:6.0 ~ymax:3.0 ();;
- : unit = ()
This does what I was expecting, but after zooming in to that level I decide that I want to adjust the tickmarks. I'll use automatic ticks for the x axis, but on the y axis I want to have major ticks spaced 0.5 apart, and use minor ticks to divide each major spacing in five.
# gv#axes ~xtick:`Auto ~ytick:(`Spacing (0.5, 5)) ();;
- : unit = ()

square root with adjusted tickmarks

There, I'm satisfied. But wait... suddenly I realize that I was supposed to plot both the square root function and the sine, on the same plot! OK, not a big deal. I just need to use the plot_many method, and pass matrix arguments for x and y. Each row of y will be plotted against the corresponding row of x.
# let x_mat = [| x; x |];;
val x_mat : float array array = [|[|0.; 0.0100100100100100099; 0.0200200200200200198; ...|]; ...|]
# let y_sin = Array.map sin x;;
val y_sin : float array = [|0.; 0.0100098428431791842; 0.0200186827054734777; ...|]
# let y_mat = [| y; y_sin |];;
val y_mat : float array array = [|[|0.; 0.100050037531277364; 0.141492119992669613; ...|]; ...|]
# gv#plot_many x_mat y_mat;;
- : unit = ()

square root and sine

Of course, I really ought to add a legend:
# gv#plot_many ~legend:[|"square root"; "sine"|] ~legendfont:1 ~legendfontsize:1.1 x_mat y_mat;;
- : unit = ()

square root and sine, with legend

Looks good to me. To create my webpage graphic, I can use the print method:
# gv#print ~driver:(`PNG "plot.png") ();;
- : unit = ()
If I wanted something worthy of direct printing, I'd just set the driver for PostScript output. If I were looking to include the plot in a document, the best choice is probably Encapsulated PostScript.
# gv#print ~driver:(`PS "plot.ps") ();;
- : unit = ()
# gv#print ~driver:(`EPS "plot.eps") ();;
- : unit = ()
Of course, sometimes it's necessary to create a table of plots. This can be accomplished using the multiplot method:
# gv#multiplot ~rows:2 ~cols:2 ();;
- : unit = ()

multiplot example

I notice a couple of problems with this plot. First of all, it's too crowded in both dimensions; we need a little more space to make room for axis labels and titles. Secondly, the legend we created earlier looks proportionally too large; decreasing the font size would help.
# gv#multiplot ~hgap:0.4 ~vgap:0.5 ();;
- : unit = ()
# gv#plot_many ~num:0 ~legend:[|"square root"; "sine"|] ~legendfont:1 ~legendfontsize:0.8 x_mat y_mat;;
- : unit = ()
The hgap and vgap arguments are relative to the size of an individual graph: ~hgap:0.4 means we are requesting that horizontal gaps are 4/10 of the width of a graph. Also notice the use of the num argument, to send the plot to the 0th location.
corrected multiplot
Let's make a few more plots to fill in the remainder of the table. First a stemplot of the natural logarithm, using resized circles around the points:
# let x1 = linspace 1.0 10.0 10;;
val x1 : float array = [|1.; 2.; 3.; 4.; 5.; 6.; 7.; 8.; 9.; 10.|]
# let y1 = Array.map log x1;;
val y1 : float array = [|0.; 0.693147180559945286; 1.09861228866810978; ...|]
# gv#plot ~num:1 ~stem:true ~symbolsize:1.0 x1 y1;;
- : unit = ()
Now let's add a plot with both the natural logarithm and the square root, labeling each with symbols.
# let x2 = x1;;
val x2 : float array = [|1.; 2.; 3.; 4.; 5.; 6.; 7.; 8.; 9.; 10.|]
# let y2 = Array.map sqrt x2;;
val y2 : float array = [|1.; 1.41421356237309515; 1.73205080756887719; ...|]
# gv#plot_many ~num:2 ~symbol:`Auto ~legend:[|"natural log"; "square root"|] ~legendfontsize:0.8 [| x1; x2 |] [| y1; y2 |];;
- : unit = ()
Finally, how about a plot of 1/x in logscale, with a grid and a subtitle. The logspace function is useful for achieving uniform sampling over a log plot.
# let x3 = logspace ~-.1.0 3.0 1000;;
val x3 : float array = [|0.1; 0.100926219098704764; 0.101861017015597577; ...|]
# let y3 = let inv x = 1.0 /. x in Array.map inv x3;;
val y3 : float array = [|10.; 9.90822809900379475; 9.81729840618883642; ...|]
# gv#plot ~num:3 ~logx:true ~logy:true ~grid:`Minor x3 y3;;
- : unit = ()
# gv#label ~num:3 ~size:1.0 `Title "Logscale Example";;
- : unit = ()
# gv#label ~num:3 ~size:0.7 ~font:1 `Subtitle "Hey look, it's linear! What a coincidence!";;
- : unit = ()

filled in multiplot example

That covers most of the important high-level features of mlGrace. Please have a look at the reference documentation to see the available plotting options in more detail. If you need access to some of the other features provided by Grace, you can use grace_view's exec method to send raw Grace scripting commands. This scripting language is unfortunately poorly documented at present. See the Grace User Guide for some commands, and check the a ACE/gr User Guide for a more thorough (but somewhat obsolete) command listing. Finally, the Grace source code is obviously the authoritative reference on the subject; src/pars.yacc is particularly helpful.

Have fun!