3 Subroutine Libraries

 3.1 The PGPLOT library
 3.2 The BUTTON library
 3.3 The pgperl package
 3.4 Python PGPLOT
 3.5 GLISH PGPLOT
 3.6 ptcl Tk/Tcl and PGPLOT
 3.7 Starlink/Native PGPLOT
 3.8 Graphical Kernel System (GKS)
 3.9 Simple Graphics System (SGS)
 3.10 PLplot Library
 3.11 The libjpeg Library
 3.12 The giflib Library
 3.13 The libungif Library
 3.14 The angif Library
 3.15 The PNG Format
 3.16 The MNG Format
 3.17 The Python Imaging Library
 3.18 The gd Library

3.1 The PGPLOT library

The PGPLOT library is Fortran or C high-level callable graphics library. It has become the de-facto standard for display of astronomical data. Along with the standard primitives to draw lines, write text and annotate plots, there are also high level routines which use these primitives to build up more complicated graphs such as histograms and contour maps. PGPLOT also has the capability for interactive graphics where the user can interact with the plots using the cursor.

While it would be quite possible for me to fill the entire cookbook with PGPLOT information an excellent tutorial style manual already exists for the library written by Tim Pearson of CalTech the package’s author. If you work at a Starlink node this manual should be available to you, if not it’s available on the web at http://astro.caltech.edu/~tjp/pgplot/contents.html.

A simple example program is shown below, taken from Chapter 2 of the PGPLOT manual. It shows how a simple plot can be generated in just a few lines of code, the output from the program is shown in Figure 1.

        PROGRAM GRAPH
  
        INTEGER I, IER, PGBEG
        REAL XR(100), YR(100)
        REAL XS(5), YS(5)
  
        DATA XS/1.,2.,3.,4.,5./
        DATA YS/1.,4.,9.,16.,25./
  
        IER = PGBEG(0,’?’,1,1)                     ! Start PGPLOT
                                                   ! Specify the device
  
        IF (IER.NE.1) STOP                         ! No response? Stop execution
        CALL PGENV(0.,10.,0.,20.,0,1)              ! Initialise the axes
        CALL PGLAB(’(x)’, ’(y)’, ’A Simple Graph’) ! Label the axes
        CALL PGPT(5,XS,YS,9)                       ! Plot 5 points using symbol 9
  
        DO 10 I=1,60
            XR(I) = 0.1*I                          ! Calculate X^2 function
            YR(I) = XR(I)**2
     10 CONTINUE
        CALL PGLINE(60,XR,YR)                      ! Draw a line
        CALL PGEND
        END


pict

Figure 1: Output from the simple PGPLOT Fortran program.


3.1.1 Encapsulated Postscript and PGPLOT

A commonly asked question is how to get PGPLOT to produce valid encapsulated postscript (EPSF) files. Most PGPLOT postscript files are valid EPSF files, except for multi-page plots. Some problems do exists however, valid EPSF files should have a %%BoundingBox comment line in the header of the file, PGPLOT places this line in the trailer of the file where some programs will fail to find it. This comment can be moved into the file header using any text editor. If you do not wish to do this you can also modify the way PGPLOT deals with bounding boxes using the PGPLOT_PS_BBOX environment variable.

Additionally PGPLOT Postscript files do not contain a screen preview section. A device-independent screen preview can be added to PGPLOT files with the program ps2epsi by George Cameron, available with the GhostScript PostScript interpreter.

3.1.2 PGPLOT Environment Variables

Some of the more useful environment variables which control the behaviour of PGPLOT are listed below, the list is not exhaustive, for a full list you should see the relevant sections of the PGPLOT manual.

PGPLOT_DIR Directory name. Unless told otherwise by environment variables PGPLOT_FONT and PGPLOT_RGB, PGPLOT looks for the files it needs at run-time in this directory. The binary font file is grfont.dat and the color-name database is rgb.txt. If this variable is undefined, or if the specified file does not exist in this directory, PGPLOT looks in the current default directory, e.g. setenv PGPLOT_DIR /usr/local/lib/pgplot/. For Starlink users this environment variable will be set at login when you source the Starlink login file, or by typing the starlink command at the UNIX prompt.
PGPLOT_DEV Device specification. If this variable is defined, it is used as the default device specification: if the device specification given to PGBEG (or supplied by the user in response to the PGPLOT prompt) is a blank string, this device specification is used, e.g. setenv PGPLOT_DEV /xwin. The Starlink distributed version of Native PGPLOT has an additional device, /gwm, that allows plotting in GWM Windows.
PGPLOT_TYPE Device type. If this variable is defined, it is used as the default device type: if the device specification supplied to PGBEG consists of a file name without a trailing slash (/) and device type, this device type is assumed, e.g. setenv PGPLOT_TYPE ps
PGPLOT_BUFFER If this variable is defined, with any non-null value, PGPLOT buffers output. The effect is the same as if PGBBUF is called immediately after opening the graphics device, and PGEBUF immediately before closing it. It will have no effect on programs that already include these calls. On some devices, buffering output can lead to large improvements in speed, but enabling buffering may upset synchronization between graphical output and other program activity, e.g. setenv PGPLOT_BUFFER yes
3.1.3 PGPLOT Postscript Environment Variables

