.\"     groff -me Using.me
.\"
.\"     Using.me
.\"     Short manual for the At Plotter Widget Set V6.0
.\"
.\"     SCCSID = @(#) Title.me (V6.0) Thu Aug  6 09:10:42 1992
.\"
.\"     Peter Klingebiel, University of Paderborn
.\"
.\"     Based on the document 'Using the AthenaTools Plotte Widget Set'
.\"     Version V5-beta from Gregory Bond, BBY
.\"
.\"
.\"     Copyright 1991 by Burdett, Buckeridge and Young Ltd.
.\"     Copyright 1992 by University of Paderborn
.\"
.\"     All rights reserved.
.\"
.\"     Permission to use, copy, modify, and distribute this software
.\"     and its documentation for any purpose and without fee is hereby
.\"     granted, provided that the above copyright notice appear in all
.\"     copies and that both that copyright notice and this permission
.\"     notice appear in supporting documentation, and that the name of
.\"     the firms, institutes or employers of the authors not be used in
.\"     advertising or publicity pertaining to distribution of the
.\"     software without specific, written prior permission.
.\"
.\"     THE AUTHORS AND THEIR FIRMS, INSTITUTES OR EMPLOYERS DISCLAIM ALL
.\"     WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
.\"     WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
.\"     AUTHORS AND THEIR FIRMS, INSTITUTES OR EMPLOYERS BE LIABLE FOR
.\"     ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\"     WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
.\"     IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
.\"     ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
.\"     THIS SOFTWARE.
.\"
.\"
.\"     Layout
.\"
.\" Use helvetica for text fonts 1..4, courier for source font 5
.fp 1 HR
.fp 2 HI
.fp 3 HB
.fp 4 HBI
.fp 5 CR
.\" Pagesize A4, margins
.ll 6.5i
.pl 11.5i
.m1 3v
.m2 3v
.m3 2v
.m4 4v
.nh
.\" Fontsize 11p normal text, 13p headings and titles
.nr pp 11
.nr qp 11
.nr sp 13
.nr tp 13
.\"
.\"     Definitons
.\"
.ds PT "The\ AthenaTools\ Plotter\ Widget\ Set
.ds PV "Version\ 6.0
.ds PD "August 1992
.\"
.\"     Macros
.\"
.\" Macro chapter title, headers and footers
.\" .CH chapter_title
.de CH
.he ''\\*(PT\ \ \ \\*(PV''
.fo '\\*(PD''%'
.nr sp 15
.sh 1 "\\$1"
.nr sp 13
.sp 1.5
.pp
..
.\" Start source code
.de SS
.(b
.sp 0.5
.nf
.ft 5
.vs -3
.ps -2
..
.\" End source code
.de SE
.ps +2
.vs +3
.ft 1
.sp 0.5
.)b
.fi
..
.\" Header output macro with horizontal line
.de $h
.rm |z
.if !\\n(?c \
\{\
.       if e .ds |z "\\*(|0
.       if o .ds |z "\\*(|1
.\}
.if !\(ts\\*(|z\(ts\(ts \
\{\
.       sz 9
.       tl \\*(|z
.       hl
.       sz \\n(pp
.\}
.rm |z
..
.\" Footer output macro with horizontal line
.de $f
.rm |z
.if \\n(?c \
\{\
.       if e .ds |z "\\*(|0
.       if o .ds |z "\\*(|1
.\}
.if \(ts\\*(|z\(ts\(ts \
\{\
.       if e .ds |z "\\*(|2
.       if o .ds |z "\\*(|3
.\}
.if !\(ts\\*(|z\(ts\(ts \
\{\
.       sz 9
.       hl
.       tl \\*(|z
.       sz \\n(pp
.\}
.rm |z
..
.\"
.\"     End header/definitions/macros
.\"
.\"     Chapter 1: Introduction
.\"
.CH "Introduction"
This document is supposed to be an overview document
and describes how to use the AthenaTools Plotter Widget Set
to add graphs to your X programs.
It is assumed the reader is familiar in general
with programming X and widget sets.
All of the detailed information regarding resources etc.
is documented in the relevant manual pages.
.pp
The AthenaTools Plotter Widget Set provides
many of the features scientific and business users need
in a graph that will be embedded in another program.
Some highlights of the plotter widgets are
.sp 0.5
.bu
X-Y plots for scientific-style graphics.
.sp 0.5
.bu
Line and bar plots for business-style graphics.
.sp 0.5
.bu
Automatic or manual scaling of axis values,
automatic selection of tic and subtic points.
.sp 0.5
.bu
Callbacks to get the current pointer position
in the plotting area in pixel and user coordinates,
and to cut off a range or rectangle from
the plotting area for zooming in, for example.
.sp 0.5
.bu
Very flexible text facilities,
including mathematical symbols,
sub- and super-scripts, font changes etc.
These text facilities can be used for legend names,
graph titles, axis labels, tic labels,
or attached to arbitrary points on the graph
in either pixel space or user space.
.sp 0.5
.bu
Unlimited number of plots on each graph,
with each plot independently specified\**.
.(f
\**Each plot on the graph is a different widget.
.)f
.sp 0.5
.bu
Encapsulated PostScript generated that closely
matches the screen output.
.sp 0.5
.bu
Logarithmic and linear axes,
or axes labeled at arbitrary points
with arbitrary strings
(which is very useful for labeling axes with dates, for example).
.sp 0.5
.bu
Very flexible axis handling.
There are up to four axes on the graph,
and any plot can be associated with
either X axis and either Y axis.
.sp 0.5
.bu
"Frame" axes that get their scaling etc.
from another axis object,
on either the same or another graph.
This makes coordination between related graphs very easy.
.sp 0.5
.bu
A Fast Update mode that can quickly redraw rapidly-changing data\**.
.(f
\**This is implemented but untested at this point in time.
.)f
.sp 0.5
.bu
Easy access to application data.
The widget set is designed to access
application data that is stored in an array of structures;
it can pull data out of structures in either
Float, Double or Integer format,
but other data types are easily added.
.sp
.pp
The Plotter Widget is a widget
based on Xlib and Xtoolkit.
It is intended to be used in conjunction
with other widget sets based on Xlib and Xtoolkit,
like the Athena Widget Set or
the OSF/Motif Widget Set.
The Plotter Widget Set
is not intended for stand-alone graphic applications
(use GNUplot or similar for that).
It is not a 3D library,
and is not really a replacement
for Harvard Graphics or some such.
It cannot do Pie charts or other non-XY type graphs.
.bp
.\"
.\"     Chapter 2: Usage Walkthrough
.\"
.CH "Usage Walkthrough"
This section gives a quick overview
of how to program using the
AthenaTools Plotter Widget Set,
and explains what sort of data the plotter
expects from your application.
There can be found four test programs
using the Athena Widget Set
in the subdirectory \f5athena\f1,
and one larger test program
using the OSF/Motif Widget Set
in the subdirectory \f5motif\f1.
You can make and run these programs by typing
\f5xmkmf\f1 to create the \f5Makefiles\f1
from the \f5Imakefiles\f1,
and then typing \f5make all\f1 or \f5make\f1
to create the executables.
All these programs are written in C
and use no resource files to run properly.
This means anyone should be able to compile and run them.
You should be able to transfer the concepts to your
favourite development environment with no problems.
The example source code in this section
is taken from two test programs
that came with the source.
The file \f5Plot.c\f1,
containing all the stuff how to
use and program the plotter widgets,
from the Motif based example program \f5mplot\f1,
and the file \f5sample_prog.c\f1,
a Athena based application,
are completely listed in Section 5.
The title page of this document,
and the Figure 1 below,
a plotter PostScript output from \f5mplot\f1,
show a typical scientific use of the plotter widget set.
.sp
.hl
.PSPIC Mplot.eps
.sp 0.5
.ce 1
\f3Figure 1\f1: PostScript Output From The \f5mplot\f1 Test Program
.sp 0.5
.hl
.sh 2 "Creating The Plotter And The Axes"
.pp
The general arrangement is as follows.
For each graph, you create a single AtPlotter widget.
This is a widget, and has an X window,
the same as most other widgets.
You then create some axis objects
(some subclass of AtAxisCore, usually AtXYAxis or AtAxis)
as children of the AtPlotter
and attach them to the parent by doing an
\f5XtSetValues()\f1 using the \f5XtNxAxis\f1
and \f5XtNyAxis\f1 resources.
In the sample program \f5mplot\f1,
a more scientific use of the plotter widgets,
this is done in the procedure \f5MakePlotter()\f1
which is called when the application shell,
the main window, some buttons and other widgets,
and a parent form and frame for the plotter are created:
.SS
	#include <At/Plotter.h>
	#include <At/XYAxis.h>

	Widget parent;          /* Already created! */
	Widget plotter, xaxis, yaxis;
	Arg args[8];
	int n;

	/* Create the plotter */
	n = 0;
	XtSetArg(args[n], XtNwidth, 400); n++;
	XtSetArg(args[n], XtNheight, 300); n++;
	XtSetArg(args[n], XtNborderWidth, 0); n++;
	XtSetArg(args[n], XtNshowLegend, True); n++;
	plotter = XtCreateManagedWidget("plotter", atPlotterWidgetClass,
					parent_widget, args, n);

	/* Create the X axis */
	n = 0;
	XtSetArg(args[n], XtNlabel, "Time"); n++;
	XtSetArg(args[n], XtNaxisWidth, 1); n++;
	xaxis = XtCreateWidget("xaxis", atXYAxisWidgetClass, plotter, args, n);

	/* Create the Y axis */
	n = 0;
	XtSetArg(args[n], XtNlabel, "Amplitude"); n++;
	XtSetArg(args[n], XtNaxisWidth, 1); n++;
	XtSetArg(args[n], XtNvertical, True); n++;
	yaxis = XtCreateWidget("yaxis", atXYAxisWidgetClass, plotter, args, n);

	/* Attach X and Y axes to the plotter */
	n = 0;
	XtSetArg(args[n], XtNxAxis, xaxis); n++;
	XtSetArg(args[n], XtNyAxis, yaxis); n++;
	XtSetValues(plotter, args, n);
.SE
This is the minimal configuration for graphs
using the AthenaToolkit Plotter Widget Set\**.
.(f
\**A complete listing of the source file
\f5Plot.c\f1 from which the examples are taken,
is enclosed in Section 5.1.
.)f
.sh 2 "Creating Plot Objects And Attaching Data"
.pp
Then, for each data item to plot on this graph,
you create a plot object,
in this example AtXYLinePlot, a subclass of AtXYPlot:
.SS
	#include <At/XYLinePlot.h>

	Widget plotter;         /* Already created! */
	Widget line1;
	Arg args[4];
	int n;

	/* Create line 1 */
	n = 0;
	XtSetArg(args[n], XtNlegendName, "sinus-points"); n++;
	XtSetArg(args[n], XtNplotLineStyle, AtLineDOTTED); n++;
	XtSetArg(args[n], XtNplotMarkType,  AtMarkRECTANGLE); n++;
	line1 = XtCreateWidget("line1", atXYLinePlotWidgetClass,
			       plotter, args, n);
.SE
.pp
When the plot objects are created,
you can use the member functions for that plot object
to attach it to your application data.
In the test program the data,
a simple polygon and some curves,
are created from within the routine \f5MakeDemoData()\f1,
or are read in from a data file in the procedure
\f5ReadPlotData()\f1.
Once the data are attached
and the AtPlotter is first displayed,
it will automatically calculate all the bounds,
scaling etc. and display the graph.
.pp
In contrast to previous releases of this widget set\**,
.(f
\**Up to Version 4.
.)f
copies of the data are not required.
The assumption is your application data
are stored in an array of structures,
statically declared as in \f5MakeDemoData()\f1
or dynamically allocated as in \f5ReadPlotData()\f1.
For the AtXYLinePlot class there are
three pre-defined data types
\f5AtDoublePoint\f1, \f5AtFloatPoint\f1 and \f5AtIntPoint\f1
which correspond to the currently supported data types
\f5AtDouble\f1, \f5AtFloat\f1 and \f5AtInt\f1.
These are simple structs containing
one item for the X coordinate and
one item for the Y coordinate of a data point.
\f5AtDoublePoint\f1, for example,
is defined in \f5At/XYLineplot.h\f1 as follows:
.SS
	typedef struct {
	    double x;           /* X coordinate */
	    double y;           /* Y coordinate */
	} AtDoublePoint;

.SE
An array of such a struct type is just
a line composed of its data points.
For the polygon in Figure 1,
a connected line defined of 6 points,
you would declare an array of 6 data points:
.SS
	#include <At/XYLinePlot.h>

	#define PNUM 6
	static AtDoublePoint polygon[PNUM];
.SE
and attach the polygon to a plot object.
using the member routine
\f5AtXYLinePlotAttachDoublePoints()\f1\**.
.(f
\**This routine is a \f5#define\f1'd alias for
the routine \f5AtXYPlotAttachData\f1.
.)f
In the example this is done in the procedure \f5AttachData()\f1:
.SS
	Widget line3;           /* Already created! */

	/* Attach polygon from predefined type AtDoublePoint to line3 */
	AtXYLinePlotAttachDoublePoints(line3, &polygon[0], 1, PNUM);
.SE
The parameters for this routine are :
.sp 0.5
.bu
The widget \f5line3\f1 (a subclass of AtXYPlot)
you are attaching the data to.
.sp 0.5
.bu
A pointer \f5&polygon[0]\f1 to the first item
in the static array.
.sp 0.5
.bu
The index of the first item in the array
which should be plotted
(often 1 but not always).
.sp
.bu
The number of items \f5PNUM\f1 in the array
which should be plotted.
.sp 0.5
.pp
The data pointed to in this routine should remain valid
until the next attach call is made
(as it may be accessed if the window resizes
or if other plots change or if PostScript output is generated).
Setting the address to NULL and the count to 0
will effectively undisplay the plot.
If the underlying data has changed,
a new call to the attach routine
should be made so that the change is noted
and new bounds are calculated.
.pp
In addition,
providing your application is suitably arranged,
the plot widgets can read the information straight out
of your existing structures.
Assume you have defined a record type,
composed of one common X value and two Y values,
like the \f5struct point\f1:
.SS
	struct point {
	    double xval;        /* The X value  */
	    double yval1;       /* The Y values */
	    double yval2;
	};
.SE
and you have 24 items of that type.
You would then declare an array of 24 records:
.SS
	#define CNUM 24
	static struct point curve[CNUM];
.SE
and use the appropriate member routine
\f5AtXYLinePlotAttachData()\f1\**
.(f
\**This routine also is just a \f5#define\f1'd alias for
the routine \f5AtXYPlotAttachData()\f1.
.)f
to attach the data.
This routine is more general than
the above denominated member routine
\f5AtXYLinePlotAttachDoublePoints()\f1
and somewhat more complicated:
.SS
	/* Attach curve from own defined type point to line1 */
	AtXYLinePlotAttachData(line1,
	    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
	    (XtPointer) &curve[0].yval1, AtDouble, sizeof(struct point),
	    1, CNUM);
.SE
The parameters are as follows:
.sp 0.5
.bu
The widget \f5line1\f1 (a subclass of AtXYPlot)
you are attaching the data to.
.sp 0.5
.bu
A pointer \f5&curve[0].xval\f1 to the first X value
data item in the array.
.sp 0.5
.bu
The type \f5AtDouble\f1 of that item.
.sp 0.5
.bu
A parameter \f5sizeof(struct point)\f1 called the Stride,
which is the number of bytes between successive data items.
In most applications, that will be the size
of the structure you are accessing.
.sp 0.5
.bu
A pointer \f5&curve[0].yval1\f1 to the first Y value
data item in the array.
.sp 0.5
.bu
The type \f5AtDouble\f1 of that item.
.sp 0.5
.bu
The stride parameter \f5sizeof(struct point)\f1.
.sp 0.5
.bu
The index of the first item in the array.
.sp 0.5
.bu
The number of items in the array which shoud be plotted.
.sp 0.5
.pp
Once the \f5XtMainLoop()\f1 routine is called
after creating the plotter, the axes and the lines,
and after attaching the data to the lines,
the graph magically appears.
.sh 2 "Using The LinePlot And BarPlot Classes"
.pp
As an example for a more business-like graphic
using line and bar plots and two Y axes,
consider the second test program \f5sample_prog\f1,
a simple accounting application
for a Widget Distribution Company\**.
.(f
\**The complete listing of \f5sample_prog.c\f1
is enclosed in Section 5.2.
.)f
You might wish to display the weekly sales
and profit figures for the sale of Widgets for the past year.
But your database stores only the volume sold,
the sale price and the purchase price.
So you would declare a structure like this:
.SS
	struct profits {
	    /* From database */
	    long volume;
	    float buy_price;
	    float sell_price;
	    /* Calculated values */
	    double sales;
	    double cost;
	    double profit;
	};
.SE
.hl
.PSPIC Sample.eps
.sp 0.5
.ce 1
\f3Figure 2\f1: PostScript Output From The \f5sample_prog\f1 Program
.sp 0.5
.hl
.sp
You would then declare an array of 52 structs:
.SS
	#define NUM_WEEKS 52
	struct profits profits[NUM_WEEKS];
.SE
.pp
Two routines (called \f5ReadFromDatabase()\f1
and \f5CalculateProfits()\f1 in the sample program)
could read in the weekly figures from the database
and run through a loop to calculate sales,
cost and profits for each week.
This creates the data to be plotted.
Like in the first example you have to create
the plotter and its children,
when application shell and parent form are created.
The routine \f5MakePlotter()\f1 does that:
it creates the main plotter,
then the X axis for the week number,
the Y axis for profit,
and the Y2 axis (on the right hand side) for volume.
Then it creates the plot objects,
one AtLinePlot object for profits
and one AtBarPlot object for volume.
.pp
The routine \f5AttachData()\f1 attaches
the calculated data to the plot objects
using the member routine
\f5AtLinePlotAttachData()\f1\**,
.(f
\**This routine is alos just a \f5#define\f1'd
alias for the routine \f5AtSPlotAttachData()\f1.
.)f
with a call like:
.SS
	AtLinePlotAttachData(line, (XtPointer) &profits[0].profit,
			     AtDouble, sizeof(struct profits), 1, NUM_WEEKS);
.SE
.pp
The parameters,
similar to that in the first example above,
are as follows:
The widget \f5line\f1 (a subclass of AtSPlot)
you are attaching the data to,
a pointer \f5&profits[0].profile\f1 to the first data item,
the type \f5AtDouble\f1 of that item,
the stride \f5sizeof(struct profits)\f1,
the integer X axis value of the first item in the list,
and the number \f5NUM_WEEKS\f1 of items in the list.
The X axis value of the last item will be (start + num - 1).
.pp
The volume data is attached to the AtBarPlot widget
with the equivalent call\**
.(f
\**The \f5AtBarPlotAttachData\f1 is also
a \f5#define\f1'd alias for \f5AtSPlotAttachData\f1.
.)f
:
.SS
	AtBarPlotAttachData(bar, (XtPointer) &results[0].volume,
			    AtInt, sizeof (struct profits), 0, NUM_WEEKS);
.SE
with the same parameters as above.
.sh 2 "Differences Between The AtXYLinePlot And AtLinePlot Classes"
.pp
Lets close this section by pointing out
the main differences between
the AtXYLinePlot and the AtLinePlot class,
as can be seen in the examples
given in the above subsections:
.sp 0.5
.bu
.sp 0.5
When attaching data to an object
of the AtXYLinePlot class
you have to specify explicitely
the X and the Y values of your data,
no matter if you use one of the
pre-defined structure types like \f5AtDoublePoint\f1
or specify your own data types.
As you would expect
you can define any range for
the X and the Y values,
as it is needed for most
scientific applications,
including connected lines
like the polygon in the first
example (see Section 2.1).
.bu
.sp 0.5
In contrast to an AtXYLinePlot object
objects from the AtLineplot or AtBarPlot classes
require data with a continuous X range.
The X values are taken as integers
from the indices in the data arrays.
You can set the \f5XtNticMultiplier\f1
resource to make the X indices and the tic labels
more conform to your real X data,
but it's impossible
to specify a range from xmin = -3 to xmax = +3,
for example, or to plot connected lines.
.bp
.\"
.\"     Chapter 3: More Detail
.\"
.CH "More Detail"
.sh 2 "Definitions"
.pp
Lets start by defining some terms so we all understand
what we are talking about.
.sp 0.5
.bu
.b Object
.br
Any X Toolkit Intrinsics object
that is a subclass of the Object class.
\f5XtSetValues\f1 operates on Objects
and \f5XtCreateWidget()\f1 creates them.
.sp 0.5
.bu
.b Widget
.br
Any Object that is a subclass of Core and thus has a window.
.sp 0.5
.bu
.b Graph
.br
The entire display of a Plotter widget
which includes the main plotter widget and all children,
axes and plots.
There can be multiple graphs,
and hence multiple AtPlotter widgets,
in one program.
.sp 0.5
.bu
.b Plot
.br
A single data Object plotted on a graph.
(i.e. a single line or bar plot).
One AtPlot Object per plot,
multiple plots per graph.
.sp 0.5
.bu
.b User\ Space,\ Pixel\ Space
.br
User space is the realm of real numbers
that the graph is attempting to plot.
Pixel space is the screen coordinates that X windows works in.
All application data is expressed in user space,
and is converted to pixel space (or pixel locations)
by the various recalc routines inside the plotter.
Application programmers should deal with user space only,
and not need to touch pixel space.
.sp 0.5
.bu
.b Refresh
.br
Simply redraw one plot on the graph.
No screen clear or redraw of other child Objects required.
.sp 0.5
.bu
.b Redraw
.br
Simply refresh the on screen image of the whole plotter widget.
No calculation required.
.sp 0.5
.bu
.b Relayout
.br
The pixel dimensions of the graph widget have changed
(e.g. because the user resized the application)
or the size of one of the component parts
(e.g. an axis is wider because the font changed),
but the data that is plotted is unchanged.
.sp 0.5
.bu
.b Rescale
.br
The data has changed and the existing axis bounds are not sufficient.
New axis bounds are required,
but no layout has changed and all axes are in the same spot.
Is concerned with min/max of axis values, tic values and intervals etc.
.sp 0.5
.bu
.b Recalc
.br
Either pixel location or data has changed for a plot,
and the cached pixel values need to be recalculated.
Can be for a single child or the whole graph.
.sp 0.5
.pp
A rescale implies a recalc, and a relayout implies a recalc,
but relayout and rescale are orthogonal
(i.e. one doesn't necessarily imply the other).
A recalc implies a redraw.
.bp
.sh 2 "Widget Class Hierarchy"
.pp
Figure 3 below shows the class inheritance of
the AthenaTools Plotter Widget Set:
.sp
.hl
.PSPIC Classes.eps
.sp 0.5
.ce 1
\f3Figure 3\f1: The Plotter Widget Set Class Hierarchy
.sp 0.5
.hl
.sp
As can be seen, most of the widgets in the set
are actually Objects and don't have an X window of their own.
They draw on the the window supplied by the parent AtPlotter widget.
A minimal graph includes a single AtPlotter widget
that is the parent of two Objects that are subclasses of AtAxisCore,
and one Object that is a subclass of AtSPlot or AtXYPlot.
.pp
The AtPlot, AtSPlot, AtXYPlot and AtAxisCore widget classes
are simply placeholders for some logic and resources;
you shouldn't ever need to make Objects of these types.
The AtPlotter will only accept children
that are a subclass of AtPlot,
and AtPlot classes will only accept AtPlotter widgets as a parent.
We will examine each of the elements in turn.
.sh 2 "Elements of the Graph"
.pp
Figure 4 on the next page shows the various areas of the graph.
The string along the top is known as the title.
The font, size, color and style
(i.e. roman, \f2italic\f1, \f3bold\f1 etc.)
and the string itself can be set using resources of the AtPlotter widget.
.(z
.PSPIC Layout.eps
.sp 0.5
.ce 1
\f3Figure 4\f1: Elements Of The Plotter Window
.sp 0.5
.hl
.)z
The font family (see Section 4.1)
is the same for all the strings in the AtPlotter widget.
Specifying a title as the empty string removes
the title and reclaims the space for the main part of the graph.
.pp
Along the right hand edge of the graph is the legend.
The AtPlotter maintains details about the legend
as Constraint resources on behalf of the children.
The AtPlotter has resources to set the string,
size and style of the legend title,
as well as the size and style of the legend labels.
The color of the text in the legend is set in the AtPlotter
and affects all the text in the legend.
The actual legend strings are constraint resources
and belong (logically) to the child.
Each item (apart from the title) in the legend
is drawn by the child plot,
and exactly matches the corresponding plot in the main graph area.
The legend is controlled by the AtPlotter widget,
and the resource \f5XtNdrawLegend\f1 controls whether it is displayed.
.pp
There are two axes used in the sample graph shown in Figure 1,
the horizontal axis is a logarithmic axis of class AtXYAxis,
the vertical axis is a linear axis, also of class AtXYAxis.
All the values displayed on these axes
were calculated automatically
(although you can manually set the maximum,
minimum and the distance between tic marks if required).
There are 3 tics on the logarithmic X axis,
and 5 tics on the linear Y axis.
Each tic has a label and a tight dotted grid line associated with it.
The color of the axis, the font, size and style of the tic labels
and a \f5sprintf()\f1-like format string can be specified.
.pp
The small marks between the tic values are called subtics,
and have a wider dotted optional subgrid line associated with it.
They are automatically generated,
whether the main ticks are manually or automatically set.
For the AtAxis class the subtic density resource can increase
or decrease the number of subtics per tic,
and care is taken that the number is sensible (e.g. power of 2 or 5 etc).
.pp
There is a label associated with each axis,
again an arbitrary text string in any font, color or style.
For vertical axes it is rotated 90 degrees.
These are the labels "Time" and "Amplitude" in the sample graph.
.pp
In general, there are four axes on the graph.
The horizontal axes are
the X axes, the lower is known as the X axis
and the upper as the X2 axis.
The vertical axes are Y axes,
the left being Y axis and the right being Y2 axis.
Each plot on the graph is associated with one X axis and one Y axis.
The AtPlotter maintains constraint resources on behalf of each plot child
to decide which X and Y axis it is associated with.
If there are no plot children associated with an axis
(as is the case for the Y2 and X2 axes
in the graph shown in Figure 1
or for the X2 axis in the graph shown in Figure 2),
then there is no need for an axis widget to be created for that axis.
.pp
The X2 and Y2 axes are known as mirror axes,
and the AtAxisCore resource \f5XtNmirror\f1 \f3must\f1
be set on axes used for these axes
and \f3must not\f1 be set on axes used for the X axis and Y axis.
Similarly, the AtAxisCore resource \f5XtNvertical\f1 \f3must\f1
be set on axes used for the Y axis and Y2 axis,
and \f3must not\f1 be set on axes used for the X axis and X2 axis.
Both \f5XtNmirror\f1 and \f5XtNvertical\f1 resources
can be set at Object creation time only;
any attempt to change them will fail with a warning message.
.pp
The AtAxisCore widget is a placeholder
for most of the axis resources,
and also contains the logic
for calculating pixel values from user-space values.
It relies on subclass member functions to decide
what values to use for minimum and maximum,
at what values to place tic and subtic marks,
and the labels associated with those tic marks.
The AtAxisCore widget then handles all the pixel conversions
and screen and PostScript redrawing,
so the axis classes are very simple to implement.
.pp
.(q
When the AtPlotter widget is created,
it does \f3not\f1 create any child axes\**.
.(f
\**This is a change in behaviour since Version 4.
.)f
.)q
It is the programmers responsibility to create (at least)
two AtAxisCore Objects and attach them to the AtPlotter
(using \f5XtSetValues()\f1 and the \f5XtNxAxis\f1 and similar resources).
Nasty things happen if this isn't done
(i.e. the program exits via \f5XtAppError()\f1).
It \f3is\f1 possible to have axis children that are
not one of the currently used axes,
but they must not be displayed
(i.e. must have \f5XtNdisplayed\f1 = False).
This is useful for having several possible axes on a plot
(e.g. an AtAxis if it is used for scaling a plot,
or a AtFrameAxis to carry tic marks when the opposite axis is being used),
and to swap between them with calls to
\f5XtSetValues()\f1 using for example the \f5XtNx2Axis\f1 resource.
.pp
Also on the sample graph are three plots from class AtXYLinePlot.
For these plots, the color, line type, line style,
point marker types and line thickness can be set.
This effects both the main plot and the legend entry for that plot.
For the AtLinePlot class only the color, line style
and line thickness can be set.
For the AtBarPlot,
the interior of the bars can either be
the same color as the outline,
or a different color.
The interior area can also be stippled
with one of 11 stipples\**
.(f
\**Only 5 distinct on-screen stipple patterns
are implemented at the moment,
pending discovery of good "10\% gray" sort of stipples.
The 11 stipples \f5GRAY0\f1 through \f5GRAY10\f1
correspond to PostScript \f51.0 setgray\f1
down to \f50.0 setgray\f1 constructs.
.)f
that will be converted to a grayscale level on PostScript output.
Ether the outline or the interior fill can be disabled
(but, obviously, not both).
.pp
\f3NOTE\f1:
All Objects that are not subclasses of rectObj
(and that includes all the AtPlot Objects)
do \f3not\f1 have a managed flag.
Hence they should \f3never\f1 be managed children of the AtPlotter widget.
This means they should be created with \f5XtCreateWidget()\f1
and not \f5XtCreateManagedWidget()\f1,
and should never be the argument to the \f5XtManageChild()\f1 routine.
Attempts to manage non-rectObjs will corrupt
the instance record with undefined results.
.pp
Rather than use \f5XtManageChild()\f1
and the \f5XtNmappedWhenManaged\f1
flag to display plots and axes,
the parent AtPlotter maintains
a constraint variable for each child called \f5displayed\f1
which may be set with the \f5XtNdisplayed\f1 resource.
Setting this to false has the same effect
that calling \f5XtUnmanageChild()\f1
with the \f5XtNmappedWhenManaged\f1 flag set
would have on a normal widget,
i.e. the child would disappear
and take no part in the calculation of axes bounds etc.
It is an error to undisplay an axis
that still has child plots associated with it,
and undefined results occur if a normal
(as opposed to frame)
axis is displayed without children associated with it.
.bp
.\"
.\"     Chapter 4: Advanced Topics
.\"
.CH "Advanced Topics"
.sh 2 "Text Facilities"
.pp
All text strings in the plotter widget set
are implemented using the AtText facility.
This is in the style of Motif compound XmString type.
It is a unified set of routines that allows
easy specification of text styles,
multiple fonts and sizes as well as symbols,
and PostScript output that closely matches the on-screen version.
See the \f5AtText(3X)\f1 manual page for the full details.
.pp
Each string segment is made up from five elements:
the font family, the style, the size, and the text.
The font family is something like "times"
and specifies the basic look of the font.
The style specifies AtFontPlain, \f2AtFontITALIC\f1,
\f3AtFontBOLD\f1 or \f4bAtFontBOLDITALIC\f1 typeface
(defined in \f5At/FontFamily.h\f1).
The size ranges from tiny \f5AtFontSMALLEST\f1 (about 8 point)
to large \f5AtFontBIGGEST\f1 (about 24 point).
Each segment is a simple list of
characters in that font/face/size combination.
The routine that compiles Strings to the AtText structs
has facilities for interpreting escapes to change fonts,
to display mathematical symbols etc.
.sp
In this widget set, the font family is set once per Object,
but the size and style can be changed on a per-string basis.
(This avoids the possibility of the so-called "ransom note" look).
.sh 2 "The Layout Procedure"
.pp
This is the sequence of steps the plotter goes through to lay out a graph.
.sp 0.5
.bu
The X and Y range for each plot child is accumulated
and remembered as data is attached to or changed for each child.
.sp 0.5
.bu
The X and Y ranges of all the child plots are merged,
on the basis of the \f5XtNuseX2Axis\f1 and \f5XtNuseY2Axis\f1 resources,
into a simple bounding box for all four axes.
(One X axis and one Y axis may be unused at this stage).
.sp 0.5
.bu
\f3minmax\f1:
Each axis currently in use is in turn offered
its minimum and maximum (calculated above)
via a call to the AtAxis member function \f5AtAxisAskRange()\f1.
It is the responsibility of this routine to do any rounding,
communication etc. as required,
and the returned minimum and maximum are used by the plotter.
There is a callback list on the AtAxisCore Object (\f5XtNrangeCallback\f1)
that is called by the AtAxisCore code
after it has decided on the axis bounds.
This programmer-written routine can modify
the minimum, maximum, number width
and tic interval values as required.
This is used for linking graphs (see Section 4.7).
The calculated number width
(which may be approximate only at this stage)
is used to calculate the "width" of the axis
(which is the amount of the axis that is outside the main graph area).
.sp 0.5
.bu
A layout is done,
assuming the axis widths calculated in step \f3minmax\f1 are accurate.
This sets the position of all the graph
components within the main AtPlotter window.
.sp 0.5
.bu
Each of the active axes is positioned by a call
to the \f5AtAxisSetLocation()\f1 member function.
If the length of the axis changes significantly
(currently by 10\%),
then it is assumed the number of relevant tics might have changed,
thus changing the rounding and endpoints of the axis.
If this is the case, the process is repeated at step \f3minmax\f1.
Should not loop more than twice at this point,
assuming step \f3minmax\f1 can do a reasonable guess for the axis width.
.sp 0.5
.bu
Each of the axes is recalculated by a call to the AtPlot
\f5AtPlotRecalc()\f1 member function.
Most of the arguments to the recalc function
for axis objects are ignored.
This step may give a better guess as to things like
the number width, which changes the layout.
If so, the sequence restarts at step \f3minmax\f1.
Some care is taken to avoid infinite loops.
.sp 0.5
.bu
Each of the non-axis child plots is recalculated
by a call to the \f5AtPlotRecalc()\f1 routine,
with the scales being extracted from the
already-recalculated axes as appropriate.
.sp 0.5
.bu
All children in the graph are redisplayed.
.sp 0.5
.pp
All of this is controlled by one routine which is
the redraw routine for the AtPlotter class.
All requests are remembered and stored up,
so the above procedure is only done when necessary.
This means a program can change several things one after the other,
and the graph will only do the expensive layout
and redraw calculation once,
not once per change.
This is faster and reduces flickering.
.pp
Furthermore, much care is taken internally to avoid
as much of the above sequence as is possible,
so that if small things change,
minimal calculation and redrawing is done.
.sh 2 "Drawing Order"
.pp
The order in which the children
of the AtPlotter widget are drawn
affects which is "above"
(and hence obscures) which in the display.
The first one drawn is conceptually on the bottom,
as you would expect.
(In this context, "children" refers to all children,
both axes and plots).
There are three typical situations where this is relevant:
.sp 0.5
.bu
Generally the grid provided by the axes should
be below the plotted data.
.sp 0.5
.bu
When drawing line plots and bar plots on the same graph,
you want the line plots to be drawn second
so that they are visible and not obscured by the bars.
Otherwise, the information from the line graph will likely be hidden.
.sp 0.5
.bu
Several bar plots can create the "stacked bar" effect
by drawing them in sequence,
and arranging them to overlap slightly.
.sp 0.5
.pp
There are two ways the AtPlotter can use
to decide which order to draw plots.
The first and default method,
which is used when the AtPlotter
resource \f5XtNrankChildren\f1 is False,
is to draw them in creation order.
The first created child is drawn first, and so on.
The second method,
used when \f5XtNrankChildren\f1 is True,
is to draw them according to a programmer-specified rank order.
The parent widget stores a constraint variable
called \f5XtNrank\f1 of behalf of all its children,
and will use this to decide which order to draw in.
This is more flexible but takes more programmer effort.
(When several children have the same rank,
they are drawn in unspecified order).
.sh 2 "Customizing Axis Layouts"
.pp
There are several alternatives to using the default
calculated axis bounds and tic positions.
The default behaviour
(for the AtXYAxis and AtAxis classes)
is to pick some number of tics
(depending on axis length
and the font used to display labels),
find a nice, round number for the tic interval
that gives approximately that number of tics\**,
.(f
\**For AtAxis objects the resource \f5XtNticDensity\f1
is used in addition to calculate the
number of tics per axis.
.)f
then round the endpoints up or down
to be a multiple of the tic interval.
Each tic is given a label by doing a \f5sprintf()\f1
using the \f5XtNticFormat\f1 resource\**.
.(f
\** For AtAxis objects the \f5XtNticMultiplier\f1 resource
is used in addition for labeling the tics.
.)f
This is fine is the axis values are numeric,
but not very useful
if the axis represents dates or categories,
or if you need to coordinate axes between separate graphs
(for example, having six variables to graph
against a common X value,
each pair plotted on a separate graph,
one graph on top of the other,
and all sharing the same X axis values -
which would look silly if
each X axis was in a different pixel position
or had a different scale).
.sp
There are three separate mechanisms to address these problems.
.sh 2 "Label Axes"
.pp
The AtLabelAxis class is very useful
if your axis doesn't represent numbers.
There are two main areas this could be useful:
.sp 0.5
.bu
If you are doing something like a stacked bar graph,
plotting a couple of figures (say, quarterly sales)
for each of several items (say, state by state).
Labeling the X axis with numbers is silly.
Instead, each X tic can be labeled with a string,
i.e. "Vic", "N.S.W." etc.
In this situation,
you would want to a label and tic for every X axis value.
.sp 0.5
.bu
If you are plotting values against dates,
you would like to be able to specify
the axis tics as dates,
not numbers.
Also, because dates are not regular
and months are not all the same length,
automatically deciding tic values
cannot do the logical thing,
such as putting a tic at the start of every month.
You would also like to be able to choose
which X values have tics and hence labels.
.sp 0.5
.pp
The AtLabelAxis axis allows the application writer
to specify arbitrary labels to put on tics,
and arbitrary positions to place tics,
at the expense of a bit more programming effort.
The programmer can specify things
like "a tic on the first day of every second month",
and label the axes with dates,
which cannot be done algorithmically.
.pp
The plotter and axis code supports
arbitrary X-Y plotting styles,
but with exception of the AtXYAxis class
and the AtXYPlot class (with the AtXYLinePlot subclass),
all other implemented plot widgets assume
the X axis is integer valued,
and that successive Y values are
at successive integral X values
(i.e. there are no "holes" in the sequence of Y values).
The AtLabelAxis also makes a similar assumption.
(This is because the initial use of this widget set
is to plot historical data against date,
and the AtLabelAxis is used for the X axis.
.pp
The application attaches data to the AtLabelAxis
with a member function called \f5AtLabelAxisAttachData()\f1\**
.(f
\**Which is \f3not\f1 an alias for the AtSPlot function!
This would be one place where multiple inheritance would be nice,
as the AtLabelAxis has elements of both AxisCore and AtSPlot classes.
.)f
that acts similarly to the attach procedures
for the AtXYLinePlot, AtLinePlot and AtBarPlot classes.
It would be used in a manner similar to this:
.SS
	AtLabelAxisAttachData(label_axis, (XtPointer) &answers[0].date_ptr,
			      sizeof(answers[0]), 0, NUM_ANSWERS);
.SE
.pp
The arguments to this function are:
.sp 0.5
.bu
The AtLabelAxis \f5label_axis\f1 that you are attaching the data to.
.sp 0.5
.bu
A pointer \f5&answers[0].data_ptr\f1 to a String
that is the first X axis label.
.sp 0.5
.bu
The stride \f5sizeof(answers[0]),
or number of bytes between successive Strings.
.sp
.bu
The X axis value of the first String.
This may or may not be the minimum value for the axis,
depending on the \f5XtNautoScale\f1 resource.
.bu
The number \f5NUM_ANSWERS\f1 of strings in the array.
.sp 0.5
.pp
If the \f5n\f1th String is non-\f5NULL\f1
and points to a non-empty string,
then a tic mark is placed at that X value
with the label specified by that string.
Otherwise no tic mark or label is placed there.
This gives the application writer complete control
over labeling the axis.
For example, in the above code fragment,
the application writer would make sure
the \f5date_ptr\f1 field of the \f5answers[]\f1 array
(which should be a \f5char *\f1)
would only be set on elements representing the first of the month,
and would point to a string like "July, 1990".
.sh 2 "Frame Axes"
.pp
The AtFrameAxis class is so named because the original use
was to put two more axes around simple graphs
so that they were completely enclosed.
(This gives a more balanced look.)
This can also be done setting the \f5XtNdrawFrame\f1
resource of an object of the AtAxisCore subclasses (like AtXYAxis),
which draws a single solid line as axis frame
without tics, subtics and labels.
An AtFrameAxis object is conceptually attached
to another AtAxisCore object
(in this or another graph), and,
when asked about axis bounds or tic positions,
gets the answer by looking at the axis to which it is attached.
The frame axis is attached to its target axis
by setting the \f5XtNwidget\f1 resource.
.pp
The only things imported from the target axis
are the tic and subtic values,
the tic labels and the endpoints.
The resources concerned with displaying the axis
(e.g. things such as color, font, label, tic length,
whether or not to draw the tic labels, etc)
are individually settable.
This is very flexible
but may require two axes to be changed
instead of one in some circumstances.
.pp
One use might be to have a frame axis as the X2 axis
attached to the normal X axis.
It would get the same tic, subtic
and bounds information as the X axis,
giving a nice symmetric look.
The labels would also be the same,
even though they might be rendered in a different font.
.sh 2 "Inter-graph linking"
.pp
The third method for handling axes is the most flexible
but also the most complex for the programmer.
As part of the layout processing,
each axis gets presented with the minimum and maximum values
of all of the plot widgets that are associated with that axis.
The axis then does whatever processing is required
to determine the endpoints of the axis
(in user space, not pixels),
such as rounding or examining other axes.
Finally, before the values are returned to the main plotter code,
the AxisCore code calls the \f5XtNrangeCallback\f1
callback of the axis.
This routine is passed three arguments:
the widget ID of the axis,
the closure field specified when the callback was added
(using \f5XtAddCallback()\f1 or equivalent),
and a pointer to an \f5AtAxisRangeArgs\f1 structure.
.pp
The \f5AtAxisRangeArgs\f1 structure is defined
in \f5<At/AxisCore.h>\f1 and looks like this:
.SS
	typedef struct {
	    double *minp, *maxp, *tic_intervalp;
	    int     *max_widthp;
	} AtAxisRangeArgs;
.SE
.pp
The four pointers point to the currently chosen values
for the maximum and minimum values of the axis,
the interval (in user space) between successive tics,
and the maximum width (in pixels) of the tic labels.
The called routine can chose whatever it likes for these values and,
by setting the pointed-to variables,
will affect the values used by the axis.
.pp
The number width field is supposed to be the width
of the widest tic label,
and is used to calculate the axis "width"
(and hence the pixel position of the axis).
Like the axis "width" it represents
height of the labels for horizontal axes
(as that is what determines the pixel Y position for that axis),
and the real width for vertical axes
(as that determines the X pixel position).
Why is this important?
Consider the three stacked graphs discussed above.
The pixel position of the Y axis of a graph depends
on the width of the Y axis.
So to maintain all Y axes at the same pixel locations it is
important to make all three Y axes have the same number width
(assuming all Y axes have the \f5XtNdrawNumbers\f1
and \f5XtNnumbersOutside\f1 resources set to True),
as well as making sure the tic length and label resources etc. the same.
.sh 2 "Extending Graphs"
.pp
A facility that is important in the plot widgets
implemented so far is the ability to efficiently handle graphs
that are being extended.
The intention is to allow efficient and reduced-flicker update
of graphs that are being added to in sort-of real time
(say once every few seconds).
As an example, consider something like
xmeter or perfmeter on the Sun - a strip chart
that is added to every 20 seconds, and,
once every couple of minutes does a shift to the left
to leave more room to stuff to be added.
The AtSPlot and AtXYPlot classes support this
via  member functions\**:
.(f
\**There are \f5\#define\f1'd versions of this
for all subclasses of AtSPlot and AtXYPlot,
including the AtLinePlot, AtBarPlot and AtXYLinePlot classes.
.)f
.SS
	AtSPlotDataExtended(widget, num)
.SE
and
.SS
	AtXYPlotDataExtended(widget ,num)
.SE
.pp
This tells the graph that extra data has arrived,
and the new maximum (\f3not\f1 the number added!)
is now \f5num\f1.
If there is enough room on the X axis,
and the new data doesn't go over the Y axis bounds,
the new data points are calculated and redrawn with minimum effort,
and little or no redrawing of the rest of the display.
If either X or Y axis bounds are exceeded,
or \f5num\f1 is less than the current value,
the equivalent of an attach is done and the graph is redrawn.
.sh 2 "Callbacks"
.pp
For the application programmer,
the AthenaTools Plotter Widget Set
provides additional callbacks\**
.(f
\**The Version 4 provided similar callbacks,
but these were dropped out in Version 5.
.)f
to permit user interaction and more flexibility.
.pp
Procedures in the \f5XtNmotionCallback\f1 list are called
when mouse motion events occur over the plotting area.
That may be used
to follow the pointer and to get the
current pointer position on the plotting area.
The \f5call_data\f1 argument to the \f5XtNmotionCallback\f1
is of type \f5AtPointCallbackData\f1
as defined in \f5At/Plotter.h\f1:
.SS
	typedef struct {
	    short pixelx, pixely;       /* Pixel point coordinates */
	    double x1, y1;              /* 1st axes point coordinates */
	    double x2, y2;              /* 2nd axes point coordinates */
	} AtPointCallbackData;
.SE
The items \f5pixelx\f1 and \f5pixely\f1
contain the pixel coordinates of the
current pointer position,
\f5x1\f1 and \f5y1\f1 the user coordinates
scaled against the first X and Y axes,
\f5x2\f1 and \f5y2\f1 the user coordinates
scaled against the second axis X2 and Y2.
Some of the example programs make use
of this callback.
.pp
Procedures of the \f5XtNclickCallback\f1 list are called
when mouse button one is clicked in the plotting aread.
That may be used to request the current
pointer position in pixel and user coordinates.
The \f5call_data\f1 argument of the \f5XtNclickCallback\f1
is also of type \f5AtPointCallbackData\f1 (see above).
.pp
Procedures of the \f5XtNdragCallback\f1 list are called
when mouse button one is dragged over the plotting area.
This callback may be used
to define a rectangle on the plotting area,
for example, for further zooming,
as it is done by some of the sample programs.
The \f5call_data\f1 argument to the
\f5XtNdragCallback\f1,
also defined in \f5At/Plotter.h\f1 is
of type \f5AtRectangleCallbackData\f1:
.SS
	typedef struct {
	    short pixelx1, pixely1;     /* Pixel lower left */
	    short pixelx2, pixely2;     /* Pixel upper rigth */
	    double x11, y11, x12, y12;  /* 1st axes range coordinates */
	    double x21, y21, x22, y22;  /* 2nd axes range coordinates */
	} AtRectangleCallbackData;
.SE
\f5Pixelx1\f1 and \f5pixely1\f1 contain the
pixel coordinates of the lower left corner
of the defined rectangle,
\f5Pixelx2\f1 and \f5pixely2\f1 the
pixel coordinates of the upper right corner.
In a similar fashion contain
\f5x11\f1, \f5y11\f1, \f5x12\f1 and \f5y12\f1
the user coordinates of the lower left corner
scaled against the axes X, Y and X2, Y2,
\f5x21\f1, \f5y21\f1, \f5x22\f1 and \f5y22\f1
the user coordinates of the upper right corner
also scaled against the axes X, Y and X2, Y2.
.pp
Care should be taken
not to make superfluous use of the
\f5XtNmotionCallback\f1, \f5XtNclickCallback\f1
and \f5XtNdragCallback\f1
callbacks,
to avoid unnecessary activity of the plotter widget.
.bp
.\"
.\"     Chapter 5: Listings
.\"
.so Listings.me
.\"
.\"     End
.\"
