NAME

Chart::Plot.pm - Plot two dimensional data in a gif image. Version 0.07.

SYNOPSIS

use Chart::Plot; 

my $plot = Chart::Plot->new; 
my $anotherPlot = Chart::Plot->new ($gif_width, $gif_height); 

$plot->setData (\@dataset) or die( $plot->error() );
$plot->setData (\@xdataset, \@ydataset);
$plot->setData (\@anotherdataset, 'red_dashedline_points'); 
$plot->setData (\@xanotherdataset, \@yanotherdataset, 
                'Blue SolidLine NoPoints');

my ($xmin, $ymin, $xmax, $ymax) = $plot->getBounds();

$plot->setGraphOptions ('horGraphOffset' => 75,
			    'vertGraphOffset' => 100,
			    'title' => 'My Graph Title',
			    'horAxisLabel' => 'my X label',
			    'vertAxisLabel' => 'my Y label' );

print $plot->draw;

DESCRIPTION

I wrote Chart::Plot.pm to create gif images of some simple graphs of two dimensional data. The other graphing interface modules to GD.pm I saw on CPAN either could not handle negative data, or could only chart evenly spaced horizontal data. (If you have evenly spaced or nonmetric horizontal data and you want a bar or pie chart, I have successfully used the GIFgraph and Chart::* modules, available on CPAN.)

Chart::Plot.pm will plot multiple data sets in the same graph, each with some negative or positive values in the independent or dependent variables. Each dataset can be a scatter graph (data are represented by graph points only) or with lines connecting successive data points, or both. Colors and dashed lines are supported, as is scientific notation (1.7E10). Axes are scaled and positioned automatically and 5-10 ticks are drawn and labeled on each axis.

You must have already installed the GD.pm library by Lincoln Stein, available on CPAN or at http://www.genome.wi.mit.edu/ftp/pub/software/WWW/GD.html

This is an early draft and has not received exhaustive testing, but it seems to work ok. I will attempt to maintain compatibility of the public interface in future versions.

USAGE

Create an image object: new()

use Chart::Plot; 

my $plot = Plot->new; 
my $plot = Plot->new ( $gif_width, $gif_height ); 
my $anotherGraph = Plot->new; 

Create a new empty image with the new() method. It will be transparent and interlaced. If image size is not specified, the default is 400 x 300 pixels, or, you can specify a different gif size. You can also create more than one image in the same script.

Acquire a dataset: setData()

$plot->setData (\@data);
$plot->setData (\@xdata, \@ydata);
$plot->setData (\@data, 'red_dashedline_points'); 
$plot->setData (\@xdata, \@ydata, 'blue solidline');

The setData() method reads in a two-dimensional dataset to be plotted into the image. You can pass the dataset either as one flat array containing the paired x,y data or as two arrays, one each for the x and y data.

As a single array, in your script, construct a flat array of the form (x0, y0, ..., xn, yn) containing n+1 x,y data points . Then plot the dataset by passing a reference to the data array to the setData() method. (If you do not know what a reference is, just put a backslash (\) in front of the name of your data array when you pass it as an argument to setData().) Like this:

my @data = qw( -3 9   -2 4   -1 1   0 0   1 1  2 4  3 9);
$plot->setData (\@data);

Or, you may find it more convenient to construct two equal length arrays, one for the horizontal and one for the corresponding vertical data. Then pass references to both arrays (horizontal first) to setData():

my @xdata = qw( -3  -2  -1  0  1  2  3 );
my @ydata = qw(  9   4   1  0  1  4  9 );
$plot->setData (\@xdata, \@ydata);

[In the current version, if you pass a reference to a single, flat array to setData(), then only a reference to the data array is stored internally in the plot object, not a copy of the array. The object does not modify your data, but you can and the modified data will be drawn. On the other hand, if you pass references to two arrays, then copies of the data are stored internally, and you cannot modify them from within your script. This inconsistent behavior is probably a bug, though it might be useful from time to time.]

You can also plot multiple datasets in the same graph by calling $plot->setData() repeatedly on different datasets.

Error checking: The setData() method returns a postive integer on success and 0 on failure. If setData() fails, you can recover an error message about the most recent failure with the error() method. The error string returned will either be "The data set does not contain an equal number of x and y values." or "The data element ... is non-numeric."

