Home » Linux Magazine » Graphing with lout

Graphing with lout

Michael Hall

Issue #34, February 1997

A document layout language, lout can also be used to generate graphs in PostScript.

Most documentation tools can also make graphs. This article will show you how to use lout, a document layout language, to create graphs. At the end we will have a script which creates a history graph of system activity.

First of all, lout is a document layout program which generates PostScript. It was written by Jeffrey Kingston at the Basser Department of Computer Science, the University of Sydney, Australia. It is available on Red Hat distributions such as Caldera’s, and many Linux ftp sites. Also, the original sources are available at ftp.cs.su.oz.au under the “jeff” directory.

In many ways, lout is a preprocessor for PostScript, since many lout statements turn into PostScript instructions. In other ways, lout is a language for writing structured documents—we describe lists, sections, chapters, books and reports with lout commands, and our text becomes the arguments to those commands. In this article, we will focus on the commands in lout’s graph package, and ignore its other capabilities for documents.

In general, lout commands start with a commercial-at sign, @. Arguments to a command appear to its right, enclosed in braces, and option settings can appear between the command and its argument:

@Command options  {  argument }

Usually the argument can contain lout commands also, so we’ll get nested groups of arguments with their braces helping to sort everything out.

Let’s jump right in and take a look at a simple lout document for a graph:

@SysInclude {graph}
@SysInclude {doc}
@Doc @Text @Begin
@Graph { @Data pairs {solid}  { 1 1  2 10  3 5 } }
@End @Text

Put this into a file called graph.l, and run lout like this:

lout -s -o ps  graph.l

lout reads the input file, and generates PostScript, writing it to the output file, here called ps. The -s tells lout that we have a stand-alone document, and we don’t want it to make its cross-reference files.

When you look at the resulting ps file with Ghostview (or print it to a printer), you’ll see a nice little graph at the top of the page. lout has automatically generated a box, figured out some appropriate scales, plotted the lines and displayed the graph. The graph package in lout has many options to modify the characteristics of this graph; we’ll see some of them later.

For now, the important part is the @Graph command:

@Graph  {  @Data  options  { data-values } }

This tells lout to make a graph from a data set in its argument list. We gave the @Data command the option “pairs {solid}”, which tells lout that the data set has pairs of x-y coordinate values, and that we want the data points connected with solid lines.

As for the rest of the example, the @SysInclude commands tell lout which packages we’ll be using in the document. The @Doc command says that the body of the document follows, which is delimited by the @Text @Begin and @End @Text statements. And that’s about as difficult as lout gets.

System Activity Graph

Suppose we want to make a system activity graph. We’ll want three curves, one each for the user, system and idle percentages. The user percentage curve will be a solid line, with filled-in circles to indicate each data point. The system and idle percentage curves won’t have symbols at each data point, but the system percent curve will be dashed, and the idle percent curve will be dotted.

Moving from the data sets to the graph itself, we want the graph to fill the page, in a landscape orientation. There will be a title at the top, a brief description below the graph, and a y-axis label to the left. Instead of a legend box to identify the curves, we want an appropriate label to the right of the last point in each curve on the graph.

Implementation

So that’s what we want. How do we get there? We will use awk as an interface between vmstat and lout. The overall flow will look like:

vmstat  |  awk  |  lout

vmstat generates numbers for the system activity over a period of time, and passes them on to awk. awk’s role is to take those numbers, collect the ones it needs, and generate @Graph and @Data statements for lout. Finally, lout takes its document and converts it to PostScript. We can take the PostScript output and view it, print it, or embed it elsewhere. If the system is up all the time, we can even use a crontab entry to automatically print out daily activity reports at the end of each day.

Listing 1. SysAct

#
#  Make a System Activity Graph
#
#  This will be a little confusing to read...
#  it contains quotes of 'lout' code embedded within an 'awk' script;
#  they both use lots of braces.
#

