Making plots using Octave, gnuplot, and LATEX

January 16, 2006



Welcome! My name is ComoComo and I’ll be your guide towards making publication-quality graphs using software libre. Although there are many excellent tutorials available online I will focus more on those few extra steps necessary to make plots just a wee bit prettier than the default output. Example code snippets are also included and released into the public domain! So, without further ado, let us consider the following cool-looking equation:

 2 sinζ ∫ α0 ∘ -------- F (α0,ζ) = (ζ +-sin-α0)3∕2 sinα ζ + sinα dα - π∕2

2-D plots

To make the example more interesting we have chosen a function which depends both on a variable ζ as well as the upper limit of integration α0. We’ll start out simple, though, making 2-d plots assuming that α0 is fixed. By the way, if you’re having problems seeing the Greek letters in this document you might need to download the proper font. You can obtain the zip file Thryomanes 1.2 containing Greek TrueType fonts from Herman Miller’s language page. In many distros you can just unzip -L the TTF files into ~/.fonts.

Although gnuplot has a bunch of tricks up its sleeve, evaluating is integrals not really one of them (although simple methods can be programmed, see for example the bivariat.dem file that comes with gnuplot). The right tool for the right job is my motto, so I’ll leave all the computations to Octave, a very powerful matrix-oriented programming language. Evaluating our function can be readably done as follows (2dplot.m):

    # You can run this by typing at the prompt: octave -q 2dplot.m
    # Set some basic parameters, including the name of the
    # output data file.
    outfile = "2dplot.dat";
    global a = 1;
    z_vec = linspace(1, 5, 100);
    # "quad" is octave's integration function. You can type
    # "help quad" and "help quad_options" in octave for help.
    function r = f(x)
      global z;
      r = 2⋆sin(x).⋆sqrt((z + sin(x)));
    function r = F()
      global a;
      r = quad("f", -pi/2, a);
    # The main loop.
    points = [];
    global z;
    for z = z_vec
      points = [points z sin(z)⋆F()/(z + sin(a))⋆⋆(3/2)];
    # Save the data to a file and exit. The output format
    # is very simple (two columns) and appropriate for gnuplot.
    fd = fopen(outfile, "wt");
    fprintf(fd, "%14.6f %14.6f\n", points);