Problems dealing with PGPLOT’s Postscript output are amongst the most common complaints about the package. PGPLOT has several environment variables which control the output from its Postscript device driver

PGPLOT_PS_WIDTH (default 7800)
PGPLOT_PS_HEIGHT (default 10500)
PGPLOT_PS_HOFFSET (default 350)
PGPLOT_PS_VOFFSET (default 250) These variables tell PGPLOT how big an image to produce. The driver uses resolution elements of 0.001 inches, (i.e. milli-inches)giving an “apparent” resolution of 1000 pixels per inch. The true resolution is device-dependent. The image dimensions are therefore 7.8 inches horizontally by 10.5 inches vertically (portrait mode) by default. These defaults while defined with American 8.5 x 11-inch paper in mind, rather than the European A4 size sheets, are appropriate in most circumstances. The maximum dimensions of a PGPLOT image are WIDTH by HEIGHT, with the lower left corner offset by HOFFSET horizontally and VOFFSET vertically from the lower left corner of the paper. The “top” of the paper is the edge that comes out of the printer first.
PGPLOT_IDENT If this variable is defined (with any value), the user name, date and time are written in the bottom right corner of each page.
PGPLOT_PS_BBOX Normally, PGPLOT computes the bounding box for the entire plot (the smallest rectangle that includes all the graphics) as it creates the PostScript file, and writes this information in a %%BoundingBox comment in the file trailer. Some programs that read encapsulated PostScript files expect to find the %%BoundingBox comment in the file header, not the trailer, and may not display the plot correctly. To fix this problem, you may need to move the comment from the trailer to the header with a text editor or special program. Alternatively, you can define PGPLOT_PS_BBOX = MAX. This tells PGPLOT to put a %%BoundingBox comment in the header of the PostScript file; the bounding box is one which encompasses the whole plotable area, not a minimal one, because PGPLOT does not know the correct bounding box until it has finished writing the file.
PGPLOT_PS_DRAW_BBOX If this variable is set, the bounding box (the smallest rectangle that includes all the graphics) is drawn on each page.
PGPLOT_PS_VERBOSE_TEXT If this variable is set, the text of each plotted character string is included in the PostScript file as a comment before the sequence of vectors that represents the string. This makes the file slightly larger, but it can be useful if you want to hand edit the PostScript file.
PGPLOT_PS_EOF Normally the output file does not contain special end-of-file characters. But if environment variable PGPLOT_PS_EOF is defined (with any value) PGPLOT writes a Control-D job-separator character at the beginning and at the end of the file. This is appropriate for Apple LaserWriters using the serial interface, but it may not be appropriate for other PostScript devices.
PGPLOT_PS_MARKERS Specify NO to suppress use of a PostScript font for the graph markers; markers are then emulated by line-drawing. If this option is not requested, PGPLOT graph markers are scaled geometrically with the character-height attribute and the line-width attribute is ignored. This is different from most of the other drivers, where the line-width used for markers is set by the line-width attribute rather than the character-height attribute. Requesting this option makes the PostScript driver behave like the other drivers, but it also makes the PostScript files larger.
3.1.4 Special characters inside PGPLOT text strings

Another group of commonly asked questions about PGPLOT concern how to put Greek characters, or super- and sub-scripts into text strings (such as axis annotations) in PGPLOT. The PGPTXT subroutine, along with all the routines that call it such as the higher level PGTEXT or PGLAB) uses escape sequences embedded in the text string to print these characters. Escape sequences are characters which are not plotted, but instead instruct the program to change font, draw superscripts, subscripts or non-ASCII characters (e.g. Greek letters). All escape sequences start with a backslash character “\”. The following escape sequences are defined:

\u Start a superscript, or end a subscript
\d Start a subscript, or end a superscript
\b Do not advance text pointer after plotting the previous character
\fn Switch to Normal font (1)
\fr Switch to Roman font (2)
\fi Switch to Italic font (3)
\fs Switch to Script font (4)
\\ Print a backslash character “\
\x Multiplication sign (×)
\. Centered dot ()
\A Ångström symbol (Å)
\gx Greek letter corresponding to roman letter x
\mn
\mnn Standard graph marker number n or nn (1-31)
\(nnnn) Character number nnnn (1 to 4 decimal digits) from the Hershey character set; the closing parenthesis may be omitted if the next character is neither a digit nor “)”. This makes a number of special characters (e.g. mathematical, musical, astronomical, and cartographical symbols) available. See Appendix B in the PGPLOT manual for a list of available characters.

3.2 The BUTTON library

While plots can be made interactive using standard PGPLOT functions, e.g. PGCURS, the BUTTON library extends this functionality to allow you to easily create interactive FORTRAN applications using graphic buttons, see Figure 2.


pict

Figure 2: Example of an application using the BUTTON PGPLOT extension library.


