8.4 Making Graphs


Displaying data graphically (graphs, bar graphs, pie charts , etc.) is the most common goal of image programming You've just seen how the GD Perl module helps you create graphics. It's great for quickly providing images from CGI web programs.

GD::Graph , another Perl module that uses GD as its underlying mechanism, does an excellent job of rendering all sorts of graphs. Programming graphs with GD::Graph is relatively easy, especially if you start with the example programs and modify them for your own purposes. The module is object oriented, and it provides many options for displaying the various graphs. Plan to take some time exploring the documentation and trying different options as you begin programming with GD::Graph . Its flexible yet relatively simple programming interface has made it a popular and powerful module. GD::Graph can be found on CPAN. It's simple to install once you have GD itself installed.

For more in-depth information on graphics programming in Perl, see Perl Graphics Programming by Shawn Wallace (O'Reilly). The book includes a chapter on GD::Graph that can serve as a fine tutorial. The documentation for GD::Graph (on CPAN, or type perldoc GD::Graph in a terminal window) is well-written and clearly organized. The software comes with several example programs that will help get you started.

The following short program, gd1.pl , uses GD::Graph to create a simple bar graph.

 #!/usr/bin/perl # # gd1.pl -- create GD::Graph bar graph # use strict; use warnings; use Carp; use GD::Graph::bars; my %dataset = ( 1 => 3,                 2 => 17,         3 => 34,         4 => 23,         5 => 25,         6 => 20,         7 => 12,         8 => 3,         9 => 1 ); # create new image my $graph = new GD::Graph::bars(600, 300);      # discover maximum values of x and y for graph parameters my( $xmax) = sort {$b <=> $a} keys %dataset; my( $ymax) = sort {$b <=> $a} values %dataset; # how many ticks to put on y axis my $yticks = int($ymax / 5) + 1;      # define input arrays and enter 0 if undefined x value my(@xsizes) = (0 .. $xmax); my(@ycounts) = (); foreach my $x (@xsizes) {     if ( defined $dataset{$x}) {         push @ycounts, $dataset{$x};     }else{         push @ycounts, 0;     } } # set parameters for graph $graph->set(     transparent                => 0,     title                => "Summary of mutation data",     x_label                => 'Mutants per cluster',     y_label                => 'Number of mutants',     x_all_ticks                => 1,     y_all_ticks                => 0,     y_tick_number        => $yticks,     zero_axis                => 0,     zero_axis_only        => 0, );      # plot the data on the graph my $gd = $graph->plot(     [  xsizes,  ycounts     ] ); # output file my $pngfile = "gdgraph1.png"; unless(open(PNG, ">$pngfile")) {     croak "Cannot open $pngfile:$!\n"; } # set output file handle PNG to binary stream # (this is important sometimes, for example doing # GCI programming on some operating systems binmode PNG; # print the image to the output file print PNG $gd->png; 

Figure 8-1 shows the image that is written to the file gdgraph1.png . On my system it's very small for an image, only 2028 bytes.

Figure 8-1. A simple bar graph
figs/mpb_0801.gif

Here's how the code works. The new module is loaded like so:

 use GD::Graph::bars; 

The dataset is then defined as a hash. In reality, GD::Graph expects to see the data in arrays. However, since your program may first collect data in a hash, I've shown you how to incorporate hash data into a GD::Graph image and included the code that extracts the required x and y arrays from the hash.

Next , the module's new constructor method is called to initialize a graph of type bars and sized at 600 pixels horizontal and 300 pixels vertical.

 # create new image my $graph = new GD::Graph::bars(600, 300); 

The next bit of code prepares some of the values needed to set parameters for the graph. The maximum x and y values are extracted from the hash %dataset . There is a way to specify how many ticks are desired along the y axis, but if you want one every five values, say, you have to figure out how many such values will just fit the data: hence the $yticks calculation.

 # discover maximum values of x and y for graph parameters my( $xmax) = sort {$b <=> $a} keys %dataset; my( $ymax) = sort {$b <=> $a} values %dataset; # how many ticks to put on y axis my $yticks = int($ymax / 5) + 1; 

Next, the actual arrays of x and y values are constructed from the data in %dataset :

 # define input arrays and enter 0 if undefined x value my(@xsizes) = (0 .. $xmax); my(@ycounts) = (); foreach my $x (@xsizes) {     if ( defined $dataset{$x}) {         push @ycounts, $dataset{$x};     }else{         push @ycounts, 0;     } } 

Finally the various parameters are set (there are quite a few possible parameters, as you'll see in the documentation), the data is plotted in the graph, an output file handle is created and set to binary mode (important for CGI web programming), and the image data is written out.

Here is another version, gd2.pl , of the same program. This version creates "lines and points" graphs that have the values written over each datapoint. Instead of showing the data as a bar, this graph shows data points joined by lines. The data points have the value written next to them, except for the value at x=3 , which is suppressed. Other than that, it's the same image from the same data as used in gd1.pl .

 #!/usr/bin/perl # # gd2.pl -- create GD::Graph "linespoints" graph # use strict; use warnings; use Carp; use GD::Graph::linespoints; my %dataset = ( 1 => 3,                 2 => 17,         3 => 34,         4 => 23,         5 => 25,         6 => 20,         7 => 12,         8 => 3,         9 => 1 ); # create new image my $graph = new GD::Graph::linespoints(600, 300);      # discover maximum values of x and y for graph parameters my( $xmax) = sort {$b <=> $a} keys %dataset; my( $ymax) = sort {$b <=> $a} values %dataset; # how many ticks to put on y axis my $yticks = int($ymax / 5) + 1;      # define input arrays and enter 0 if undefined x value my(@xsizes) = (0 .. $xmax); my(@ycounts) = (); foreach my $x (@xsizes) {     if ( defined $dataset{$x}) {         push @ycounts, $dataset{$x};     }else{         push @ycounts, 0;     } } # define input data # need to do separately so show_values will work my $data = GD::Graph::Data->new(     [  xsizes,  ycounts    ] ); # use show_values to show values of data next to points # use $values to suppress printing of value for x=3 my $values = $data->copy; $values->set_y(1, 3, undef); # set parameters for graph $graph->set(     transparent                => 0,     title                => "Summary of mutation data",     x_label                => 'Mutants per cluster',     y_label                => 'Number of mutants',     x_all_ticks                => 1,     y_all_ticks                => 0,     y_tick_number        => $yticks,     zero_axis                => 0,     zero_axis_only        => 0,     show_values         => $values, );      # plot the data on the graph my $gd = $graph->plot(     [  xsizes,  ycounts     ] ); # output file my $pngfile = "gdgraph2.png"; unless(open(PNG, ">$pngfile")) {     croak "Cannot open $pngfile:$!\n"; } binmode PNG; print PNG $gd->png; 

Figure 8-2 shows the image that's written to the file gdgraph2.png .

Figure 8-2. A lines and points graph
figs/mpb_0802.gif

A variety of image viewing programs may be used to display your results while you're doing graphics programming. ImageMagick has a display program called display that runs on a Linux system and elsewhere. I often use xv , and while it usually works quite well, it seems to have trouble with PNG files. When programming, it's a good idea to pick an imaging program that can be set to automatically update the display when you overwrite the image file with new data. It's common for a system's user interface to allow you to click on the image file's name or thumbnail image in order to launch an image viewing program with the image loaded.

This section just gives you a taste of the capabilities of GD::Graph . The module provides many possibilities, all of which are easily incorporated into your Perl programs for output to files or sent to a web browser from your CGI program.



Mastering Perl for Bioinformatics
Mastering Perl for Bioinformatics
ISBN: 0596003072
EAN: 2147483647
Year: 2003
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net