Remember that in Octave you can always get help immediately by typing help command (which you should do, because there’s a lot more behind the quad option than what the above code suggests!) Taking derivatives isn’t all that hard either, and it provides a good example on how to load simple data files into Octave (d2dplot.m):

    # You can run this by typing at the prompt: octave -q d2dplot.m
    outfile = "d2dplot.dat";
    # Note that octave will by default name the matrix "filename",
    # but since variable names cannot start with a number it'll
    # call this one "X2dplot" instead of "2dplot". We then take
    # the numerical derivative and save.
    load 2dplot.dat
    z = X2dplot(:,1);
    dz = diff(z);
    points = [z(1:numel(z)-1) + dz(1)/2, diff(X2dplot(:,2))./dz];
    fd = fopen(outfile, "wt");
    fprintf(fd, "%14.6f %14.6f\n", \
            reshape(points', 1, numel(points)));

Now, on to the plotting. In its simplest form this is actually really, really easy. Just start up gnuplot and type the following to get a graph (s2dplot.plt):

    plot [-0.5:5] [-0.2:0.2] '2dplot.dat' , \
                             'd2dplot.dat' , x⋆⋆2⋆(1 - x)

which results in the following picture on your screen:


Hmmmm, not bad...

To make things more interesting I’ve also plotted the function x2(1 - x) on the same graph. Now, this isn’t bad at all, but it could be better. Let’s assume we don’t care about the scale, but that we do want a cross-hair x-y plot. We’d also like to identify the curves, and so we do (2dplot.plt):

    # You can run this by typing at the prompt: gnuplot 2dplot.plt
    unset border
    unset ytics
    unset key
    # "samples" is the number of points at which to evaluate a
    # function. "100" is actually the default.
    set samples 100
    set style line 1 linetype -1 linewidth 1
    set style arrow 1 nohead linetype 0 linewidth 1
    # We make the cross-hairs here. "ls" is short for "linestyle".
    # "1" is a linestyle we defined above. We also add one unlabeled
    # x tic.
    set xzeroaxis ls 1
    set yzeroaxis ls 1
    set xtics axis ('' 1.965)
    # You can find appropriate label positions by moving the cursor
    # inside the plot.
    set label 'c' at 0.6,-0.18
    set label 'z' at 4.9,0.01
    set label 'F' at 2.8,-0.08
    set label 'dF' at 3,0.19
    # Uncomment the following two lines to save the graph as an eps
    # file.
    set terminal postscript eps rounded
    set output '2dplot.eps'
    # "w l ls 1" is short for "with lines linestyle 1".
    set arrow from 1.965,0 to 1.965,-0.136 arrowstyle 1
    plot [-0.5:5] [-0.2:0.2] '2dplot.dat' w l ls 1, \
    'd2dplot.dat' w l ls 1, x⋆⋆2⋆(1 - x)  w l ls 1

which, lo and behold, gives us:



Now, those tags don’t look too good (and make little sense to boot). However the idea is to ultimately include the plot in a paper or report made with LATEX, and so the real point to the tags is to use them as markers for the psfrag package which allows to replace text within EPS graphs. This way of labeling has three big advantages over hardcoding the tags into the figure. First is consistency, as the fonts will be the same as those in the article. Second is the fact that LATEX’s mathematical engine can be used to the fullest extent within the plot. Last but not least, it allows changing notation easily within the .tex file, as opposed to having to recreate the plot from scratch.

With these points in mind, the following code:

    % You can run this by typing the following commands:
    %    latex 2dplot.tex
    %    dvips -o 2dplot.dvi
    % The syntax of the "psfrag" command is:
    %    \psfrag{tag}[<posn>][<psposn>][<scale>][<rot>]{replacement}
    % See the file for full documentation.
      \psfrag{c}[B][B][1][0]{$x^2 (1-x)$}
      \psfrag{dF}[Bl][Bc][1][0]{\large{$\left. \frac{\partial F}
                                                    {\partial \zeta}

will generate a page with the plot in its final form:



Parametric plots

Plotting data generated by a parametric function is essentially a repeat of the above procedure. Consider the following equation:

 ( ) --G(-ζ)-------H(-ζ)--- (ˆx,ˆt) = √ζ-+sinα0,(ζ + sinα0)3∕2


 ∫ ∫ π∕2 -2-sinα--- π∕2 ∘-------- G(ζ) = α0 √ζ + sinα dα H(ζ) = α0 2 sinα ζ + sinα dα

The Octave code is very similar to the previous one, although in this case α0 is the parameter which determines both the (ˆx,ˆt ) coordinates. The relevant files are pplot.m, pplot.plt, and pplot.tex, which generate the following figure:


As you can see, you can substitute a marker (C in this case) with a picture using the following command (which also scales and rotates the inserted image):

    \psfrag{C}[c][c][1][0]{\includegraphics[scale=0.2, angle=-15]{como_9.eps}}

3-D plots

To make a 3-d plot we consider our original equation F(α0). The code to evaluate it is (3dplot.m):

    # You can run this by typing at the prompt: octave -q 3dplot.m
    outfile = "3dplot.dat";
    samples = 100;
    a_vec = linspace(0.5, 1, samples);
    z_vec = linspace(1, 5, samples);
    function r = f(x)
      global z;
      r = 2⋆sin(x).⋆sqrt((z + sin(x)));
    function r = F(a)
      r = quad("f", -pi/2, a);
    points = [];
    global z;
    for z = z_vec
      for a = a_vec
        points = [points z a sin(z)⋆F(a)/(z + sin(a))⋆⋆(3/2)];
    fd = fopen(outfile, "wt");
    fprintf (fd, "%14.6f %14.6f %14.6f\n", points);

This calculation is a bit more interesting as both the integrand and the upper limit of integration vary. The gnuplot commands to plot this nicely are (3dplot.plt):

    # You can run this by typing at the prompt: gnuplot 3dplot.plt
    unset key
    # Use the surface colours for the contours
    set style line 1 palette
    # Set the border lines to show (see the file gnuplot.pdf that
    # came with gnuplot), and add a bit more space between the tic
    # labels and "y" axis. Note that the positioning of the "xlabel"
    # is in units of the character size.
    set border 1+2+4+8+16
    set zrange [-0.6:0.4]
    set yrange [0.5:1]
    set xtics 1,1,5
    set format y "%8.1f"
    set xlabel "x"
    set ylabel "y"
    set zlabel "z" -7,-8
    # Make a grid, set a coloured surface with contours, and
    # select a nice colour scheme.
    set dgrid3d 100,100,1
    set pm3d
    set contour
    set hidden3d
    set palette rgb 10,13,31
    set terminal postscript eps colour solid rounded
    set output '3dplot.eps'
    # The next command controls the appearance of the colour
    # map box, and the last makes the graph.
    set colorbox horiz user origin 0.1,0.9 size 0.8,.04
    splot '3dplot.dat' w l ls 1, '3dplot.dat' w pm3d

and the resulting graph becomes:



which has been included into a LATEXfile in the usual way (3dplot.tex).


This document was originally written in LATEX(prettyplots.tex) and then converted into HTML code using TeX4ht. Further HTML cleanup was then carried out with HTML Tidy. You can recreate this page (including making the plots from scratch) by following the procedure below:

  1. Make sure you have all the necessary software. This includes:
  2. Download the source files ( and the zsh script into a new, empty directory.
  3. Run chmod 755 ; ./ &> /dev/null in that directory.
  4. Wait a couple of minutes ^_^
  5. The resulting web page is prettyplots.html!

If you’d like to perform a quick and dirty benchmark against my machine (Athlon XP 2200+/512MB RAM/IDE HD) here is my timing:

    time ./
    ./  104.26s user 10.04s system 99% cpu 1:54.70 total


“Making plots using Octave, gnuplot, and LATEX” is ©opyright Marco De la Cruz-Heredia ( and released under a Creative Commons Attribution-ShareAlike 2.5 License. All code files (.m, .plt, .tex and .sh) are released to the public domain. “ComoComo” is ©opyright Daisuke Nishijima, who has released it under a Creative Commons Attribution-NonCommercial-NoDerivs 2.5 license.