5 CXGN::Cview::Chromosome - a class for drawing chromosomes.
9 Inherits from L<CXGN::Cview::ImageI>. The chromosome can be defined by adding markers as CXGN::Cview::Marker objects, using the add_marker() function. An object defining a ruler (CXGN::Cview::Ruler) can be obtained by calling the get_ruler() function. The length of the chromosome is either defined implicitly by the marker with the highest cM position, or explicitly using the set_length() function. The placement of the chromosome is defined by CXGN::Cview::ImageI defined functions such as set_horizontal_offset(), which defines the mid-line of the chromosome, and set_vertical_offset(), which defines the top edge.
11 Chromosomes can be rendered either in full or in section. The sections can start at cM positions other than 0 and are rendered slightly differently. Use set_section() to define the section.
13 The render() function will render the chromosome on the GD::Image supplied. It calls the subroutines to draw the chromosomes, lays out the marker labels and then calls the render function on each marker object.
15 Certain aspects of the appearance of the chromosome can be changed. For example, the color of the chromosome can be changed using set_color(). Labels can be rendered on the left or on the right of the chromosome, using set_labels_right() or set_labels_left().
17 Markers with the highest LOD score or rendered last, such that they will appear on the chromosome at the expense of lower scoring markers.
19 Chromosome areas can be rendered clickable using the function rasterize().
23 See also the documentation in L<CXGN::Cview> and L<CXGN::Cview::ImageI>.
27 Lukas Mueller (lam87@cornell.edu)
31 CXGN::Cview::Chromosome has the following methods:
36 use CXGN
::Cview
::ImageObject
;
37 use CXGN
::Cview
::Marker
;
38 use CXGN
::Cview
::Marker
::SequencedBAC
;
39 use CXGN
::Cview
::Ruler
;
40 use CXGN
::Cview
::Ruler
::PachyteneRuler
;
41 use CXGN
::Cview
::Chromosome
::BarGraph
;
44 package CXGN
::Cview
::Chromosome
;
46 use base
qw(CXGN::Cview::ImageObject);
52 my $c = CXGN::Cview::Chromosome -> new( chr number, height in pixels, horizontal offset, vertical offset, [start cM], [end cM])
54 Creates a new chromosome object. The horizontal offset denotes the offset of the chromosome mid-line. The vertical offset defines the upper end of the chromosome. Note that some renditions of the chromosome will add round edges on the top and on the bottom, so that the rounded top position will be smaller than the vertical offset.
56 Optionally, start_cM and end_cM can be supplied, which will set the start and end in cM for a chromosome section. The chromosome will be rendered as a section, i.e, the ends will be flat instead of rounded.
70 my $self = $class -> SUPER
::new
($x, $y, $height);
72 $self -> set_start_cM
($start); # if a chromosome section, where the section starts, in cM
73 $self -> set_end_cM
($end); # if a chromosome section, where the section ends, in cM
75 $self -> {markers
} = ();
77 $self->set_labels_right();
78 $self -> set_width
(20); # default width
79 $self -> {curved_height
} = $self->get_width();
81 $self->{chr_nr
}=$chr_nr;
82 $self->set_name($chr_nr);
84 $self -> {font
} = GD
::Font
->Small();
86 $self -> set_horizontal_offset
($x);
87 $self -> set_vertical_offset
($y);
88 $self -> set_color
(200, 150, 150);
89 $self -> set_hilite_color
(255, 255, 0);
90 $self -> set_outline_color
(0,0,0);
91 $self -> set_hide_marker_offset
();
92 $self -> set_ruler
( CXGN
::Cview
::Ruler
->new($self->get_horizontal_offset(), $self->get_vertical_offset(), $self->get_height(), 0, $self->get_length()) );
93 # don't do this - will cause deep recursion... $self -> set_bargraph( CXGN::Cview::Chromosome::BarGraph->new($self->get_horizontal_offset(), $self->get_vertical_offset(), $self->get_height(), 0, $self->get_length()));
94 $self -> hide_bargraph
(); # by default, do not show the bar graph.
98 =head2 function set_height()
100 $chr->set_height($height)
102 Sets the height of the chromosome in pixels. Recalculates all the scaling information.
103 Implemented in superclass.
108 =head2 function get_height()
110 $height = $chr ->get_height()
112 Gets the height of the chromosome in pixels. Implemented in the superclass.
117 =head2 function set_length()
119 sets the length in map units [cM].
121 This can also be automatically determined if not set manually, to the offset of the marker with the highest map unit value.
128 $self->{chromosome_length_cM
}=shift;
131 =head2 function get_length()
133 gets the length of the chromosome in map units.
140 return $self->{chromosome_length_cM
};
144 =head2 function get_units()
156 return $self->get_ruler()->get_units();
159 =head2 function set_units()
172 $self->get_ruler()->set_units($units);
175 =head2 function get_ruler()
187 return $self->{ruler
};
190 =head2 function set_ruler()
202 $self->{ruler
}=shift;
205 =head2 accessors set_bargraph(), get_bargraph()
207 Property: an associated bar graph with this chromosome
208 The bargraph is a CXGN::Cview::Chromosome::BarGraph
209 object. The default is no bar graph, ie, an empty
210 bar graph is initialized in the constructor.
219 return $self->{bargraph
};
224 $self->{bargraph
}=shift;
228 =head2 functions show_bargraph(), hide_bargraph()
240 $self->{show_bargraph
}=1;
245 $self->{show_bargraph
}=0;
248 =head2 function set_section()
250 $chr->set_section($start_in_map_units, $end_in_map_units);
252 Defines the chromosome as a section. The section starts at the start coordinate in map units, and ends at the end coordinate in map units. Chromosomes that are sections are rendered differently than full chromosomes. The section will be rendered so that it fills the entire height of the chromosome as defined with new or set_height, and the top edge will be drawn at the horizontal and vertical offset defined in the new call or with set_horizonatal_offset and set_vertical_offset.
260 $self -> set_start_cM
(shift);
261 $self -> set_end_cM
(shift);
262 $self -> {is_section
} =1;
265 =head2 function get_section()
267 $flag = $chr->is_section()
269 Returns true if the chromosome $chr is a section.
275 return $self -> {is_section
};
278 =head2 function set_hilite()
280 $chr->set_hilite(start_coord, end_coord)
282 Highlights the region of the chromosome between start_coord and end_coord with the hilite_color (which can be set with set_hilite_color, see below).
288 $self->{hilite_start
}=shift;
289 $self->{hilite_end
}=shift;
292 =head2 function set_hilite_color()
294 $chr->set_hilite($red_channel, $green_channel, $blue_channel)
296 Sets the hilite color for chromosome highlighting. Three values between 0 and 255 are required for defining red, green and blue channels. The default color is yellow (255, 255,0)
300 sub set_hilite_color
{
302 $self->{hilite_color
}[0]=shift;
303 $self->{hilite_color
}[1]=shift;
304 $self->{hilite_color
}[2]=shift;
307 sub get_hilite_color
{
309 return @
{$self->{hilite_color
}};
314 =head2 function set_color()
316 Sets the chromosome outline color. Three values between 0 and 255 are required for defining red, green and blue channels. The default color is 0,0,0, which is black. This function is defined in the parent class.
320 sub set_outline_color
{
322 $self->{outline_color
}[0]=shift;
323 $self->{outline_color
}[1]=shift;
324 $self->{outline_color
}[2]=shift;
328 =head2 function set_caption()
330 Sets the caption of the chromosome. The caption will be drawn centered on the top of the chromosome. Usually, the chromosome number should be displayed.
337 $self->{caption
}=shift;
342 return $self->{caption
};
345 =head2 function set_labels_left()
347 Causes the labels to be displayed on the left side of the chromosome.
351 sub set_labels_left
{
353 $self->{label_side
} = "left";
356 =head2 function set_labels_right()
358 Causes the labels to be displayed on the right side of the chromosome.
362 sub set_labels_right
{
364 $self->{label_side
} = "right";
367 =head2 function set_labels_none()
369 Causes the labels not to be displayed for the whole chromosome.
373 sub set_labels_none
{
375 $self -> {label_side
} = "";
378 =head2 function get_label_side()
390 return $self->{label_side
};
394 =head2 function set_display_marker_offset()
396 Causes the marker offsets to be displayed on the opposite side of the labels.
400 sub set_display_marker_offset
{
402 # is set, the marker offset in cM will be displayed on the opposite side of the label
405 $self -> {display_marker_offset
} = 1;
408 sub set_hide_marker_offset
{
410 $self -> {display_marker_offset
} = 0;
413 =head2 function render()
415 $chr-> render($image);
417 This function is called to render the chromosome and recursively calls all the rendering functions of the objects it contains. The image parameter is an GD image object. Usually, you should not have to call this function, but the MapImage object calls this function for you if you render a map.
426 $self -> draw_chromosome
($image);
427 $self -> render_markers
($image);
430 =head2 function render_markers()
436 Description: This function renders the markers of the chromosome object.
437 The important thing is to render the markers such that the highest
438 load score marker is rendererd last.
446 my @markers = $self->get_markers();
448 foreach my $lod (-1,0,1,2,3) {
450 foreach my $m (@markers) {
452 if (!$m->isa("CXGN::Cview::Marker::SequencedBAC")) {
453 if ($m->get_confidence()==$lod) {
454 $m -> render
($image);
463 # render highlighted markers again to prevent clobbering
464 foreach my $m (@markers) {
465 if ($m->is_visible() && $m->get_hilited()) {
471 foreach my $m (@markers) {
472 if ($m->isa("CXGN::Cview::Marker::SequencedBAC")) {
473 $m->get_label()->set_text_color(200,200,80);
474 $m->get_label()->set_line_color(200,200,80);
475 $m->set_color(255,255,0);
483 # =head2 function render_labels
493 # sub render_labels {
496 # foreach my $m ($self->get_markers()) {
497 # if ($m->is_visible() && $m->get_label()->get_hilited()) {
498 # $m->get_label()->render($image);
505 sub get_enclosing_rect
{
507 return (int($self->get_horizontal_offset()-$self->get_width()/2), $self->get_vertical_offset(), $self->get_horizontal_offset()+int($self->get_width()/2), $self->get_vertical_offset()+$self->{height
});
510 =head2 function rasterize()
512 Causes the chromosome to be rasterized in the MapImage tags. A scaffold of rectangular areas is overlaid on the chromosome that can be used to link to something to this part of the chromosome. The link is supplied through set_rasterize_link. The parameter gives the size of the raster in cM. With the parameter set to zero, no rastering occurs.
517 # this function sets the rasterize variable, get_image_map then rasterizes the chromosome if necessary.
520 $self->{rasterize
}=shift;
522 return $self->{rasterize
};
525 sub set_rasterize_link
{
527 $self->{rasterize_link
} = shift;
530 # the rasterize link has to be of the format http://url.domain.etc/etc/program?parameter=values¶meter=values&cM=
531 # rasterizatio will add the number of cM where clicked at the end of the link.
532 sub get_rasterize_link
{
534 if (!exists($self->{rasterize_link
}) || !defined($self->{rasterize_link
})) {
535 $self->{rasterize_link
}="";
537 return $self->{rasterize_link
};
540 =head2 function get_image_map()
542 Gets the image map for the chromosome and all contained objects within chromosome. This is normally called by the MapImage object.
548 my $coords = join ",", ($self -> get_enclosing_rect
());
551 if ($self->get_url()) { $string = "<area shape=\"rect\" coords=\"".$coords."\" href=\"".$self->get_url()."\" alt=\"\" />";}
552 foreach my $m (($self->get_markers())) {
553 if ($m->is_visible()) {
554 $string .= $m -> get_image_map
();
557 if ($self->rasterize() && $self->get_length()>0) {
558 my $raster = $self->get_length()/20;#$self->{rasterize}; # cM
559 my $steps = ($self->get_length()/$raster);
561 my $halfwidth = ($self->get_width()/2);
562 my $x = $self->get_horizontal_offset();
563 my $y = $self->get_vertical_offset();
564 my $box_pixel_height = $self->get_height()/$steps;
566 for (my $i=0; $i<=($steps+1); $i++) {
568 my $pixels = $self->mapunits2pixels($cM)+$y;
570 $string .="<area shape=\"rect\" coords=\"".int($x-$halfwidth).",".int($pixels).",".int($x+$halfwidth).",".int($pixels+$box_pixel_height)."\" href=\"".$self->get_rasterize_link().$cM."\" alt=\"\" />\n";
577 sub _sort_by_position
{
578 return ($a->get_offset() <=> $b->get_offset);
581 =head2 function sort_markers()
583 Synopsis: $c->sort_markers()
586 Side effects: sorts the markers according to their position
587 in the internal datastructure. This is required
588 for proper rendering of the marker labels; if
589 the markers are added in sequence, calling this
599 my @sorted_markers = sort _sort_by_position
($self->get_markers());
600 $self->set_markers(@sorted_markers);
603 sub _calculate_scaling_factor
{
606 $self -> _calculate_chromosome_length
();
607 if ($self->get_length()==0) { return 0; }
609 $self->{scaling_factor
}=($self->get_height()/$self->get_length());
611 #print STDERR "calculating scaling factor. height in pixels: $self->{height} chromosome_length=$self->{chromosome_length_cM} scaling factor: $self->{scaling_factor}\n";
613 return $self->{scaling_factor
};
616 sub get_scaling_factor
{
618 if (!exists($self->{scaling_factor
})) {
619 $self->{scaling_factor
}=0;
620 warn "[CXGN::Cview::Chromosome] WARNING! Scaling factor is 0.\n";
622 return $self->{scaling_factor
};
625 =head2 function add_marker()
627 $chr->add_marker($m);
629 Adds the marker object $m to the chromosome.
636 push @
{$self->{markers
}}, $m;
639 =head2 function get_markers()
641 my @m = $chr -> get_markers();
643 Gets all the markers in the chromosome as an array.
649 if (!defined($self->{markers
})) { return (); }
650 return @
{$self->{markers
}};
655 @
{$self->{markers
}} = @_;
658 =head2 accessors set_start_cM(), get_start_cM()
671 if (!exists($self->{start_cM
}) || !defined($self->{start_cM
})) { $self->{start_cM
}=0; }
672 return $self->{start_cM
};
677 $self->{start_cM
}=shift;
680 =head2 accessors set_end_cM(), get_end_cM()
693 if (!exists($self->{end_cM
})) { $self->{end_cM
}=0; }
694 return $self->{end_cM
};
699 $self->{end_cM
}=shift;
704 sub get_markers_in_interval
{
706 my $start = shift; # start in cM
707 my $end = shift; # end position in cM
708 if (!$start && !$end) { $start = 0; $end = $self -> get_length
()+1 ; }
710 foreach my $m (@
{$self->{markers
}}) {
711 if ($m -> get_offset
() >= $start && $m->get_offset() <= $end) {
715 return @markers; # returns all the markers in between start and end
718 sub get_frame_markers
{
720 my @framemarkers = ();
721 foreach my $m (@
{$self->{markers
}}) {
722 if ($m->is_frame_marker()) {
723 push @framemarkers, $m;
726 return @framemarkers;
729 sub get_markers_ref
{
731 return \@
{$self->{markers
}};
736 $self->_calculate_chromosome_length();
737 $self->_calculate_scaling_factor();
738 $self -> distribute_labels
();
739 $self -> distribute_label_stacking
();
743 sub _calculate_chromosome_length
{
747 # get chromosome length in cM.
749 # if it is a section, we return the length of the section, as defined by start_cM and end_cM
751 if ($self->is_section()) {
752 if ($self->get_end_cM()>$self->{chromosome_length_cM
}) {
753 $self->get_end_cM($self->{chromosome_length_cM
});
755 $self->{chromosome_length_cM
}=$self->get_end_cM()-$self->get_start_cM();
756 return $self->{chromosome_length_cM
};
759 # it may be that chromosome_length has been manually set with set_length.
761 if ($self->get_length()) {
762 return $self->get_length();
765 # otherwise, we get the marker with the highest cM position.
766 # the length may have been set already by set_length...
768 foreach my $m (@
{$self->{markers
}}) {
769 my $offset = $m -> get_offset
();
770 if ($offset > $length) { $length = $offset; }
772 $self->{chromosome_length_cM
} = $length;
774 return $self->{chromosome_length_cM
};
777 # otherwise return some default length
783 sub get_chromosome_length
{
784 # same as get_length. Deprecated.
786 return $self->{chromosome_length_cM
};
789 =head2 function mapunits2pixels()
791 my $pixels = $chr->mapunits2pixels($cM_pos);
793 Gets the number of pixels the cM value corresponds to. Note that you have to add the vertical chromosome offset (get_vertical_offset) to this number the get the actual image coordinates.
798 sub mapunits2pixels
{
802 if (! $cM) { $cM=0; }
803 my $pixels = ($cM - $self->get_start_cM()) * $self->get_scaling_factor();
804 #print STDERR "Scaling factor: $self->{scaling_factor} cM: $cM = $pixels pixels\n";
808 =head2 function get_pixels_cM()
810 my $cM = $chr->get_pixels_cM($pixels);
812 Gets the number of cM that the number of $pixels correspond to. Note that you have to substract the vertical chromosome offset (get_vertical_offset) from the pixels this number the get the correct number of cM.
819 my $cM = ($pixels / $self->{scaling_factor
}) + $self->get_start_cM();
828 if ($self->is_section()) {
829 if ($cM >= $self->get_start_cM() && $cM <= $self ->get_end_cM()) {
838 =head2 function distribute_labels()
840 Synopsis: $c->distribute_labels()
842 Returns: distributes the labels nicely along the chromosome
843 Side effects: changes the positions of the labels
844 Description: first it calculates label positions by setting the first label
845 to be equal to the top of the chromosome, then adjusts
846 all following label positions not to overlap with the
847 previous label, pushing them down if necessary.
848 Second, it calculates the label positions by setting the last
849 label to be equal to the end of the chromosome, and iterates
850 through all labels not to overlap with the previous label, if
851 necessary, pushing it up. To calculate the final label
852 position, it takes the average of the downwards and the
853 upwards iterations through the labels. Note that the labels need
854 to be ordered for this to work.
855 this function was renamed slightly (_ omitted) and refactored
856 such that left labels and right labels are distributed
861 sub distribute_labels
{
863 $self->_distribute_labels("left");
864 $self->_distribute_labels("right");
869 sub _distribute_labels
{
873 my @m = $self->get_markers();
874 my $lastlabelpos = 0;
876 # calculate the downwards offsets
883 #if ($m->get_label_side() !~ /right|left/i) { die "Label side is not set correctly for marker ".$m->get_name()."\n"; }
884 if ($m->is_visible() && $m->is_label_visible() && ($m->get_label_side() eq "$side")) { # || !$m->get_label_side())) {
885 my $cM= $m->get_offset();
886 my $labelpos = $self->mapunits2pixels($cM)+$self->get_vertical_offset();
887 my $labelheight = $m -> get_label_height
();
888 #print STDERR "label height: $labelheight\n";
890 if (($labelpos-$labelheight)<$lastlabelpos) {
891 $labelpos = $lastlabelpos+$labelheight;
892 if (exists($downwards{$m->get_name()})) { warn "CATASTROPHE: Duplicate marker name ".($m->get_name())."\n"; }
893 $downwards{$m->get_name()} = $labelpos;
896 $downwards{$m->get_name()}=$labelpos;
898 $lastlabelpos = $labelpos;
902 # calculate the upwards offsets
905 my $toplabelpos = $self->get_vertical_offset()+$self->get_height()+12+$m[-1]->get_label_height();
906 foreach my $m (reverse(@m)) {
907 if($m->is_visible() && $m->is_label_visible() && $m->get_label_side() eq "$side") {
908 my $cM=$m->get_offset();
909 my $labelpos = $self->mapunits2pixels($cM)+$self->get_vertical_offset();
910 #print STDERR "VERTICAL OFFSET = ".$self->get_vertical_offset()."\n";
911 my $labelheight= $m->get_label_height();
912 # print STDERR $m->get_name()." offset = $cM ID=".$m->get_id()."\n";
913 if (($labelpos+$labelheight)>$toplabelpos) {
914 $labelpos = $toplabelpos-$labelheight;
915 if (!$m->get_name()) { warn "CATASTROPHE: Didn't get name on marker ".$m->get_id()."\n"; }
916 if (exists($upwards{$m->get_name})) { warn "CATASTHROPHE: duplicate marker name ".$m->get_name()."\n"; }
917 $upwards{$m->get_name()} = $labelpos;
920 $upwards{$m->get_name()}=$labelpos;
922 $toplabelpos = $labelpos;
926 # load into marker objects
929 if ($m->get_label_side() eq "$side") {
930 my $marker_name = $m -> get_name
();
931 # test to prevent warnings...
932 if (! $downwards{$marker_name}) { $downwards{$marker_name}=0; }
933 if (! $upwards{$marker_name}) { $upwards{$marker_name} = 0; }
935 my $pixels = int(($downwards{$marker_name}+$upwards{$marker_name})/2);
936 #print STDERR "Vertical pixels for marker ".$m->get_marker_name()." : $pixels.\n";
937 $m->get_label()->set_vertical_offset($pixels);
942 =head2 function distribute_label_stacking()
947 Side effects: distributes the labels of the markers of type
948 RangeMarker such that they do not collide
949 vertically, and does this for each side
955 sub distribute_label_stacking
{
957 $self->_distribute_label_stacking("left");
958 $self->_distribute_label_stacking("right");
961 sub _distribute_label_stacking
{
965 my $maximum_stacking_level = 0;
967 my $TRACK_LIMIT = 20000; # exit the loop if we exceed this number of tracks.
969 # the @tracks array keeps track of which positions are already occupied by giving the
970 # lower boundary to which the track has been filled.
971 # it is important that the markers are sorted by position in some way
972 # for this to look good (currently, for physical map, BACs are sorted by status, association_type
973 # and offset, which forces sequenced BACs to be rendered next to the chromosome
974 # and other BACs further away). All other maps should just be sorted by position.
976 foreach my $m ($self->get_markers()) {
977 if ($m->is_visible() && $m->get_label_side() eq $side) {
979 # define the position of the marker
980 my $upper_edge = $m->get_offset()-$m->get_north_range(); # the position of the top of the marker
981 if ($upper_edge < 0 || !defined($upper_edge)) { $upper_edge = 0; }
982 my $lower_edge = $m->get_offset()+$m->get_south_range(); # the position of the bottom of the marker
983 if ($lower_edge < 0 || !defined($lower_edge)) { $lower_edge = 0; }
986 my $current_track = 1;
989 while (defined($tracks[$current_track]) && ($tracks[$current_track]>($upper_edge - $m->get_label()->get_vertical_stacking_spacing()))) {
991 if (!exists($tracks[$current_track]) || !defined($tracks[$current_track])) { $tracks[$current_track]=0; }
994 # under certain conditions an infinite loop may be created. To prevent it, we set
995 # an arbitrary limit on the number of tracks supported.
996 if ($current_track>$TRACK_LIMIT) {
998 # if ($m->get_marker_name() =~ /Lpen/) {
999 # print STDERR "Skipping pennellii bac ".($m->get_marker_name())." at position ".($m->get_offset())."\n";
1003 if ($current_track > $maximum_stacking_level) {
1004 $maximum_stacking_level = $current_track;
1009 # print STDERR "TRACK $current_track has lower bound $tracks[$current_track]. \n";
1010 $tracks[$current_track] = $lower_edge;
1012 $m->get_label()->set_stacking_level($current_track);
1014 #print STDERR "TRACKS: ".($m->get_marker_name())." [$current_track] = $tracks[$current_track], $upper_edge\n";
1018 # here we adjust the label_spacer property of the label to be higher than the highest track.
1019 # seems like a good idea but it may produce weird effects on some maps. Maybe this should
1020 # be factored out into another subroutine so that it could be called only if desired.
1022 foreach my $m ($self->get_markers()) {
1023 if ( ($m->get_label_side() eq "$side") && ($m->get_label()->get_stacking_height()>0)) {
1024 my $label_spacer = $m->get_label()->get_label_spacer();
1025 my $dynamic_spacer = ($maximum_stacking_level+1) * $m->get_label()->get_stacking_height()+10;
1026 if ($dynamic_spacer > $label_spacer ) {
1027 $m->get_label()->set_label_spacer( $dynamic_spacer );
1032 warn "Skipped $skipped because of space constraints (max $TRACK_LIMIT tracks).\n";
1036 =head2 function draw_chromosome()
1038 $chr->draw_chromosome($image, $type);
1040 Draws the chromosome on $image. Image is a GD image. The default chromosome rendering is as a 'sausage' type chromosome. A line model is available by supplying the type parameter "line". This is usually called by the MapImage object.
1044 sub draw_chromosome
{
1048 # draw chromosome outline
1050 if (! $self->{style
}) { $self->{style
}=""; }
1051 if ($self->{style
} eq "line") {
1052 $self->draw_chromosome_line($image);
1054 elsif ($self->{style
} eq "sausage") {
1055 $self->draw_chromosome_sausage($image);
1057 else { $self->draw_chromosome_sausage($image); }
1060 sub draw_chromosome_line
{
1064 my $color = $image -> colorResolve
($self->{color
}[0], $self->{color
}[1], $self->{color
}[2]);
1065 #print STDERR "$self->{x}, $self->get_vertical_offset(), $self->{x}, $self->get_vertical_offset()+$self->{height}, $color\n";
1066 $image -> line
($self->get_horizontal_offset(), $self->get_vertical_offset(), $self->get_horizontal_offset(), $self->get_vertical_offset()+$self->{height
}, $color);
1069 sub draw_chromosome_sausage
{
1075 my $outline_color = $image -> colorResolve
($self->{outline_color
}[0], $self->{outline_color
}[1], $self->{outline_color
}[2]);
1076 my $hilite_color = $image -> colorResolve
($self->{hilite_color
}[0], $self->{hilite_color
}[1], $self->{hilite_color
}[2]);
1077 my $color = $image -> colorResolve
($self->{color
}[0], $self->{color
}[1], $self->{color
}[2]);
1079 my $halfwidth = $self ->{width
}/2;
1081 $image -> line
($self->get_horizontal_offset() - $halfwidth, $self->get_vertical_offset() , $self->get_horizontal_offset()-$halfwidth, $self->get_vertical_offset()+$self->{height
}, $outline_color);
1082 $image -> line
($self->get_horizontal_offset() + $halfwidth, $self->get_vertical_offset() , $self->get_horizontal_offset()+$halfwidth, $self->get_vertical_offset()+$self->{height
}, $outline_color);
1083 if ($self->is_section()) {
1084 my $text_color = $image -> colorResolve
(50, 50, 50);
1085 $image -> line
($self->get_horizontal_offset()-$halfwidth, $self->get_vertical_offset(), $self->get_horizontal_offset()+$halfwidth, $self->get_vertical_offset(), $outline_color);
1086 $image -> line
($self->get_horizontal_offset()-$halfwidth, $self->get_vertical_offset()+$self->{height
}, $self->get_horizontal_offset()+$halfwidth, $self->get_vertical_offset()+$self->{height
}, $outline_color);
1087 $image -> fill
($self->get_horizontal_offset(), $self->get_vertical_offset()+1, $color);
1088 my $top_label = int($self->get_start_cM()).$self->get_units();
1089 my $bottom_label = int($self ->{end_cM
}).$self->get_units();
1090 $image -> string
($self->{font
}, $self->get_horizontal_offset()-$self->{font
}->width()* length($top_label)/2, $self->get_vertical_offset()-$self->{font
}->height()-3, $top_label, $text_color);
1091 $image -> string
($self->{font
}, $self->get_horizontal_offset() - $self->{font
}->width() * length($bottom_label)/2, $self->get_vertical_offset()+$self->get_height()+3, $bottom_label,$text_color);
1094 $image -> setAntiAliased
($outline_color);
1095 $image -> arc
($self->get_horizontal_offset(), $self->get_vertical_offset(), $self->{width
}, $self->{curved_height
}, 180, 0, GD
::gdAntiAliased
);
1096 $image -> arc
($self->get_horizontal_offset(), $self->get_vertical_offset()+$self->{height
}, $self->{width
}, $self->{curved_height
}, 0, 180, GD
::gdAntiAliased
);
1097 $image -> fill
($self->get_horizontal_offset(), $self->get_vertical_offset(), $color);
1102 if ($self->{hilite_start
} || $self->{hilite_end
}) {
1104 # if we are dealing with a section, don't hilite more than the section...
1106 if ($self->is_section()) {
1107 if ($self->{hilite_start
} < $self->get_start_cM()) {
1108 $self->{hilite_start
} = $self->get_start_cM();
1110 if ($self->{hilite_end
} > $self->get_end_cM()) {
1111 $self->{hilite_end
} = $self->get_end_cM;
1115 my $start = $self->get_vertical_offset()+$self->mapunits2pixels($self->{hilite_start
});
1116 my $end = $self->get_vertical_offset()+$self->mapunits2pixels($self->{hilite_end
});
1117 $image -> rectangle
($self->get_horizontal_offset()-$halfwidth,
1119 $self->get_horizontal_offset()+$halfwidth,
1122 $image -> fill
($self->get_horizontal_offset(), $start+1, $hilite_color);
1126 $self->draw_caption($image);
1133 my $outline_color = $image -> colorResolve
(
1134 $self->{outline_color
}[0],
1135 $self->{outline_color
}[1],
1136 $self->{outline_color
}[2]
1138 my $bigfont = GD
::Font
->Large();
1141 $self->get_horizontal_offset()- $bigfont->width() * length($self->get_caption())/2,
1142 $self->get_vertical_offset()-$bigfont->height()-$self->{curved_height
}/2,
1143 $self->get_caption(), $outline_color );