Gri: A Language for Scientific Illustration

This scripting language avoids integrating analysis and display capabilities and instead focuses on providing precise and flexible control over the display of technical material.

Like other computer users, scientists
sometimes find themselves torn between simple tools and complex
tools, between ease of use and power.

Take writing, for example. The simplest tools for writing are
those of the office-suite variety, because they are GUI-based. If
you can click and point, you can produce results quickly without
climbing a steep learning curve.

However, you might also pay a price for this shallow learning
curve. Many technical writers who make extensive use of
mathematical notation find GUI-based products to be both limiting
and annoying when used for anything but a one-pager. For example,
graduate students in our research field (Physical Oceanography)
often write hundreds of equations in their dissertations. Almost
without exception, these students use markup languages (mostly TeX
and LaTeX) for this work. It must be admitted that markup-based
writing tools are harder to learn than GUI-based tools, but the
effort of learning is rewarded with precise control over output
that is aesthetically pleasing and flexible enough to meet all
reasonable demands.

What goes for words also goes for pictures. For quick jobs,
it's lovely to use a GUI-based graphing package or a spreadsheet.
However, many users prefer a markup-based system for complicated
illustrations, for the same reasons they prefer a markup-based
system for complicated text. An additional factor is that GUI-based
systems cannot help with illustrations that must be generated
automatically without human intervention.

An interesting example is provided by storm-surge forecasts
prepared by oceanographers at Dalhousie University in Nova Scotia,
Canada. Storm surges are unusual elevations in sea level that are
driven by anomalous wind stresses and low atmospheric pressures
associated with storms. These surges can cause considerable damage
to low-lying areas. Since damage is worsened if a surge happens to
occur at the time of a high tide, it is important to make precise
predictions of surge arrival times. Surge-induced damage can be
greatly reduced if people are given sufficient warning of impending
storm surges. Dalhousie researchers have developed numerical ocean
models, akin to numerical weather models, for predicting the
incidence of storm surges in the northwest Atlantic Ocean. The goal
is to provide advance-warning systems that display surge forecasts
graphically on the Web. Gri is used for the graphics in this
system, because it can be run without human intervention. It is so
flexible, researchers can tailor the illustrations to be quickly
understood by non-technical users.

We mention this storm-surge example mostly because we find it
interesting. Many folks use Gri, so we could have picked other
examples of Gri applications in different disciplines of science
and engineering. To help you decide whether Gri might help you in
your own work, we will explain how to use Gri for some basic
scientific illustrations (line graphs, contour graphs and image
graphs). This will be enough to get you up and running in a few
minutes. After that, we'll outline a few examples from our own work
and that of colleagues. In this second part, we won't be hesitant
about explaining the scientific background of the work, since we've
enjoyed reading such things in this magazine.

Getting Started

One feature scientists like about Gri is that it provides
fine control over nearly all aspects of the appearance of the
output. This is relevant because scientists have diverse needs,
ranging from complicated working plots to pared-down and elegant
diagrams for use in proposals, conference presentations and
publications. Many Gri users report it is flexible enough to
satisfy the full range of applications, removing the need to learn
one tool for working plots and another for “publication-quality”
illustrations.

Gri achieves its flexibility by being highly configurable; it
has many knobs you can twiddle. Just because the knobs are there
doesn't mean you need to touch them, since the Gri defaults are
reasonable for many applications. The reasonableness of the
defaults may well result from the fact that Gri was designed by a
scientist for his research work, not by a committee or a corporate
structure that had surveyed (or imagined) a market.

Line Graphs

Perhaps the best way to illustrate the defaults and the
simplicity of Gri is to show how one would produce the most common
form of scientific illustration, a line graph describing x,y data.
To be specific, let's suppose we have an ASCII file named
linegraph.dat, containing the following x,y pairs:

0.05 12.5
0.25 19.0
0.50 15.0
0.75 15.0
0.95 13.0

Creating a line graph then takes just three Gri commands:

open linegraph.dat
read columns x y
draw curve

If these commands were stored in a file called linegraph.gri and if
Gri were invoked as gri linegraph.gri in a UNIX
shell, the result would be a PostScript file named linegraph.ps as
shown in Figure 1. Gri does not draw to the screen, because
screen-drawing libraries are more limited than PostScript and
high-quality PostScript viewers are freely available on all
platforms.

