CIEXYZ response curves


Download Current Version Released Terms
graph-eps 1.15 2011-10-12 Free

Why another graphing program? From web searches it appears that hundreds of graphing programs have been written. They run the gamut from FORTRAN, C, or Java function libraries to special purpose languages to interactive applications. It is possible that an adequate free software graphing program has already been written and runs in Linux; but I didn't find it.

This describes a graphing library written in PostScript. Why PostScript?

What differentiates grapheps from other graphing programs?

About PostScript

PostScript is a stack-oriented reverse Polish notation language. This means that literals and return values are pushed on top of the stack; arguments to functions are popped from the top of the stack.

Here is a simple definition:

  /myvar 3 def
The name myvar is pushed onto the stack. On top of it is pushed 3. The def operator pops these and makes an association so that when myvar is read, its value (3) is pushed onto the stack.

The vector datatype can be constructed using [ and ]. Those elements pushed onto the stack between [ and ] become the elements of the vector.

The PostScript Interface

Most PostScript-generating programs output a prologue defining 10 or 20 graphics primitives named by one or two letter names; then output polylines in the raster coordinate system. The results are not human readable and limit the precision; magnifying part of the graph does not convey any more information.

Instead we write the raw data as a two dimensional array, a vector of vectors:

   [0.3050	9.2	0.05	0.0000	9.5	0.05	0.0000]
   [0.3100	40.8	0.25	0.0003	42.3	0.26	0.0003]
   [0.3150	103.9	0.77	0.0008	107.8	0.80	0.0008]
   [0.3200	174.4	1.64	0.0017	181.0	1.70	0.0017]
   [0.3250	237.9	2.83	0.0029	246.9	2.94	0.0029]
   [0.3300	381.0	4.74	0.0049	395.4	4.92	0.0049]
   [0.3350	376.0	6.62	0.0069	390.2	6.87	0.0069]
   [0.3400	419.5	8.71	0.0090	435.4	9.04	0.0090]
   [0.3450	423.0	10.83	0.0112	439.0	11.24	0.0112]
   [0.3500	466.2	14.33	0.0149	483.8	14.87	0.0149]
   ] def
Four other variables are defined to control graph characteristics: fontsize is height of text characters in points, 1/72 inch; glyphsize is the diameter of scatter-plot glyphs. The margin-templates are strings whose displayed width is used to reserve space for the left and right side numerical legends.
  /fontsize 12 def
  /glyphsize 6 def
  /lmargin-template (-.0123456789) def
  /rmargin-template (-.0123456789) def
PostScript commands are written directly to control other rendering features.

The procedures below are documented in the style of the PostScript Language Reference Manual, second edition with (stack) arguments on the left and results on the right of the procedure name in boldface.


A range is a vector of two numbers, the minimum and maximum values of some dataset.

data k column-range range
Returns the extrema of column k of array data.
range p pad-range range
Expands range by p percent on each end.
range snap-range range
Expands range slightly, per tick computation.
rect xrange yrange setup-plot
Sets up scaling and margins for making a graph. The margins are sized proportional to the fontsize value at the time of the call to setup-plot. setup-plot sets two variables:

The region where data points will be plotted.
The rect argument to setup-plot. Includes plotrect, legends, etc.

Drawing the Graph

Each glyph and plot style is encoded by a "gproc", a vector containing 3 procedures [preamble render postamble].

[array j k] gproc plot-column
Plots points with x coordinate from column j and y coordinate from column k; style is rendered by gproc.

Here are the gprocs provided:

line Draws lines between the points.
impulse Draw line from the x axis to each point.
bargraph Draw rectangle from x axis to each point.
barfill Draw filled rectangle from x axis to each point.
point Minimal point -- invisible if linewidth is 0.
disk Solid round dot.
circle Hollow circle.
square Square box.
diamond Square box at 45.o.
plus Plus Sign.
cross X Sign.
triup Triangle pointing up
tridown Triangle pointing down
pentagon 5-sided polygon.

plot-text-column is like plot-column, but renders text at the specified locations.

[array x-column y-column t-column] gproc plot-text-column