The program which produced the plot shown in Figure 2 is shown below, and is compiled using the command f77 -o sample sample.f libbutton.a -lpgplot -lX11 (assuming that libbutton.a shared library has been built and is in the current directory).

  !------------------------------------------------------------------------------
  ! Version 23-July-1998                                           File: sample.f
  !------------------------------------------------------------------------------
  ! Copyright N. Cardiel and J. Gorgas, Departamento de Astrofisica
  ! Universidad Complutense de Madrid, 28040-Madrid, Spain
  ! E-mail: ncl@astrax.fis.ucm.es or fjg@astrax.fis.ucm.es
  !------------------------------------------------------------------------------
  ! This program is free software; you can redistribute it and/or modify it
  ! under the terms of the GNU General Public License as published by the Free
  ! Software Foundation; either version 2 of the License, or (at your option) any
  ! later version. See the file gnu-public-license.txt for details.
  !------------------------------------------------------------------------------
  
         PROGRAM SAMPLE
         IMPLICIT NONE
  
         INTEGER I,NB,NCOLOR
         INTEGER NTERM,IDN(8),ITERM
         REAL XC,YC
         REAL XX(100),YY(100)
         REAL XV3,XV4,YV3,YV4
         LOGICAL LCOLOR(8)
         CHARACTER*1 CH
  
  ! Open graphic output
  
         CALL RPGBEGIN(NTERM,IDN,LCOLOR)
  
  ! Plot and label buttons
  
  5      CALL BUTTON(1,’sin’,0)
         CALL BUTTON(2,’cos’,0)
         CALL BUTTON(3,’clear’,0)
         CALL BUTTON(4,’color’,0)
         CALL BUTTON(6,’EXIT’,0)
         CALL BUTTON(7,’mode 0’,0)
         CALL BUTTON(8,’mode 1’,0)
         CALL BUTTON(8,’mode 1’,1)
         CALL BUTTON(9,’mode 2’,0)
         CALL BUTTON(10,’mode 3’,0)
         CALL BUTTON(10,’mode 3’,3)
         CALL BUTTON(11,’mode 4’,4)
         CALL BUTTON(12,’mode 5’,5)
  
  ! Plot box
  
         DO ITERM=NTERM,1,-1
           CALL PGSLCT(IDN(ITERM))
           IF(ITERM.EQ.1)THEN
             CALL RPGENV(0.,1.,-1.1,1.1,0,0)
           ELSE
             CALL PGENV(0.,1.,-1.1,1.1,0,0)
           END IF
           CALL PGLABEL(’X axis’,’Y axis’,’Plot label’)
         END DO
         NCOLOR=1
  
  10     CONTINUE                         ! main loop: button handle
  
         CALL RPGBAND(0,0,0.,0.,XC,YC,CH)
         CALL IFBUTTON(XC,YC,NB)
  
         IF(NB.EQ.0)THEN
  
           WRITE(*,100)’Cursor at:’
           WRITE(*,*)XC,YC
  
         ELSEIF(NB.EQ.6)THEN
  
           CALL BUTTON(6,’EXIT’,5)
           WRITE(*,100)’Press  to EXIT’
           READ(*,*)
           GOTO 20
  
         ELSEIF(NB.EQ.1)THEN              ! plot sin function
  
           CALL BUTTON(1,’sin’,5)
           DO I=1,100
             XX(I)=REAL(I-1)/99.*2.*3.141593
             YY(I)=SIN(XX(I))
             XX(I)=XX(I)/(2.*3.141593)
           END DO
           DO ITERM=NTERM,1,-1
             CALL PGSLCT(IDN(ITERM))
             IF((NCOLOR.NE.1).AND.(LCOLOR(ITERM))) CALL PGSCI(NCOLOR)
             CALL PGLINE(100,XX,YY)
             IF((NCOLOR.NE.1).AND.(LCOLOR(ITERM))) CALL PGSCI(1)
           END DO
           CALL BUTTON(1,’sin’,0)
  
  
         ELSEIF(NB.EQ.2)THEN              ! plot cos function
  
           CALL BUTTON(2,’cos’,5)
           DO I=1,100
             XX(I)=REAL(I-1)/99.*2.*3.141593
             YY(I)=COS(XX(I))
             XX(I)=XX(I)/(2.*3.141593)
           END DO
           DO ITERM=NTERM,1,-1
             CALL PGSLCT(IDN(ITERM))
             IF((NCOLOR.NE.1).AND.(LCOLOR(ITERM))) CALL PGSCI(NCOLOR)
             CALL PGLINE(100,XX,YY)
             IF((NCOLOR.NE.1).AND.(LCOLOR(ITERM))) CALL PGSCI(1)
           END DO
           CALL BUTTON(2,’cos’,0)
  
         ELSEIF(NB.EQ.3)THEN              ! clear plot
  
           CALL BUTTON(3,’clear’,5)
           DO ITERM=NTERM,1,-1
             CALL PGSLCT(IDN(ITERM))
             CALL BUTTQBR(XV3,XV4,YV3,YV4)
             CALL RPGERASW(0.,1.,0.,YV3)
           END DO
           GOTO 5
  
         ELSEIF(NB.EQ.4)THEN              ! change color
  
           CALL BUTTON(4,’color’,5)
           WRITE(*,100)’Current PGPLOT color is number: ’
           WRITE(*,*)NCOLOR
           WRITE(*,100)’Enter new PGPLOT color number: ’
           READ(*,*) NCOLOR
           CALL BUTTON(4,’color’,0)
         END IF
  
         GOTO 10
  
  
  20     CONTINUE                         ! end of main loop: button handle
  
         CALL PGEND
         STOP
  
  100    FORMAT(A,$)
         END

