@code{(require 'eps-graph)}
@noindent
This is a graphing package creating encapsulated-PostScript files.
Its motivations and design choice are described in
@url{http://people.csail.mit.edu/jaffer/Docupage/grapheps}
@noindent
A dataset to be plotted is taken from a 2-dimensional array.
Corresponding coordinates are in rows. Coordinates from any
pair of columns can be plotted.
@defun create-postscript-graph filename.eps size elt1 @dots{}
@var{filename.eps} should be a string naming an output file to be created. @var{size}
should be an exact integer, a list of two exact integers, or #f.
@var{elt1}, ... are values returned by graphing primitives described here.
@code{create-postscript-graph} creates an @dfn{Encapsulated-PostScript} file named @var{filename.eps} containing
@cindex Encapsulated-PostScript
graphs as directed by the @var{elt1}, ... arguments.
The size of the graph is determined by the @var{size} argument. If a list
of two integers, they specify the width and height. If one integer,
then that integer is the width and the height is 3/4 of the width.
If #f, the graph will be 800 by 600.
@end defun
@noindent
These graphing procedures should be called as arguments to
@code{create-postscript-graph}. The order of these arguments is
significant; PostScript graphics state is affected serially from the
first @var{elt} argument to the last.
@defun whole-page
Pushes a rectangle for the whole encapsulated page onto the
PostScript stack. This pushed rectangle is an implicit argument to
@code{partition-page} or @code{setup-plot}.
@end defun
@menu
* Column Ranges::
* Drawing the Graph::
* Graphics Context::
* Rectangles::
* Legending::
* Legacy Plotting::
* Example Graph::
@end menu
@node Column Ranges, Drawing the Graph, PostScript Graphing, PostScript Graphing
@subsubsection Column Ranges
@noindent
A @dfn{range} is a list of two numbers, the minimum and the maximum.
@cindex range
@cindex range
Ranges can be given explicity or computed in PostScript by
@code{column-range}.
@defun column-range array k
Returns the range of values in 2-dimensional @var{array} column @var{k}.
@end defun
@defun pad-range range p
Expands @var{range} by @var{p}/100 on each end.
@end defun
@defun snap-range range
Expands @var{range} to round number of ticks.
@end defun
@defun combine-ranges range1 range2 @dots{}
Returns the minimal range covering all @var{range1}, @var{range2}, ...
@end defun
@defun setup-plot x-range y-range pagerect
@defunx setup-plot x-range y-range
@var{x-range} and @var{y-range} should each be a list of two numbers or the value returned
by @code{pad-range}, @code{snap-range}, or @code{combine-range}.
@var{pagerect} is the rectangle bounding the graph to be drawn; if missing, the
rectangle from the top of the PostScript stack is popped and used.
Based on the given ranges, @code{setup-plot} sets up scaling and margins for making
a graph. The margins are sized proportional to the @var{fontheight}
value at the time of the call to setup-plot. @code{setup-plot} sets two variables:
@table @var
@item plotrect
The region where data points will be plotted.
@item graphrect
The @var{pagerect} argument to @code{setup-plot}. Includes plotrect, legends, etc.
@end table
@end defun
@node Drawing the Graph, Graphics Context, Column Ranges, PostScript Graphing
@subsubsection Drawing the Graph
@defun plot-column array x-column y-column proc3s
Plots points with x coordinate in @var{x-column} of @var{array} and y coordinate @var{y-column} of
@var{array}. The symbol @var{proc3s} specifies the type of glyph or drawing style for
presenting these coordinates.
@end defun
@noindent
The glyphs and drawing styles available are:
@table @code
@item line
Draws line connecting points in order.
@item mountain
Fill area below line connecting points.
@item cloud
Fill area above line connecting points.
@item impulse
Draw line from x-axis to each point.
@item bargraph
Draw rectangle from x-axis to each point.
@item disc
Solid round dot.
@item point
Minimal point -- invisible if linewidth is 0.
@item square
Square box.
@item diamond
Square box at 45.o
@item plus
Plus sign.
@item cross
X sign.
@item triup
Triangle pointing upward
@item tridown
Triangle pointing downward
@item pentagon
Five sided polygon
@item circle
Hollow circle
@end table
@defun plot-text-column array x-column y-column t-column proc3s
Plots text in @var{t-column} of @var{array} at x coordinate in @var{x-column} of @var{array} and y coordinate
@var{y-column} of @var{array}. The symbol @var{proc3s} specifies the offset of the text from the
specified coordinates.
@end defun
@noindent
The offsets available are:
@table @code
@item above
Draws the text centered above at the point.
@item center
Draws the text centered at the point.
@item below
Draws the text centered below the point.
@item left
Draws the text to the left of the point.
@item right
Draws the text to the right of the point.
@end table
All the offsets other than @code{center} are calculated to keep the
text clear of a glyph drawn at the same coordinates. If you need
more or less clearance, use @code{set-glyphsize}.
@node Graphics Context, Rectangles, Drawing the Graph, PostScript Graphing
@subsubsection Graphics Context
@defun in-graphic-context arg @dots{}
Saves the current graphics state, executes @var{args}, then restores
to saved graphics state.
@end defun
@defun set-color color
@var{color} should be a string naming a Resene color, a saturate color, or a
number between 0 and 100.
@code{set-color} sets the PostScript color to the color of the given string, or a
grey value between black (0) and white (100).
@end defun
@defun set-font font height
@defunx set-font font encoding height
@var{font} should be a (case-sensitive) string naming a PostScript font.
@var{height} should be a positive real number.
@var{encoding} should name a PostScript encoding such as
@samp{ISOLatin1Encoding}.
@code{set-font} Changes the current PostScript font to @var{font} with the @var{encoding}
encoding, and height equal to @var{height}. The default font is
@samp{Helvetica} (12pt). The default encoding is
@samp{StandardEncoding}.
@end defun
@noindent
The base set of PostScript fonts is:
@multitable @columnfractions .20 .25 .25 .30
@item Times @tab Times-Italic @tab Times-Bold @tab Times-BoldItalic
@item Helvetica @tab Helvetica-Oblique @tab Helvetica-Bold @tab Helvetica-BoldOblique
@item Courier @tab Courier-Oblique @tab Courier-Bold @tab Courier-BoldOblique
@item Symbol
@end multitable
@noindent
The base set of PostScript encodings is:
@multitable @columnfractions .33 .33 .33
@item StandardEncoding @tab ISOLatin1Encoding @tab ExpertEncoding
@item ExpertSubsetEncoding @tab SymbolEncoding
@end multitable
@noindent
Line parameters do no affect fonts; they do effect glyphs.
@defun set-linewidth w
The default linewidth is 1. Setting it to 0 makes the lines drawn
as skinny as possible. Linewidth must be much smaller than
glyphsize for readable glyphs.
@end defun
@defun set-linedash j k
Lines are drawn @var{j}-on @var{k}-off.
@end defun
@defun set-linedash j
Lines are drawn @var{j}-on @var{j}-off.
@end defun
@defun set-linedash
Turns off dashing.
@end defun
@defun set-glyphsize w
Sets the (PostScript) variable glyphsize to @var{w}. The default
glyphsize is 6.
@end defun
@noindent
The effects of @code{clip-to-rect} are also part of the graphic
context.
@node Rectangles, Legending, Graphics Context, PostScript Graphing
@subsubsection Rectangles
@noindent
A @dfn{rectangle} is a list of 4 numbers; the first two elements are
@cindex rectangle
the x and y coordinates of lower left corner of the rectangle. The
other two elements are the width and height of the rectangle.
@defun whole-page
Pushes a rectangle for the whole encapsulated page onto the
PostScript stack. This pushed rectangle is an implicit argument to
@code{partition-page} or @code{setup-plot}.
@end defun
@defun partition-page xparts yparts
Pops the rectangle currently on top of the stack and pushes @var{xparts} * @var{yparts}
sub-rectangles onto the stack in decreasing y and increasing x order.
If you are drawing just one graph, then you don't need @code{partition-page}.
@end defun
@defvar plotrect
The rectangle where data points should be plotted. @var{plotrect} is set by
@code{setup-plot}.
@end defvar
@defvar graphrect
The @var{pagerect} argument of the most recent call to
@code{setup-plot}. Includes plotrect, legends, etc.
@end defvar
@defun fill-rect rect
fills @var{rect} with the current color.
@end defun
@defun outline-rect rect
Draws the perimiter of @var{rect} in the current color.
@end defun
@defun clip-to-rect rect
Modifies the current graphics-state so that nothing will be drawn
outside of the rectangle @var{rect}. Use @code{in-graphic-context} to limit
the extent of @code{clip-to-rect}.
@end defun
@node Legending, Legacy Plotting, Rectangles, PostScript Graphing
@subsubsection Legending
@defun title-top title subtitle
@defunx title-top title
Puts a @var{title} line and an optional @var{subtitle} line above the @code{graphrect}.
@end defun
@defun title-bottom title subtitle
@defunx title-bottom title
Puts a @var{title} line and an optional @var{subtitle} line below the @code{graphrect}.
@end defun
@defvar topedge
@defvarx bottomedge
These edge coordinates of @code{graphrect} are suitable for passing
as the first argument to @code{rule-horizontal}.
@end defvar
@defvar leftedge
@defvarx rightedge
These edge coordinates of @code{graphrect} are suitable for passing
as the first argument to @code{rule-vertical}.
@end defvar
@defun set-margin-templates left right
The margin-templates are strings whose displayed width is used to
reserve space for the left and right side numerical legends.
The default values are "-.0123456789".
@end defun
@defun rule-vertical x-coord text tick-width
Draws a vertical ruler with X coordinate @var{x-coord} and labeled with string
@var{text}. If @var{tick-width} is positive, then the ticks are @var{tick-width} long on the right side
of @var{x-coord}; and @var{text} and numeric legends are on the left. If @var{tick-width} is
negative, then the ticks are -@var{tick-width} long on the left side of @var{x-coord}; and @var{text}
and numeric legends are on the right.
@end defun
@defun rule-horizontal y-coord text tick-height
Draws a horizontal ruler with Y coordinate @var{y-coord} and labeled with
string @var{text}. If @var{tick-height} is positive, then the ticks are @var{tick-height} long on the top
side of @var{y-coord}; and @var{text} and numeric legends are on the bottom. If @var{tick-height} is
negative, then the ticks are -@var{tick-height} long on the bottom side of @var{y-coord}; and
@var{text} and numeric legends are on the top.
@end defun
@defun y-axis
Draws the y-axis.
@end defun
@defun x-axis
Draws the x-axis.
@end defun
@defun grid-verticals
Draws vertical lines through @code{graphrect} at each tick on the
vertical ruler.
@end defun
@defun grid-horizontals
Draws horizontal lines through @code{graphrect} at each tick on the
horizontal ruler.
@end defun
@node Legacy Plotting, Example Graph, Legending, PostScript Graphing
@subsubsection Legacy Plotting
@defvar graph:dimensions
A list of the width and height of the graph to be plotted using
@code{plot}.
@end defvar
@defun plot func x1 x2 npts
@defunx plot func x1 x2
Creates and displays using @code{(system "gv tmp.eps")} an
encapsulated PostScript graph of the function of one argument @var{func}
over the range @var{x1} to @var{x2}. If the optional integer argument @var{npts} is
supplied, it specifies the number of points to evaluate @var{func} at.
@end defun
@defun plot x1 x2 npts func1 func2 @dots{}
Creates and displays an encapsulated PostScript graph of the
one-argument functions @var{func1}, @var{func2}, ... over the range
@var{x1} to @var{x2} at @var{npts} points.
@end defun
@defun plot coords x-label y-label
@var{coords} is a list or vector of coordinates, lists of x and y
coordinates. @var{x-label} and @var{y-label} are strings with which
to label the x and y axes.
@end defun
@node Example Graph, , Legacy Plotting, PostScript Graphing
@subsubsection Example Graph
@noindent
The file @file{am1.5.html}, a table of solar irradiance, is fetched
with @samp{wget} if it isn't already in the working directory. The
file is read and stored into an array, @var{irradiance}.
@code{create-postscript-graph} is then called to create an
encapsulated-PostScript file, @file{solarad.eps}. The size of the
page is set to 600 by 300. @code{whole-page} is called and leaves
the rectangle on the PostScript stack. @code{setup-plot} is called
with a literal range for x and computes the range for column 1.
Two calls to @code{top-title} are made so a different font can be
used for the lower half. @code{in-graphic-context} is used to limit
the scope of the font change. The graphing area is outlined and a
rule drawn on the left side.
Because the X range was intentionally reduced,
@code{in-graphic-context} is called and @code{clip-to-rect} limits
drawing to the plotting area. A black line is drawn from data
column 1. That line is then overlayed with a mountain plot of the
same column colored "Bright Sun".
After returning from the @code{in-graphic-context}, the bottom ruler
is drawn. Had it been drawn earlier, all its ticks would have been
painted over by the mountain plot.
The color is then changed to @samp{seagreen} and the same graphrect
is setup again, this time with a different Y scale, 0 to 1000. The
graphic context is again clipped to @var{plotrect}, linedash is set,
and column 2 is plotted as a dashed line. Finally the rightedge is
ruled. Having the line and its scale both in green helps
disambiguate the scales.
@example
(require 'eps-graph)
(require 'line-i/o)
(require 'string-port)
(define irradiance
(let ((url "http://www.pv.unsw.edu.au/am1.5.html")
(file "am1.5.html"))
(define (read->list line)
(define elts '())
(call-with-input-string line
(lambda (iprt) (do ((elt (read iprt) (read iprt)))
((eof-object? elt) elts)
(set! elts (cons elt elts))))))
(if (not (file-exists? file))
(system (string-append "wget -c -O" file " " url)))
(call-with-input-file file
(lambda (iprt)
(define lines '())
(do ((line (read-line iprt) (read-line iprt)))
((eof-object? line)
(let ((nra (make-array (A:floR64b)
(length lines)
(length (car lines)))))
(do ((lns lines (cdr lns))
(idx (+ -1 (length lines)) (+ -1 idx)))
((null? lns) nra)
(do ((kdx (+ -1 (length (car lines))) (+ -1 kdx))
(lst (car lns) (cdr lst)))
((null? lst))
(array-set! nra (car lst) idx kdx)))))
(if (and (positive? (string-length line))
(char-numeric? (string-ref line 0)))
(set! lines (cons (read->list line) lines))))))))
(let ((xrange '(.25 2.5)))
(create-postscript-graph
"solarad.eps" '(600 300)
(whole-page)
(setup-plot xrange (column-range irradiance 1))
(title-top
"Solar Irradiance http://www.pv.unsw.edu.au/am1.5.html")
(in-graphic-context
(set-font "Helvetica-Oblique" 12)
(title-top
""
"Key Centre for Photovoltaic Engineering UNSW - Air Mass 1.5 Global Spectrum"))
(outline-rect plotrect)
(rule-vertical leftedge "W/(m^2.um)" 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)
))
(system "gv solarad.eps")
@end example