#
#  Write the 'lout' statements to setup the graph
#
( echo "@SysInclude {graph}
@SysInclude {doc}
@Document
  @InitialFont {Helvetica Base 10p}
  @PageHeaders {None}
//
@Text @Begin
@Display  90d @Rotate  @Graph
  width  {8 in}
  height {5.5 in}
  abovecaption {System Activity Graph: User, System, and Idle Percentages}
  belowcaption {Ten minute period starting on `date`}
  leftcaption {90d @Rotate {Percent of System Used}}
  hidecaptions {no}
  xticks { 0@ 1@ 2@ 3@ 4@ 5@ 6@ 7@ 8@ 9@ 10@ }
  yextra {0}
  xextra {0}"

#
#  run "vmstat" to get system data
#  read the data lines; store selected data in arrays
#  at end of the data, generate the remainder of the 'lout' statements
#

vmstat -n 10 60 | awk '

BEGIN {
   n = 0          # initialize data-point counter
}

{
   if ( $0 ~ /[a-zA-Z]/ )     # skip over header lines
      next

   # save selected data values
   user[n] = $13        # user %
   syst[n] = $14        # system %
   idle[n] = $15        # idle %
   n++
}


#
#  we have all the values
#  generate data statements for lout
#

function gen_data(array, dot, line) {

   printf("@Data ")          # start a data group
   if ( dot != "" )
      printf("points { %s } ", dot)      # set data-point style
   printf("pairs { %s } {\n", line)      # x/y pairs, line-style
   for ( i = 0; i < n; i++ ) {         # write the data values
      printf("%f   %d\n", i/6.0, array[i])
   }
   print "}"              # end this data group
}

END {
   # print the identifier at the end of each plot
   print "objects {"
   printf(" @E at {%d %d} {User}\n",   (n+2)/6.0, user[n-1])
   printf(" @E at {%d %d} {System}\n", (n+2)/6.0, syst[n-1])
   printf(" @E at {%d %d} {Idle}\n",   (n+2)/6.0, idle[n-1])
   print "}"

   # now generate the data body
   print "{ "
   gen_data(user, "filledcircle", "solid")
   gen_data(syst, "", "dashed")
   gen_data(idle, "", "dotted");
   print "}"

   # and finish-up the document
   print "@End @Text"
}' ) | lout -s -


The complete script is shown in Listing 1. Let’s step through it together. The echo command sends the lout setup code; we include the graph and doc packages, set the default font for the document, and turn off the page headers to avoid getting page numbers.

After the @Text @Begin statements, we show the rotated graph, or, as expressed in lout:

@Display 90d @Rotate @Graph { ... }

Here the @Rotate command takes two arguments: on its left, the number of degrees to rotate, and on its right, the lout object to rotate. In this case, the object we rotate is our entire graph.

The @Graph statement is followed by several graph options. We set the graph size, and we set some captions. We add a caption above the graph with abovecaption { title text }. Similarly, we add a comment below the graph, and a y-axis label to the left of the graph. Note that we rotated the leftcaption so that it would be parallel to the y-axis of the graph. After the captions, we specify the tick marks on the x-axis. By default, lout generated ticks only for every other minute. We can specify where we want ticks and what to label each tick with the xticks and yticks options. In this case, the y-axis ticks are fine, but we want a tick and label on the horizontal axis for each minute. The last two graph options tell lout to not leave any free space between the graph curves and the axes of the graph. This way, the bottom line of the graph box becomes the 0% line of the chart.

Now that all the setup is done, we can start collecting data. We call vmstat, and tell it that we want 60 samples taken 10 seconds apart, to collect data over a 10-minute period. We send these measurements to awk.

Inside the awk script, we collect the user, system, and idle percentages in separate arrays, taking care to skip over the header lines. When vmstat exits, we’ll use these saved values to generate data sets for lout.

Inside the END routine of the awk script, we first generate the lout code to put the curve identifiers at the right side of the graph. In the code, these appear in an objects { … } option to the @Graph command. This is a powerful feature which lets us put nearly anything anywhere on the graph. After the objects are written, we can generate the data sets. An awk function generates the lout statements for us—we pass the array name, the point-style, and the line-style to the routine called gen_data. It takes care of generating a well-formatted data set for lout.

Finally, the awk script finishes the lout document by declaring the end of the text with @End @Text.

The combined output of echo and awk are piped into lout, which sends the PostScript for the system activity graph to its standard output. This script could serve as the basis for many other graphs:

  • We could pass in the options to vmstat to get better control over the sampling interval and duration.
  • Instead of rotating the graph to take up the full page, we could leave it on a portrait-aligned page, and put additional graphs below it (for swap, free and buffer memory, perhaps).
  • We could instruct the awk script to highlight severe system conditions by changing the line-style and point-style in separate data sets when the data values become too high or too low.
  • We could generate annotations for the graph automatically, showing the time and percentage values when the system percentage crosses some threshold.

The principle is the same for any other data. Need a disk-usage graph? Run du through an interface script and generate some lout code to graphically show the disk-hogs on the system. Modify the script a little to get a directory usage graph for a single user.

I hope this brief introduction has piqued your interest in the graphing abilities of lout. For more information about lout, see the excellent user and reference manuals that come with it. They cover everything you’ll need to know to use lout.

Availability

Scripts for the system activity graph and a disk-usage graph can be found at: http://www.balr.com.

Mike Hall is a senior consultant at BALR Corporation, and can be reached at mghall@balr.com.

x

Check Also

PostScript, The Forgotten Art of Programming

Hans de Vreught Issue #42, October 1997 A tutorial for beginners is presented on writing ...