The BUTTON library is available from http://www.ucm.es/info/Astrof/button/button.html along with installation instructions and a description of the library functions.

3.3 The pgperl package

The pgperl package is a dynamically loadable Perl module which interfaces to Fortran PGPLOT library. Perl provides a superset of the features of the useful UNIX utilities awk and sed and is the “Swiss-Army Chainsaw” of UNIX programming. Users of PONGO and SM packages will be familiar with this style of programming.

The simple example shown below, taken from the pgperl distribution, shows how the Fortran routines are interfaced into a simple Perl script, the output from this script is shown in Figure 3.

  #!/usr/local/bin/perl
  
  use PGPLOT;                                 # Load PGPLOT PERL module
  
  print "\nTesting simple point plot...\n\n";
  print "PGPLOT module version $PGPLOT::VERSION\n\n";
  
  pgqinf("VERSION",$val,$len);                # Query PGPLOT version number
  print "PGPLOT $val library\n\n";
  
  $dev = "?" unless defined $dev;             # "?" will prompt for device
  
  pgbegin(0,$dev,1,1);                        # Open plot device
  
  pgscf(2);                                   # Set character font
  pgslw(4);                                   # Set line width
  pgsch(1.6);                                 # Set character height
  
  pgenv(0,10,-5,5,0,0);                       # Define data limits and plot axes
  
  pglabel("X","Y","Data");                    # Print axis labels
  pgsci(5);                                   # Change plot colour
  
  @x=(); @y=(); $i=0;
  
  
  while(<DATA>){
                                              # Read data in 2 columns
                                              # from file handle and
                                              # put in two perl arrays
     ($x[$i], $y[$i]) = split(’ ’);
     $i++;
  }
  
  
  pgpoint($i,\@x,\@y,17);                    # Plot points
                                             # note how perl arrays are passed
  pgend;                                     # Close plot
  
  __DATA__
  1 -4.5
  2 -4
  3  -3.2
  4 -2.1
  5 -1
  6 0.3
  7 1.2
  8 2.4
  9 2.9


pict

Figure 3: Output from the simple pgperl example script.


For every PGPLOT Fortran function the pgperl module provides an equivalent Perl function with the same arguments. Thus the user of the module should refer to the PGPLOT manual to learn all about how to use pgperl and for the complete list of available functions. More information on pgperl can be found at http://www.aao.gov.au/local/www/kgb/pgperl/.

3.3.1 Argument mapping – simple numbers and arrays

Passing simple numbers and arrays to the PGPLOT subroutines via the pgperl module any Fortran REAL, INTEGER or CHARACTER scalar variable maps to a Perl scalar, since Perl doesn’t care about the differences between strings, integers or reals. Therefore to draw a line to point (42,$x):

  pgdraw(42,$x);

To plot ten points of data held in in Perl arrays @x and @y with plot symbol 17 the Perl arrays are passed (by reference) to the PGPLOT module as follows:

  pgpoint(10, \@x, \@y, 17);

Label the axes:

  pglabel("X axis", "Data units", $label);

Draw a single point, note that when N = 1, pgpoint() can take a scalar argument rather than an array:

  pgpoint(1, $x, $y, 17);

3.3.2 Argument mapping – images and 2D arrays

Many of the PGPLOT calls (e.g. pggray) take 2D arrays as arguments. Several methods to access these subroutines are provided by pgperl:

(1)
Pass a reference to a 2D array:
  # Create 2D array
  $x=[];
  
  for($i=0; $i<128; $i++) {
    for($j=0; $j<128; $j++) {
      $$x[$i][$j] = sqrt($i*$j);
    }
  }
  pggray( $x, 128, 128, ...);

(2)
Pass a reference to a 1D array :
  @x=();
  for($i=0; $i<128; $i++) {
    for($j=0; $j<128; $j++) {
       $x[$i][$j] = sqrt($i*$j);
    }
  }
  pggray( \@x, 128, 128, ...);

Here @x is a 1D array of 1D arrays. Alternatively @x could be a flat 1D array with 128x128 elements, 2D routines such as pggray() are programmed to do the right thing as long as the number of elements match.

(3)
If your image data is packed in raw binary form into a character string you can simply pass the raw string:

  read(IMG, $img, 32768);
  pggray($img, $xsize, $ysize, ...);

Here the read() function reads the binary data from a file and the pggray() function displays it as a grey-scale image. This saves unpacking the image data in to a potentially very large 2D perl array. However the types must match. The string must be packed as a “f*” for example to use pggray. This is intended as a short-cut for sophisticated users. Even more sophisticated users will want to download the PDL module which provides a wealth of functions for manipulating binary data.

3.3.3 Argument mapping – function names

Some PGPLOT functions (e.g. pgfunx) take functions as callback arguments. In Perl simply pass a subroutine reference or a name, for example:

  # Anonymous code reference:
  pgfunx(sub{ sqrt($_[0]) },  500, 0, 10, 0);
  # Pass by ref:
  sub foo {
    my $x=shift;
    return sin(4*$x);
  }
  pgfuny(\&foo, 360, 0, 2*$pi, 0);
  # Pass by name:
  pgfuny("foo", 360, 0, 2*$pi, 0);