Plots text in t-column of array at x coordinate in x-column of array and y coordinate y-column of array. The symbol proc3s specifies the offset of the text from the specified coordinates.

The offsets available are:

Draws the text centered above at the point.
Draws the text centered at the point.
Draws the text centered below the point.
Draws the text to the left of the point.
Draws the text to the right of the point.

All the offsets other than center are calculated to keep the text clear of a glyph drawn at the same coordinates. If you need more or less clearance, use set-glyphsize.

Graphics State

PostScript maintains a separate stack for graphics state.

Pushes the current graphics state on the graphics-state stack.
Pops and restores the graphics state from the graphics-state stack.


The current color affects text, lines, and region fills.

x setgray
Sets the current color to a gray. 0 setgray is black; 1 setgray is white.
r g b setrgbcolor
Sets the current color to have red, gree, and blue components between 0 and 1.


The current font size is kept in the variable fontsize so that font-dependent sizing scales correctly. Change fontsize thus:
  /fontsize 12 def

/fontname fontsize selectfont
PostScript comes with at least these fonts, of which Helvetica is grapheps' default:
Times             Helvetica	         Courier		   
Times-Italic	  Helvetica-Oblique    	 Courier-Oblique	   
Times-Bold	  Helvetica-Bold	 Courier-Bold	       
Times-BoldItalic  Helvetica-BoldOblique	 Courier-BoldOblique

To change font to Courier:

  /Courier fontsize selectfont

Line Fancy

Line parameters do no affect fonts; they do effect glyphs.

x setlinewidth
The default linewidth is 1. Setting it to 0 makes the lines drawn as skinny as possible. Line width must be much less than glyphsize for readable glyphs.
[] 0 setdash
Turns off dashing.
[3] 0 setdash
Lines are drawn 3-unit on; 3-unit off; ...
[2 1] 0 setdash
Lines are drawn 2-unit on; 1-unit off; ...


In grapheps, a rectangle is a vector of length 4; the first two elements are the x and y coordinates of lower left corner of the rectangle. The other two elements are the width and height of the rectangle.

whole-page rect
Pushes a rectangle for the whole page on the stack.
n m partition-page rect1 ... rectn*m
Pops the rectangle currently on top of the stack and pushes N * M sub-rectangles onto the stack in decreasing y and increasing x order. If you are drawing just one graph, then you don't need partition-page.
rect fill-rect
Pops the rectangle currently on top of the stack and fills that rectangle with the current color.
rect outline-rect
Pops the rectangle currently on top of the stack and draws a line around its perimeter.
rect clip-to-rect
Pops the rectangle currently on top of the stack and modifies the current graphics-state so that nothing will be drawn outside of that rectangle. Use gpop (with previous gpush) to undo the effects of clip-to-rect.

Legends and Rules

String literals in PostScript are delimited by parentheses, eg.

(this is a string literal)
title subtitle title-top
Puts string centered above the plot.
title subtitle title-bottom
Puts string centered below the plot.
xcoord txt tickwidth rule-vertical
Draws a vertical ruler with X coordinate xcoord named txt. If tickwidth is positive, then the ticks are tickwidth long on the right side of xcoord; and txt and numeric legends are on the left. If tickwidth is negative, then the ticks are -tickwidth long on the left side of xcoord; and txt and numeric legends are on the right.
leftedge x-coord
rightedge x-coord
These are the X coordinate of the left and right edges of plotrect (set by setup-plot). They are intended to pass as the xcoord argumnet to rule-vertical.
ycoord txt tickheight rule-horizontal
Draws a horizontal ruler with Y coordinate ycoord named txt. If tickheight is positive, then the ticks are tickheight long on the right side of ycoord; and txt and numeric legends are on the left. If tickheight is negative, then the ticks are -tickheight long on the left side of ycoord; and txt and numeric legends are on the right.
topedge y-coord
bottomedge y-coord
These are the Y coordinate of the top and bottom edges of plotrect (set by setup-plot). They are intended to pass as the ycoord argumnet to rule-horizontal.
Draws the y-axis.
Draws the x-axis.
Draws vertical lines through `graphrect' at each tick on the vertical ruler.
Draws horizontal lines through `graphrect' at each tick on the horizontal ruler.