Figure 1. A Simple Line Graph Produced by
Gri

The example illustrates a few things. To begin with, Gri
syntax is simple, being patterned on English and purposefully using
a minimum of punctuation. For example, the
open command takes as an argument
the name of the file containing the data. This file name is not
enclosed in parentheses, as it would be in a subroutine-based
language. We think the lack of parentheses makes Gri easier to read
than some languages. Nor is there any need for the file name to be
enclosed in quotation marks, although these are required for file
names with spaces in them (and for pseudo-file names created by
UNIX pipe commands, which are supported in the Perl style).

Now let's move on to the read line. Gri knows of four types
of data: scalars, columns, grids and images. These types are what
you'd expect: scalars hold numerical values or strings, columns
hold lists of numbers, grids hold two-dimensional matrices and
images hold pixels. Each data type has a host of associated read
commands and data-processing commands. Folks who are used to
programming languages should note that Gri is an
illustration-oriented language, not a programming-oriented one, so
it attaches special meanings to columns. Thus, the columns named x
and y in the example above correspond to the x,y values in a
Cartesian space. Gri also has a column named z used for gridding, a
column called w used for weights in statistical operations, columns
called u and v for vector fields, etc.

The draw curve command tells Gri to draw a
curve composed of line segments connecting these points. You may
not be surprised, given the focus on drawing, to learn that Gri has
many options for draw--over 40, in
fact. For example, to get symbols drawn at the data points, you
could add the line draw symbol someplace after
the read command. This will draw bullets at the x,y points. Bullets
are the default, but Gri provides a dozen other symbol choices. The
symbols are designed according to the recommendations of scientific
journals and technical-drafting texts. For example, efforts have
been made to ensure that the superposition of any two symbols does
not result in a symbol that can be mistaken for a third symbol
type. The default symbol size is a diameter of 0.1 cm (defined in
the expected way for a bullet, and in a reasonable way for
non-circular symbols). If this doesn't suit your application, you
could issue a command such as set symbol size
0.2 to create larger symbols (in this case, 0.2
centimeters). This is by no means the only
set command. It has many options,
since Gri is designed to be configurable. Indeed, there is an
average of nearly two set commands for each draw command.

In addition to such basic commands and a few others discussed
next, Gri provides programming features such as “if” statements,
loops and system calls. It also provides a simple scheme for
creating new commands to complement the existing commands;
e.g.,

Draw Logo
{
... Gri commands to draw a logo
}

creates a new command to draw a logo. This command is invoked
by Draw Logo, just as if it were a built-in
command. Many users store such definitions in a file called
~/.grirc and thus customize Gri for the sort of work they do.

Gri updates its PostScript output file step by step as it
processes commands. When Gri executes any drawing command, the item
is drawn with whatever settings (fonts, colors, line widths, etc.)
are in place at that time. To use an artistic analogy, draw will
paint with whatever color has been stored on the brush with the
most recent set command. Many other scripting graphic languages
follow a different approach, with some commands being able to alter
the form of material that has already been drawn (e.g., axis in
matlab). Such languages are meant to be used interactively in an
exploratory way, so it makes sense to have this out-of-order
processing. However, Gri processes commands in order, because it is
designed to be used non-interactively in a planned way.

Gri scripts are not typically written in one large chunk.
Instead, Gri users typically write their scripts a bit at a time,
running Gri at frequent intervals to see what the results look
like. Some like to keep a PostScript viewer open at all times,
clicking on an update button every time they run Gri. Most Gri
users run it from inside Emacs, which has a button that runs Gri
and displays the output. This is but one helpful feature of the Gri
Emacs mode. It also provides syntax coloring, indentation, linkage
to the on-line Gri documentation, command-specific help, command
completion and a search facility that lists all Gri commands
containing a given word.

Trending Topics

Upcoming Webinar

Getting Started with DevOps - Including New Data on IT Performance from Puppet Labs 2015 State of DevOps Report

August 27, 2015
12:00 PM CDT

DevOps represents a profound change from the way most IT departments have traditionally worked: from siloed teams and high-anxiety releases to everyone collaborating on uneventful and more frequent releases of higher-quality code. It doesn't matter how large or small an organization is, or even whether it's historically slow moving or risk averse — there are ways to adopt DevOps sanely, and get measurable results in just weeks.