3.3.4 Argument mapping – general handling of binary data

In addition to the implicit rules mentioned above PGPLOT now provides a scheme for explictly handling binary data in all routines.

If your scalar variable (e.g. \$x) holds binary data (i.e. ’packed’) then simply pass PGPLOT a reference to it (e.g. \$x). Thus one can say:

  read(MYDATA, $wavelens, $n*4);
  read(MYDATA, $spectrum, $n*4);
  pgline($n, \$wavelens, \$spectrum);

This is very efficient as we can be sure the data never gets copied and will always be interpreted as binary.

3.4 Python PGPLOT

Python is one of the new breed of object-oriented programming languages. It is commonly used both for scripting and as a stand alone rapid development language. One of the properties of the language is that it provides facilities for the easy integration of external services. It should therefore come as no surprise that there are currently several different Python interfaces to the PGPLOT subroutine libraries. Due to the nature of the language, being a rapid development tool, it should also come as no surprise that the documentation is a bit on the patchy side.

The most well documented seems to be an interface to PLplot. While based on PGPLOT, and having a similar API, PLplot is not derived from the PGPLOT source and care must be taken when using it if you are used to PGPLOT. More information on PLplot can be found in Section 3.10.

Both of the other interfaces require the installation of the NumPy libraries. NumPy is a collection of C extension modules to the Python programming language which add multi-dimensional array objects. These new objects give Python the number crunching power of numeric languages like Matlab and IDL while maintaining all of the advantages of the general-purpose programming language Python. If you are running Linux it is possible that NumPy may already be installed, else or otherwise, it can be found at http://andrich.net/python/.

One interface also requires you to install SWIG. The Simplified Wrapper and Interface Generator (SWIG) is is a software development tool that connects programs written in C, C++, and Objective-C with a variety of high-level programming languages. SWIG is primarily used with common scripting languages such as Perl, Python, and Tcl/Tk but has been extended to include languages such as Java.

More details of the interfaces available, including some basic usage and installation instructions, can be found on the UBC Python Page at http://www.geog.ubc.ca/~phil/ubc_python.html.

3.5 GLISH PGPLOT

For users of aips++ a PGPLOT binding for GLISH has been developed. While the PGPLOT library itself has a large number of device drivers, only the Tk and PostScript drivers are available from GLISH. More information on the PGPLOT bindings in GLISH can be found at http://aips2.nrao.edu/released/docs/reference/Glish/node97.html.

3.6 ptcl Tk/Tcl and PGPLOT

ptcl registers PGPLOT functions as tcl commands. It allows you to create plots from the command line or from scripts. If the tk extensions are installed it is simple to create graphical user interfaces (GUIs) allowing you to directly interact with the plots. More information on ptcl can be found at http://www.InfoMagic.com/~nme2/ptcl/ptcl.html.

3.7 Starlink/Native PGPLOT

Unbeknown to some, PGPLOT commonly comes in two flavours on Starlink supported machines. The original or “Native” version which uses the low level graphics package GRPCKG, which was also written at Caltech, and a version developed by Starlink, in collaboration with Dr Pearson, which uses RAL GKS. The two versions have identical subroutine interfaces and in most cases, applications can be moved from one version to the other simply by re-linking.

Starlink currently supports both the native version and the Starlink versions. Most packages available in the Starlink Software Collection (USSC) currently are linked against the Starlink version. Work is ongoing to port these applications to the Native version. More information can be found in SUN/15 which describes the use of PGPLOT on Starlink systems. Use of the Starlink/GKS version is deprecated. The Starlink distributed version of Native PGPLOT has an additional device, /gwm, that allows plotting in GWM Windows.

To compile a program and link it to the native version of PGPLOT you should use the following command line:

  % f77 prog.f -L/star/lib ‘pgplot_link‘

While to use the Starlink version you should use:

  % f77 prog.f -L/star/lib ‘pgp_link‘

Or to link the code in an ADAM application:

  % alink prog.f -L/star/lib ‘pgp_link_adam‘

More detailed discussion of the differences between the two versions can be found in SUN/15.

3.8 Graphical Kernel System (GKS)

The Graphical Kernel System (GKS) is a device independent low level graphics system designed to be the kernel of a wide variety of higher-level graphics systems. It is very comprehensive but does not itself set out to provide the most convenient or user-friendly interface for all applications. For high level graphics you are recommended to use the PGPLOT library, while for low-level graphics you may prefer to use SGS rather than play with GKS directly.

More information on the GKS system can be found in the Starlink GKS document SUN/83. While detailed API information can be found in the RAL GKS User Guide and the RAL GKS Reference Manual (obtainable from your Starlink site manager or Starlink user support at RAL).

3.8.1 Enquiring about the display

With the current movement away from pseudo- to true-colour XWindow displays, a common problem when writing software is trying to find what sort of X display the person running your package has available. A good indicator as to the type of X display available is whether the colour table is writable. If it is, then your user is probably sitting in front of a pseudo-colour display. If it’s not, then it is more likely that the display is True Colour (see Section 11).

