Recipe: Contours with Perl and GNUplot

Ah, and before I forget: Here is a trivial, but elegant piece of Perl code which utilizes the trusty GNUplot program to compute a 3D presentation of a given elevation model, together with its contours.

Something like this:

1

Invocation in Perl

To start the GNUplot binary we will open another process from the Perl program. There are many ways to do that, the most simple I found was via IPC::Run:

my $in = ...;
my ($out, $err);
use IPC::Run qw(run timeout);
my $h = run [ split /\s+/, "/usr/bin/gnuplot -" ],
            \$in, \$out, \$err, timeout( 10 ) ;

The routine run expects first an array (reference) containing the program and all its necessary parameters:

  • The split I simply use because I want Perl to take care of the list segmentation by itself. I'm too pretty to do this kind of work.
  • The next three parameters are handles for STDIN, STDOUT and STDERR, strictly in the UNIX tradition. You can pass in here all sorts of things, also file names or file handles.
  • The final parameter simply attaches a timeout object to terminate the whole thing after 10 seconds, should it not complete before that by itself.

In my case $err is a scalar, one which is expected to be checked for any error messages GNUplot has produced.

Also $out is a scalar here and the plan is to get the 3D presentation produced by GNUplot into this scalar. The last thing I need is to mess around with files.

GNUplot scripting

To instruct GNUplot to send its output to STDOUT and not to the screen or to a file the GNUplot program must contain somewhere a

set term png font arial 10 size 600,400 nocrop
set output

Obviously we want PNGs to be created, together with the given dimensions. The font specification applies to any text GNUplot happens to add to the image. The set output line redirects the output to STDOUT, so that it eventually ends up in $out.

The control script for GNUplot itself is also not stored in a file (did I mention that I do not fancy files?), but is created on-the-fly inside our Perl program. That also makes it trivial to craft it according to your needs and it also can be made flexible, dependent on user requirements.

The only thing we have to do is to add that GNUplot script into $in and the '-' in the invocation makes sure that GNUplot consumes the script from STDIN.

The script itself might look something like this:

set dgrid3d 30,30,4
set contour base
set surface

set zrange [0:2.0]
set view 60, 30, 0.85, 1.1
set cntrparam levels 20
set hidden3d

You may want to consult the GNUplot documentation here, it is amazing what you can control.

Adding Data

But not only the script, also the data will be read from STDIN. If you had it in a 2-dimensional array, then something like the following would aggregate into the variable $s the data in the correct GNUplot data format:

my $s;
foreach my $y (0 .. $space->{N}) {
  foreach my $x (0 .. $space->{M}) {
    $s .= sprintf "%d\t%d\t%.2f\n",
          $x, $y, $space->{data}->[$x]->[$y]->[0];
  }
}

To tell GNUplot to plot with data coming from STDIN, we use '-' as the required file:

splot '-' with lines;

The thing which remains is to combine the GNUplot script, say stored in $GP and the data, stored in $s:

my $in = $GP . "\n" . $s . 'e';

GNUplot expects that the data input is terminated by a sole 'e' on a new line.

Contours Only

If you were not interested in the 3D surface, you can turn it off with unset surface (or set nosurface with older versions).

More interestingly, you can generate the contours only and this time not rendered into an image, but as raw data:

set dgrid3d 30,30
set contour base
unset surface

set view 0,0
set cntrparam levels 10
set hidden3d

set term table
set output

For that we had to change the view point and instruct GNUplot to produce tabular data.

These guys know how to make an integrator happy. I bow in reverence.

AttachmentSize
HwUVGgTwi5.png11.63 KB
contour.jpg21.22 KB
Posted In

size restrictions

I couldn't find any information on this. I have a 3.5GB size 3D data table I would like to GNUplot, but it doesn't seem to be getting far. Any experiences with huge volume "files"? anyone? hello?

Marcus Meisel (not verified) | Thu, 01/10/2008 - 14:36

A Book on Gnuplot

I saw your posting regarding Gnuplot, and thought you might be interested to know that there is now a book on it: "Gnuplot in Action". You can pre-order it directly from the publisher: <a href='http://www.manning.com/janert/'>Manning: Gnuplot in Action</a>.

If you want to learn more about the book and the author, check out my book page at <a href="http://principal-value.com/my-book.php">Principal Value - Gnuplot in Action</a>.

Let me know if you are interested in a review copy.

Philipp K Janert (not verified) | Thu, 03/20/2008 - 05:48

same thing in python

Hello,
Came across this post while searching for making gnuplot
output without using files. I tried a similar thing in
python and it works OK, except that the first few characters
are "gnuplot> gnuplot> gnuplot>"... and so on (there was also
a 'gnuplot>' at the end). The rest of it is valid PNG output
but due to these ascii chars, the browser can't display it:
I've to manually remove all these before it can show the
PNG in my browser. Any idea why this might be happening? Also
the number of gnuplot> before the png output starts is equal
to the number of lines in the gnuplot script.

abhidg (not verified) | Tue, 07/22/2008 - 12:36

Re: same thing in python

.... "gnuplot> gnuplot> gnuplot>"

These would be the prompts from gnuplot, yes.

I actually do not get these into $out, i.e. where the PNG is produced. Probably they go into STDERR, and I never check that.

Maybe you should double-check that your back-pipe is NOT sending STDERR, by any accident. Not sure how you invoke gnuplot from Python.

But even if you get the prompts, removing them before handing the PNG over to someone else should be pretty easy.

I'll have a look into the Gnuplot Manning book, maybe it has to say something about this.

rho | Tue, 07/22/2008 - 14:28