$plot->setData (\@data) or die( $plot->error() );

In the current version, only numerals, decimal points (apologies to Europeans), minus signs, and more generally, scientific notation (+1.7E-10 or -.298e+17) are supported. Commas (,), currencies ($), time (11:23am) or dates (23/05/98) are not yet supported and will generate errors. I hope to figure these out sometime in the future.

Be cautious with scientific notation, since the axis tick labels will probably become unwieldy. Consider rescaling your data by orders of magnitude or using logarithmic transforms before plotting them. Or experiment with image size and graph offset.

Style options: You can also specify certain graphing style options for each dataset by passing an optional final string argument to setData() with a concatenated list of selections from each of the following groups:

black  *
red
green 
blue

solidline  *
dashedline
noline

points  *
nopoints

The starred options in each group are the default for that group. If you do not specify any options, you will get black solid lines connecting successive data points with dots at each data point ('black_solidline_points'). If you want a red scatter plot (red dots but no lines) you could specify either

$plot->setData (\@data, 'redNOLINE'); 
$plot->setData (\@xdata, \@ydata, 'Points Noline Red');

Options are detected by a simple regexp match, so order does not matter in the option string, options are not case sensitive and extraneous characters between options are ignored. There is no harm in specifying a default. There is also no error checking.

Obtain current graph boundaries: getBounds()

my ($xmin, $ymin, $xmax, $ymax) = $plot->getBounds;

This method returns tha data values of the lower left corner and upper right corner of the graph, based on the datasets so far set. If you have only positive data, then $xmin and $ymin will be 0. The upper values will typically not be the data maxima, since axis tick ranges are usually a little beyond the range of the data. If you add another dataset, these values may become inaccurate, so you will need to call the method again. As an example, I use this to draw a least squares line through a scatter plot of the data, running from the edges of the graph rather than from the bounds of the data.

Graph-wide options: setGraphOptions()

    $plot->setGraphOptions ('title' => 'My Graph Title',
		            'horAxisLabel' => 'my X label',
		            'vertAxisLabel' => 'my Y label' 
			    'horGraphOffset' => $numHorPixels,
	                    'vertGraphOffset' => $numvertPixels);

This method and each of its arguments are optional. You can call it with one, some or all options, or you can call it repeatedly to set or change options. This method will also accept a hash.

In the current version, Chart::Plot.pm is a little smarter about placement of text, but is still not likely to satisfy everyone, If you are not constructing images on the fly, you might consider leaving these blank and using a paint program to add text by hand.

Titles and Axis labels are blank, by default. The title will be centered in the margin space below the graph. A little extra vertical offset space (the margin between the edges of the graph proper and the image) is added to allow room. There is no support for multi-line strings. You can specify empty strings for one or the other of the axis labels. The vertical label will be centered or left justified above the vertical axis; the horizontal label will be placed below the end of the horizontal axis, centered or right justified.

By default, the graph will be centered within the gif image, with 50 pixels offset distance from its edges to the edges of the image (though a title will increase the vertical offset). Axis and tick labels and the title will appear in this margin (assuming all data are positive). You can obtain more space for a title or a horizontal label by increasing the image size (method new() ) and adjusting the offset.

Draw the image: draw()

$plot->draw;

This method draws the gif image and returns it as a string, which you can print to a file or to STDOUT. (This should be the last method called from the $plot object.) To save it in a file:

open (WR,'>plot.gif') or die ("Failed to write file: $!");
print WR $plot->draw();
close WR;

Or, to return the graph from a cgi script as a gif image:

print "Content-type: image/gif\n\n";
print  $plot->draw();

Or, to pipe it to a viewing program which accepts STDIN (such as xv on Unix)

open (VIEWER,'| /usr/X11R6/bin/xv -') or die ("Failed to open viewer: $!");
print VIEWER $plot->draw();
close VIEWER;

BUGS AND TO DO

You will probably be unhappy with axis tick labels running together if you use scientific notation. Controlling tick label formatting and length for scientific notation seems doable but challenging.

Future versions might incorporate data set labels inside the graph, a legend, control of font size, word wrap and dynamic adjustment of axis labels and title. Better code, a better pod page.

AUTHOR

Copyright (c) 1998 by Sanford Morton <sanford@halcyon.com>. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

GIFgraph(1) and Chart(1) are other front end modules to GD(1).