GKS provides a function to enquire whether the colour table (amongst other attributes) is writable, formally called “Inquire Dynamic Modification of Workstation Attributes”, i.e. 

        CALL GQDWKA( WTYPE, IERR, PLBUN, PMBUN, TXBUN, FABUN,
       :             PAREP, COLREP, WKTR)

Where the variables are defined as:

WTYPE = _INTEGER (Read)
workstation type
IERR = _INTEGER (Returned)
error indicator
PLBUN = _INTEGER (Returned)
polyline bundle representation changeable
PMBUN = _INTEGER (Returned)
polymarker bundle representation changeable
TXBUN = _INTEGER (Returned)
text bundle representation changeable
FABUN = _INTEGER (Returned)
fill area bundle representation changeable
PAREP = _INTEGER (Returned)
pattern representation changeable
COLREP = _INTEGER (Returned)
colour representation changeable
WKTR = _INTEGER (Returned)
workstation transformation changeable

If the colour table is writable, COLREP will be returned as 1. More information on other useful GKS functions can be found in the RAL GKS Reference Manual, which can be found online at http://www.itd.clrc.ac.uk/Publications/RAL-GKS/gks_cat.html.

3.8.2 Compiling and Linking GKS programs

Before compiling a program that uses the GKS include file GKS_PAR you must first execute the command:

  $ gks_dev

Programs are linked with GKS by:

  $ ld objmodule -L/star/lib ‘gks_link‘

3.9 Simple Graphics System (SGS)

The Simple Graphics System (SGS) is a low-level graphics subroutine library sitting above the GKS package allowing easier access to GKS features. Full details of the SGS library package can be found in SUN85.

3.10 PLplot Library

PLplot is a library of C functions that are useful for making scientific plots from a program written in C, C++, or Fortran. The PLplot library can be used to create standard x-y plots, semilog plots, log-log plots, contour plots, 3D plots, mesh plots, bar charts and pie charts. Multiple graphs (of the same or different sizes) may be placed on a single page with multiple lines in each graph. Different line styles, widths and colors are supported. A virtually infinite number of distinct area fill patterns may be used. There are almost 1000 characters in the extended character set. This includes four different fonts, the Greek alphabet and a host of mathematical, musical, and other symbols. The fonts can be scaled to any desired size. A variety of output devices are supported. More information on PLplot can be found at http://emma.la.asu.edu/plplot/.

3.10.1 PLplot and 3D Surface Plots

One important feature available in PLplot, which is not (trivially) available in PGPLOT is the ability to represent a single-valued function of two variables as a surface.

As usual, we would like to refer to a three dimensional point (X, Y, Z) in terms of some meaningful user-specified coordinate system. These are called three-dimensional world coordinates. We need to specify the ranges of these coordinates, so that the entire surface is contained within the cuboid defined by xmin < x < xmax, ymin < y < ymax and zmin < z < zmax. Typically, we shall want to view the surface from a variety of angles, and to facilitate this, a two-stage mapping of the enclosing cuboid is performed. Firstly, it is mapped into another cuboid called the normalized box whose size must also be specified by the user, and secondly this normalized box is viewed from a particular azimuth and elevation so that it can be projected onto the two-dimensional window.

This two-stage transformation process allows considerable flexibility in specifying how the surface is depicted. The lengths of the sides of the normalized box are independent of the world coordinate ranges of each of the variables, making it possible to use “reasonable” viewing angles even if the ranges of the world coordinates on the axes are very different. The size of the normalized box is determined essentially by the size of the two-dimensional window into which it is to be mapped. The normalized box is centered about the origin in the x and y directions, but rests on the plane z = 0. It is viewed by an observer located at altitude, alt, and azimuth, az, where both angles are measured in degrees. The altitude should be restricted to the range zero to ninety degrees for proper operation, and represents the viewing angle above the xy plane. The azimuth is defined so that when az = 0, the observer sees the xz plane face on, and as the angle is increased, the observer moves clockwise around the box as viewed from above the xy plane. The azimuth can take on any value.

The routine PLWIND or PLENV (equivalent to the PGPLOT PGENV routine) is used in the usual way to establish the size of the two-dimensional window.

  XMIN2D = -2.5;
  XMAX2D =  2.5;
  YMIN2D = -2.5;
  YMAX2D =  4.0;
  PLENV(XMIN2D, XMAX2D, YMIN2D, YMAX2D, 0, -2);

The routine PLW3D must then be called to establish the range of the three dimensional world coordinates, the size of the normalized box and the viewing angles. After calling PLW3D, the actual surface is drawn by a call to PLOT3D.

  BASEX = 2.0;
  BASEY = 4.0;
  HEIGHT = 3.0;
  XMIN = -10.0;
  XMAX = 10.0;
  YMIN = -3.0;
  YMAX = 7.0;
  ZMIN = 0.0;
  ZMAX = 8.0;
  ALT = 45.0;
  AZ = 30.0;
  SIDE = 1;
  PLW3D(BASEX, BASEY, HEIGHT, XMIN, XMAX, YMIN, YMAX, ZMIN, ZMAX, ALT, AZ);
  PLOT3D(X, Y, Z, NX, NY, OPT, SIDE);

