Mastering Perl for Bioinformatics [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Mastering Perl for Bioinformatics [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید












8.3 Adding GD Graphics to Restrictionmap.pm



Now that you''ve seen an overview of the
GD.pm Perl module, let''s enhance
the Restrictionmap.pm module that
you''ve seen previously in Chapter 5, Chapter 6, and Chapter 7 so it can output PNG graphics files.


Reviewing how the Restrictionmap.pm module works,
you can see that its
get_graphic method examines the
_graphictype attribute to determine what graphics
drawing method to call. Following is the
get_graphic method again, along with the
attributes the class defines. (Recall that this class inherits from
the class Restriction.pm, so many things are
defined there):


# Class data and methods
{
# A list of all attributes with default values.
my %_attributes = (
# key = restriction enzyme name
# value = space-separated string of recognition sites => regular expressions
_rebase => { }, # A Rebase.pm object
_sequence => '''', # DNA sequence data in raw format (only bases)
_enzyme => '''', # space separated string of one or more enzyme names
_map => { }, # a hash: enzyme names => arrays of locations
_graphictype => ''text'', # one of ''text'' or ''png'' or some other
_graphic => '''', # a graphic display of the restriction map
);
# Return a list of all attributes
sub _all_attributes {
keys %_attributes;
}
}
sub get_graphic {
my($self) = @_;
# If the graphic is not stored, calculate and store it
unless($self->{_graphic}) {
unless($self->{_graphictype}) {
croak ''Attribute graphictype not set (default is "text")'';
}
# if graphictype is "xyz", method that makes the graphic is "_drawmap_xyz"
my $drawmapfunctionname = "_drawmap_" . $self->{_graphictype};
# Calculate and store the graphic
$self->{_graphic} = $self->$drawmapfunctionname;
}
# Return the stored graphic
return $self->{_graphic};
}


As you recall, the get_graphic method requires
that some graphic type be defined in the
_graphictype attribute. It then tries to call a
method whose name incorporates the name of the graphic type; for
instance, if the graphic type is
"png", the
get_graphic method tries to call a graphic drawing
method called _drawmap_png.


How might you design such a get_graphic method?



8.3.1 Designing Graphics



There are several ways to construct a PNG
graphic
to draw a restriction map. You can extract the data necessary using
_drawmap_text and its helper methods,
_initialize_annotation_text,
_add_annotation_text, and
_formatmaptext. These methods use the methods of
the Restriction class to get the locations of
restriction sites for each enzyme and then make a text version of an
annotated sequence string that shows the names of the restriction
enzymes above their respective restriction sites in the sequence.


Having found the locations of the restriction sites in the sequence,
there are many ways you can visually represent the map. You can
incorporate a design of double-stranded DNA, for instance, to serve
as a background to the actual sequence you can draw on top of the
double helical design. You can use colors and different sizes and
choices of fonts to make the restriction sites stand out. You can
draw the annotation in various ways, perhaps giving the restriction
enzyme and the location in some visually appealing way near the
restriction site. You may or may not want to draw the entire
sequence; perhaps you could truncate long stretches of sequence that
have no restriction sites, for instance, to make the relevant
information (the restriction site locations) fit better into a
smaller, more easily grasped space, ideally on one screen.


The following _drawmap_png
method uses the output of the _drawmap_text method
and makes a PNG graphic out of it.


#
# Method to output graphics in PNG format
#
sub _drawmap_png {
my($self) = @_;
# Get text version of graphic
my @maptext = split( /\n+/, $self->_drawmap_text);
# Now make a PNG graphic from the text version
use GD;
#
# Layout information: fonts, margins, image size
#
# Use built-in GD fixed-width font ''gdMediumBoldFont'' (could use TrueType fonts)
#
# Font character size in pixels
my ($fontwidth, $fontheight) = (gdMediumBoldFont->width,
gdMediumBoldFont->height);
# Margins top, bottom, right, left, and between lines
my ($tmarg, $bmarg, $rmarg, $lmarg, $linemarg) = (10, 10, 10, 10, 5);
# Image width is length of line times width of a character, plus margins
my ($imagewidth) = (length($maptext[0]) * $fontwidth) + $lmarg + $rmarg;
# Image height is height of font plus margin times number of lines, plus margins
my ($imageheight) = (($fontheight + $linemarg) * (scalar @maptext)) + $tmarg
+ $bmarg;
my $image = new GD::Image($imagewidth, $imageheight);
# First one becomes background color
my $white = $image->colorAllocate(255, 255, 255);
my $black = $image->colorAllocate(0, 0, 0);
my $red = $image->colorAllocate(255, 0, 0);
# Origin at upper left hand corner
my ($x, $y) = ($lmarg, $tmarg);
#
# Draw the lines on the image
#
foreach my $line (@maptext) {
chomp $line;
# Draw annotation in red
if($line =~ / /) { #annotation has spaces
$image->string(gdMediumBoldFont, $x, $y, $line, $red);
# Draw sequence in black
}else{ #sequence
$image->string(gdMediumBoldFont, $x, $y, $line, $black);
}
$y += ($fontheight + $linemarg);
}
return $image->png;
}


_drawmap_png has a fairly straightforward logic,
given that I just drew the same text as is formatted in the
_drawmap_text method. So, it''s no
surprise that the first step of the _drawmap_png
method is to get the formatted text. Recall that the lines of the
text are joined into a string so the graphic can be stored in a
scalar variable. So, the scalar string is split on
newlines back into an array @maptext:


# Get text version of graphic
my @maptext = split( /\n+/, $self->_drawmap_text);


Now, the GD module is loaded:


# Now make a PNG graphic from the text version
use GD;


Next, various layout dimensions are calculated:


#
# Layout information: fonts, margins, image size
#
# Use built-in GD fixed-width font ''gdMediumBoldFont'' (could use TrueType fonts)
#
# Font character size in pixels
my ($fontwidth, $fontheight) = (gdMediumBoldFont->width, gdMediumBoldFont->height);
# Margins top, bottom, right, left, and between lines
my ($tmarg, $bmarg, $rmarg, $lmarg, $linemarg) = (10, 10, 10, 10, 5);
# Image width is length of line times width of a character, plus margins
my ($imagewidth) = (length($maptext[0]) * $fontwidth) + $lmarg + $rmarg;
# Image height is height of font plus margin times number of lines, plus margins
my ($imageheight) = (($fontheight + $linemarg) *
(scalar @maptext)) + $tmarg + $bmarg;


GD includes a handful of built-in, fixed-width fonts. It also permits
the use of TrueType fonts; however, although they are freely
available, high quality, very extensive, and probably available on
your system, they are nevertheless not available everywhere. As a
result, I''ve decided to use a built-in font
that''s always available with GD.


However, as a result, the method has the font name hardcoded in a few
places. (See the exercises at the end of the chapter.) For instance,
GD built-in font names are objects with methods associated with them,
in particular, methods that return the width and height of the font
in pixels, which my _drawmap_png method saves in
the variables $fontwidth and
$fontheight.


Various margins are then set for the page as a whole and for the
spacing between lines.


Finally, the overall dimensions of the image are calculated:


# Image width is length of line times width of a character, plus margins
my ($imagewidth) = (length($maptext[0]) * $fontwidth) + $lmarg + $rmarg;
# Image height is height of font plus margin times number of lines, plus margins
my ($imageheight) = (($fontheight + $linemarg) *
(scalar @maptext)) + $tmarg + $bmarg;


The comments explain the logic. Recall that
@maptext is the array that contains the text to be
formatted. $maptext[0] is the first line, which is
either a full line and thus the maximum width, or
it''s less than a full line but is the only line, and
thus the maximum width. (scalar @maptext) returns
the number of lines in the @maptext array (because
an array in scalar context returns the size of the array).


After those preliminary calculations, the constructor for the GD
class can be called to create a new image object
$image of the correct dimensions:


my $image = new GD::Image($imagewidth, $imageheight);


8.3.1.1 Applying color



The colors I use can now be allocated
for the image object. In GD, the first call to the
colorAllocate method determines the background
color for the entire image. The triples of numbers are the red, blue,
and green values that are combined to form the various possible
colors:


# First one becomes background color
my $white = $image->colorAllocate(255, 255, 255);
my $black = $image->colorAllocate(0, 0, 0);
my $red = $image->colorAllocate(255, 0, 0);


Next, the x and y (horizontal and vertical) positions are initialized
at the origin of the image to be drawn. In GD, the origin of the
picture is 0,0 at the upper left corner. Increasing values of x move
from left to right across the image; increasing values of y move from
top to bottom down the image. Given that I want to have top and left
margins, I set the image origin at the upper left corner, offset by
the values of the margins:


# Origin at upper left corner
my ($x, $y) = ($lmarg, $tmarg);


Now, everything is set up, and it''s time to draw the
image. The text to be drawn is processed line-by-line; after each
line is drawn, the vertical position $y is
increased by the height of the font plus the interline margin.


There are two kinds of lines: sequence and annotation. I assume that
each annotation line contains some spaces (this
won''t always be true; see the exercises). Annotation
lines are printed as strings in the color red, and sequence lines are
printed in the color black.


#
# Draw the lines on the image
#
foreach my $line (@maptext) {
chomp $line;
# Draw annotation in red
if($line =~ / /) { #annotation has spaces
$image->string(gdMediumBoldFont, $x, $y, $line, $red);
# Draw sequence in black
}else{ #sequence
$image->string(gdMediumBoldFont, $x, $y, $line, $black);
}
$y += ($fontheight + $linemarg);
}


8.3.1.2 Calling the method



Finally, after all the text lines have been formatted and added to
the image, the png GD method is called on the
image. This produces a PNG image, which is returned from my
_drawmap_png method:


return $image->png;


Because that method was called by the method
_getgraphic, the PNG graphic is both saved in the
_graphic attribute and sent off to the
user''s browser, which knows how to display a PNG
image.


In other circumstances you might want to save the image to a file,
which you can do by opening a file, assigning it a filehandle (say
IMG), and printing the $image->png output to
the file:


print IMG $image->png;


8.3.2 Adding JPEG Output to Restrictionmap.pm



Let''s consider how to add
JPEG output to Restrictionmap.pm. I need a
_drawmap_jpg method to handle
the case when a JPEG image is requested by the programmer setting the
_graphictype attribute to
"jpg".


Looking over the GD documentation and the
_drawmap_png method I''ve just
written, I see that the last line of my
_drawmap_png method:


return $image->png;


can be replaced by:


return $image->jpeg;


in order to output a JPEG format. So, here''s my new
_drawmap_jpg method, almost an exact duplicate of
_drawmap_png (see the exercises at the end of the
chapter).


#
# Method to output graphics in JPEG format
#
sub _drawmap_jpg {
my($self) = @_;
# Get text version of graphic
my @maptext = split( /\n+/, $self->_drawmap_text);
# Now make a JPEG graphic from the text version
use GD;
#
# Layout information: fonts, margins, image size
#
# Use built-in GD fixed-width font ''gdMediumBoldFont'' (could use TrueType fonts)
#
# Font character size in pixels
my ($fontwidth, $fontheight) = (gdMediumBoldFont->width,
gdMediumBoldFont->height);
# Margins top, bottom, right, left, and between lines
my ($tmarg, $bmarg, $rmarg, $lmarg, $linemarg) = (10, 10, 10, 10, 5);
# Image width is length of line times width of a character, plus margins
my ($imagewidth) = (length($maptext[0]) * $fontwidth) + $lmarg + $rmarg;
# Image height is height of font plus margin times number of lines, plus margins
my ($imageheight) =
(($fontheight + $linemarg) *
(scalar @maptext)) + $tmarg + $bmarg;
my $image = new GD::Image($imagewidth, $imageheight);
# First one becomes background color
my $white = $image->colorAllocate(255, 255, 255);
my $black = $image->colorAllocate(0, 0, 0);
my $red = $image->colorAllocate(255, 0, 0);
# Origin at upper left hand corner
my ($x, $y) = ($lmarg, $tmarg);
#
# Draw the lines on the image
#
foreach my $line (@maptext) {
chomp $line;
# Draw annotation in red
if($line =~ / /) { #annotation has spaces
$image->string(gdMediumBoldFont, $x, $y, $line, $red);
# Draw sequence in black
}else{ #sequence
$image->string(gdMediumBoldFont, $x, $y, $line, $black);
}
$y += ($fontheight + $linemarg);
}
return $image->jpeg;
}


To use this new method from the webrebase1 CGI
Perl script, I''d have to change the requested
graphictype attribute to jpeg;
I''d also have to change the HTML header line that
gets printed out just before printing the image data. Now, that line
is set to:


print "Content-type: image/png\n\n";


but I''d have to change that to:


print "Content-type: image/jpeg\n\n";


You''ll notice if you try that out, the JPEG graphic
seems a bit blurry around the edges of the letters. This is a result
of the compression algorithm that JPEGs use. They tend to work very
well with photographic images, but the kind of text and line images
that webrebase1 creates do not fare as well under
JPEG compression.



/ 156