The first line of a graphing file must be:

  %!PS-Adobe-3.0 EPSF-3.0
The second line declares the lower left and upper right coordinates of the bounding box of the page. Some programs treat these coordinates as being 72 dots per inch.
  %%BoundingBox: 0 0 750 500
Other meta-information fields you might like to generate are:
  %%Title: Solar Irradiance
  %%For: A lark
  %%CreationDate: Fri Nov 14 17:55:30 2003
After any other meta-information fields goes:
The contents of graph-eps should then be copied to the file.

After this the data arrays should be written:

   [0.3050	9.2	0.05	0.0000	9.5	0.05	0.0000]
   [0.3100	40.8	0.25	0.0003	42.3	0.26	0.0003]
  ] def
Then the graph drawing program should be written, followed by:

Using Grapheps from Other Languages

The previous section detailed the structure of a grapheps file. Any programming language with the ability to write text to a file can thus create graphs. I have written a package for the SLIB Scheme library which does so. An example of its use is the Scheme code:

(let ((xrange '(.25 2.5)))
   "solarad.eps" '(600 300)
   (setup-plot xrange (column-range irradiance 1))
   (title-top "Solar Irradiance")
    (set-font "Helvetica-Oblique" 12)
     "Key Centre for Photovoltaic Engineering UNSW - Air Mass 1.5 Global Spectrum"))
   (outline-rect plotrect)
   (rule-vertical leftedge "W/(m^" 10)
   (in-graphic-context (clip-to-rect plotrect)
                       (plot-column irradiance 0 1 'line)
                       (set-color "Bright Sun")
                       (plot-column irradiance 0 1 'mountain)
   (rule-horizontal bottomedge "Wavelength in .um" 5)
   (set-color 'seagreen)

   (setup-plot xrange '(0 1000) graphrect)
   (in-graphic-context (clip-to-rect plotrect)
                       (set-linedash 5 2)
                       (plot-column irradiance 0 2 'line))
   (rule-vertical rightedge "Integrated .W/(m^2)" -10)))
Which produces this graph: Graph of Solar Irradiance

By generating this PostScript code:

 [	305.0e-3	9.2	50.0e-3	0.0	9.5	50.0e-3	0.0]
 [	310.0e-3	40.8	250.0e-3	299.99999999999997e-6	42.3	260.0e-3	299.99999999999997e-6]
 [	315.0e-3	103.9	770.0e-3	800.0e-6	107.8	800.0e-3	800.0e-6]
 [	3.573	11.5	959.33	995.6e-3	11.9	995.61	995.6e-3]
 [	3.765	9.4	961.54	997.9e-3	9.8	997.91	997.9e-3]
 [	4.045	7.2	963.66	1.0	7.5	1.0e3	1.0]
] def
[ 250.0e-3 2.5 ] scm:G23 1 column-range setup-plot
(Solar Irradiance () title-top
/fontsize 12 def /Helvetica-Oblique fontsize selectfont
() (Key Centre for Photovoltaic Engineering UNSW - Air Mass 1.5 Global Spectrum) title-top
plotrect outline-rect
leftedge (W/(m^ 10 rule-vertical
plotrect clip-to-rect
[ scm:G23 0 1 ] line plot-column
.995 .827 .235 setrgbcolor
[ scm:G23 0 1 ] mountain plot-column
bottomedge (Wavelength in .um) 5 rule-horizontal
.035 .345 .349 setrgbcolor
graphrect [ 250.0e-3 2.5 ] [ 0 1000 ] setup-plot
plotrect clip-to-rect
[ 5 2 ] 0 setdash
[ scm:G23 0 2 ] line plot-column
rightedge (Integrated .W/(m^2)) -10 rule-vertical


I am a guest and not a member of the MIT Computer Science and Artificial Intelligence Laboratory.  My actions and comments do not reflect in any way on MIT.
agj @
Go Figure!