The values of the function are stored in a two-dimensional array z[][] where the array element z[i][j] contains the value of the function at the point xi, yj. (The two-dimensional array z is a vectored array instead of a fixed size array. z points to an array of pointers which each point to a row of the matrix.) Note that the values of the independent variables xi and yj do not need to be equally spaced, but they must lie on a rectangular grid. Thus two further arrays x[nx] and y[ny] are required as arguments to plot3d to specify the values of the independent variables. The values in the arrays x and y must be strictly increasing with the index. The argument opt specifies how the surface is outlined. If opt = 1, a line is drawn representing z as a function of x for each value of y, if opt = 2, a line is drawn representing z as a function of y for each value of x, and if opt = 3, a net of lines is drawn. The first two options may be preferable if one of the independent variables is to be regarded as a parameter, whilst the third is better for getting an overall picture of the surface. If side is equal to one then sides are drawn on the figure so that the graph doesn’t appear to float.

The routine PLMESH is similar to PLOT3D, except that it is used for drawing mesh plots. Mesh plots allow you to see both the top and bottom sides of a surface mesh, while 3D plots allow you to see the top side only (like looking at a solid object). The side option is not available with PLMESH.

Labelling a three-dimensional or mesh plot is somewhat more complicated than a two dimensional plot due to the need for skewing the characters in the label so that they are parallel to the coordinate axes. The routine PLBOX3 thus combines the functions of box drawing and labelling.

3.11 The libjpeg Library

Let us get it clear right from the start, JPEG is not an image format, instead the ANSI JPEG specification lays down a definition for a family of compression algorithms. In fact the JPEG specification is commonly used in two file formats JFIF and TIFF. The JFIF format is a simple format used for applications that just need to store image data, this is the format that is commonly referred to as being “JPEG” and files in this format usually have .jpg or .jpeg endings. The second, more complex, TIFF file format is used by applications that need to store extra data about images (e.g. colour correction curves). However TIFF, while more flexible, are far less portable than JFIF since different applications implement different subsets of TIFF specification. It should be noted that the official standard for JPEG image compression is not available on-line, you have to order a paper copy from ANSI (or ISO).

The forthcoming JPEG Part 3 standard defines a file format called SPIFF. This format should be backwards compatible with the JFIF image standard, although it has some technical advantages. However its major advantage is that it is an official ANSI standard, where JFIF and TIFF are not. At this time it is unclear as to whether SPIFF will replace JFIF, or whether JFIF will continue to be widely used with the new SPIFF standard being ignored by the rest of the world.

The JPEG standard is optimised for “real-world” images, cartoons and other non-realistic images are not handled well, since JPEG is a lossy algorithm. This means that the output image is not identical to the image, you trade off output image quality against a smaller file size, by adjusting a compression parameter (how lossy the image will be) on image generation.

The Independent JPEG Group (IJG) has a freely redistributable implementation of the JPEG (JFIF) image compression/decompression algorithms. The distributed programs provide conversion between JPEG format and image files formats such as PPM/PGM, GIF, BMP, and Targa. The core programs used to do this is cjpeg to compress an image file into JPEG format and djpeg to decompress a JPEG file back into a conventional format. The core compression and decompression library, libjpeg.so, which is written in C can easily be reused in your own programs programs.

The code is available for both commercial and non-commercial use, and the latest version of the code can be obtained via anonymous FTP from ftp://ftp.uu.net/graphics/jpeg/. Detailed documentation on how to code using the library API is provided along with the distribution (see the libjpeg.doc file).

If you are using a Linux system it is likely that the library, and associated applications, are already installed. RedHat 6.0 ships with libjpeg.so shared object library as part of the standard distribution. The libjpeg library is also distributed as part of the Starlink Base Set, if you are using a Starlink supported machine you can link your program to the Starlink distributed version.

3.12 The giflib Library

GIF files use Lempel-Ziv-Welsh (LZW) compression algorithm to encode the image data to save space, however there is a great deal of controversy over the GIF legal position (see Section 15) due to the Unisys patent issue.

Eric S. Raymond, the maintainer of giflib has this to say about Unisys’s licensing: “Due to Unisys’s increasingly aggressive interpretation of its patent claims on the LZW compression format, I can no longer recommend the use of the giflib library or utilities. giflib may be withdrawn in the near future”.

If you need to deal with GIF images it is recommended that you use the the libungif library.

3.13 The libungif Library

The way round the entire legal mess surrounding the GIF image standard is simply not to use the LZW compression algorithm. The libungif library follows this approach and is designed to handle uncompressed GIFs. These are image files that, while not using LZW compression, are still recognizable as GIF files by decoders which expect normal (compressed) GIFs. The obvious problem is that the uncompressed GIF images will be larger than those encoded using the LZW algorithm. This library speaks both GIF87a and GIF89.

The latest version of the libungif library can be obtained from the anonymous FTP archive at ftp://prtr-13.ucsc.edu/pub/libungif/. Extensive documentation on how to code using the library API is included with the distribution. However if you are using a Linux system it is likely that the library, and associated applications, are already installed. RedHat 6.0 for instance ships with both libgif.so and libungif.so shared object libraries as part of the standard distribution.

3.14 The angif Library

ANGIF is a C library to generate GIF format output. It can generate animated or, a bit of a standard breaker here, true colour (24bpp) GIFs. Due to the legal problems surrounding the format ANGIF is LZW free. Command line test programs are included with the distribution.

It should be noted that ANGIF is in pre-beta release, the only documentation available is the source code comments. Although there doesn’t appear to be a home page for the library yet, it can be downloaded via HTTP from http://phil.ipal.org/freeware/angif/.

3.15 The PNG Format

The Portable Network Graphics (PNG) format was designed to replace the older and simpler GIF format and, to some extent, the much more complex TIFF format.

PNG format several major advantages over GIF. Firstly it uses alpha channels, allowing you to have variable transparency images. Unlike GIF, which implements a simple binary transparency (either a pixel is transparent or opaque) PNG specifies 254 levels of partial transparency. Instead of storing three bytes for each pixel for red, green and blue (RGB), four are now stored, these being red, green, blue and alpha (RGBA). PNG supports both true colour, greyscale and palette-based (pseudo) colour images, unlike GIF which supports only pseudo colour images. All three types of PNG image support alpha channels, although the size of true colour PNG images effectively rules them out for use on the web. Additionally, the format makes use of gamma correction, allowing cross-platform control of image brightness. Finally, the PNG format specifies two-dimensional interlacing (progressive display) rather than the one-dimensional scheme used by GIF images.

PNG also compresses better than GIF in almost every case, but the difference is generally only around 5 to 25 per cent. Additionally, and quite importantly, PNG is free of any legal entanglement.

For those of you wanting to implement programs to handle PNG images, the official PNG library libpng is available via anonymous FTP from ftp://swrinde.nde.swri.edu/pub/png/src/. This library requires zlib, a general purpose lossless compression library. A copy of the library can be found at the same FTP site, but the latest version and more information about the library can be found at ftp://ftp.freesoftware.com/pub/infozip/zlib/index.html

More information on the PNG format, programming resources and supporting applications can be found online at http://www.libpng.org/pub/png/.

3.16 The MNG Format

The Multiple-image Network Graphics (MNG) format has been implemented by the same people that brought you PNG, and it therefore shares the same modular philosophy. The idea behind the format is to provide a home for all of the multi-image capabilities that have no place in PNG. While it has fairly extensive animation and image-manipulation capabilities, there is no serious expectation that it will ever integrate audio or video. In other words this format it intended to replace multi-image GIF animations.

Though the MNG specification itself has not yet been promoted to release status, as of 11 May 1999 it was officially frozen by a vote of the MNG developers. Although relatively mature, MNG is still a draft proposal. There is therefore no general use MNG reference library (along the same lines as libjpeg for example). However, there are already several applications with partial MNG support, the main UNIX application being ImageMagick (see Section 7.1).

3.17 The Python Imaging Library

The Python Imaging Library (PIL) adds an image object to your Python interpreter. You can load image objects from a variety of file formats, including BMP, EPS, GIF, JPEG, PNG, PPM, TIFF and XBM, and apply a rich set of image operations to them. See the feature sheet at http://www.python.org/sigs/image-sig/Imaging.html for more details.

3.18 The gd Library

gd is a C graphics library that allows you to quickly draw images with lines, arcs, text, multiple colors, cut and paste from other images, and flood fills, and write out the result as a PNG file. More information can be found at http://www.boutell.com/gd/gd.html.

A simple example of the gd library in use, taken from the documentation, is shown below:

  /* Bring in gd library functions */
  #include "gd.h"
  
  /* Bring in standard I/O so we can output the PNG to a file */
  #include <stdio.h>
  
  int main() {
          /* Declare the image */
          gdImagePtr im;
          /* Declare an output file */
          FILE *out;
          /* Declare color indexes */
          int black;
          int white;
  
          /* Allocate the image: 64 pixels across by 64 pixels tall */
          im = gdImageCreate(64, 64);
  
          /* Allocate the color black (red, green and blue all minimum).
                  Since this is the first color in a new image, it will
                  be the background color. */
          black = gdImageColorAllocate(im, 0, 0, 0);
  
          /* Allocate the color white (red, green and blue all maximum). */
          white = gdImageColorAllocate(im, 255, 255, 255);
  
          /* Draw a line from the upper left to the lower right,
                  using white color index. */
          gdImageLine(im, 0, 0, 63, 63, white);
  
          /* Open a file for writing. "wb" means "write binary", important
                  under MSDOS, harmless under Unix. */
          out = fopen("test.png", "wb");
  
          /* Output the image to the disk file. */
          gdImagePng(im, out);
  
          /* Close the file. */
          fclose(out);
  
          /* Destroy the image in memory. */
          gdImageDestroy(im);
  }

When run, this program creates an image, allocates two colours (the first colour allocated becomes the background colour) and draws a diagonal line (note that 0, 0 is the upper left corner) before writing the image to a PNG file.

3.18.1 gd from other languages

The gd library can also be accessed from languages other than C. There is an API for both the Perl, see http://stein.cshl.org/WWW/software/GD/GD.html, and Tcl scripting languages, see http://www.tcltk.com/ftp/ellson/.