3 # Copyright (C) 2007 Martin A. Hansen.
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # http://www.gnu.org/copyleft/gpl.html
22 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
25 # Routines to plot stuff with Gnuplot and SVG.
28 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
38 use vars qw ( @ISA @EXPORT );
46 @ISA = qw( Exporter );
49 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
52 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LINEPLOTS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
57 # Martin A. Hansen, January 2008.
59 # Plots a simple lineplot using Gnuplot.
61 my ( $data, # data table - each column will be plottet as one line.
62 $options, # options hash
63 $tmp_dir, # temporary directory
68 my ( $tmp_file, $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines, $xtic_space, @plot_cmd );
70 $tmp_dir ||= $ENV{ 'BP_TMP' };
72 $tmp_file = "$tmp_dir/lineplot_simple.tab";
74 $fh_out = Maasha::Filesys::file_write_open( $tmp_file );
76 map { print $fh_out join( "\t", @{ $_ } ), "\n" } @{ $data };
80 $options->{ "terminal" } ||= "dumb";
84 $pid = open2( $fh_out, $fh_in, $cmd );
88 print $fh_in "set terminal $options->{ 'terminal' }\n";
89 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
90 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
91 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
92 print $fh_in "set grid\n" if not $options->{ "terminal" } eq "dumb";
93 print $fh_in "set autoscale\n";
94 print $fh_in "unset key\n";
95 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
97 for ( $i = 1; $i < scalar @{ $data->[ 0 ] } + 1; $i++ ) {
98 push @plot_cmd, qq("$tmp_file" using $i with lines ls 1);
101 print $fh_in "plot " . join( ", ", @plot_cmd ) . "\n";
105 while ( $line = <$fh_out> )
118 return wantarray ? @lines : \@lines;
122 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> HISTOGRAMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
127 # Martin A. Hansen, August 2007.
129 # Plots a simple histogram using Gnuplot.
131 my ( $data, # list of [ xlabel, data value ] tuples
132 $options, # options hash
137 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines );
139 $options->{ "terminal" } ||= "dumb";
143 $pid = open2( $fh_out, $fh_in, $cmd );
147 # print $fh_in "set terminal $options->{ 'terminal' } 10 \n"; # adsjust fontsize to 10 - find some other way to do this, because it don't work with SVG.
148 print $fh_in "set terminal $options->{ 'terminal' }\n";
149 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
150 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
151 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
152 print $fh_in "set autoscale\n";
153 print $fh_in "unset key\n";
154 print $fh_in "set style fill solid\n";
155 print $fh_in "set style histogram title offset character 0, 0, 0\n";
156 print $fh_in "set style data histograms\n";
157 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
159 print $fh_in "plot '-' using 2:xticlabels(1)\n";
161 for ( $i = 0; $i < @{ $data }; $i++ )
163 print $fh_in join( "\t", "\"$data->[ $i ]->[ 0 ]\"", $data->[ $i ]->[ 1 ] ), "\n";
168 while ( $line = <$fh_out> )
179 return wantarray ? @lines : \@lines;
183 sub histogram_lendist
185 # Martin A. Hansen, August 2007.
187 # Plots a histogram using Gnuplot.
189 my ( $data, # list of [ xlabel, data value ] tuples
190 $options, # options hash
195 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines, $xtic_space );
197 $options->{ "terminal" } ||= "dumb";
199 if ( $data->[ -1 ]->[ 0 ] <= 10 ) {
201 } elsif ( $data->[ -1 ]->[ 0 ] <= 100 ) {
203 } elsif ( $data->[ -1 ]->[ 0 ] <= 250 ) {
205 } elsif ( $data->[ -1 ]->[ 0 ] <= 500 ) {
207 } elsif ( $data->[ -1 ]->[ 0 ] <= 1000 ) {
209 } elsif ( $data->[ -1 ]->[ 0 ] <= 2500 ) {
211 } elsif ( $data->[ -1 ]->[ 0 ] <= 5000 ) {
213 } elsif ( $data->[ -1 ]->[ 0 ] <= 10000 ) {
215 } elsif ( $data->[ -1 ]->[ 0 ] <= 50000 ) {
217 } elsif ( $data->[ -1 ]->[ 0 ] <= 100000 ) {
223 $pid = open2( $fh_out, $fh_in, $cmd );
225 print $fh_in "set terminal $options->{ 'terminal' }\n";
226 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
227 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
228 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
229 print $fh_in "set autoscale\n";
230 print $fh_in "unset key\n";
231 print $fh_in "set style fill solid\n";
232 print $fh_in "set style histogram clustered gap 1 title offset character 0, 0, 0\n";
233 print $fh_in "set style data histograms\n";
234 print $fh_in "set xtics 0,$xtic_space border out nomirror\n";
236 print $fh_in "plot '-' using 1\n";
238 for ( $i = 0; $i < @{ $data }; $i++ )
240 $data->[ $i ]->[ 0 ] = "." if $data->[ $i ]->[ 0 ] % 10 != 0;
242 print $fh_in join( "\t", $data->[ $i ]->[ 1 ] ), "\n";
247 while ( $line = <$fh_out> )
258 return wantarray ? @lines : \@lines;
262 sub histogram_chrdist
264 # Martin A. Hansen, August 2007.
266 # Plots a histogram using Gnuplot.
268 my ( $data, # list of [ xlabel, data value ] tuples
269 $options, # options hash
274 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines );
276 $options->{ "terminal" } ||= "dumb";
280 $pid = open2( $fh_out, $fh_in, $cmd );
282 print $fh_in "set terminal $options->{ 'terminal' }\n";
283 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
284 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
285 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
286 print $fh_in "set autoscale\n";
287 print $fh_in "unset key\n";
288 print $fh_in "set style fill solid\n";
289 print $fh_in "set style histogram title offset character 0, 0, 0\n";
290 print $fh_in "set style data histograms\n";
291 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
293 print $fh_in "plot '-' using 2:xticlabels(1)\n";
295 for ( $i = 0; $i < @{ $data }; $i++ ) {
296 print $fh_in join( "\t", "\"$data->[ $i ]->[ 0 ]\"", $data->[ $i ]->[ 1 ] ), "\n";
301 while ( $line = <$fh_out> )
312 return wantarray ? @lines : \@lines;
316 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KARYOGRAM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
321 # Martin A. Hansen, August 2007.
323 # Plot hits on a karyogram for a given genome.
325 my ( $data, # list of [ chr, beg, end ] triples
326 $options, # hashref with options
331 my ( $karyo_file, $svg, $features, $karyo );
333 if ( $options->{ "genome" } eq "hg18" )
335 $karyo_file = $ENV{ 'BP_DIR' } . "/bp_data/human_cytobands.txt";
337 elsif( $options->{ "genome" } eq "mm9" )
339 $karyo_file = $ENV{ 'BP_DIR' } . "/bp_data/mouse_cytobands.txt";
342 $karyo = parse_karyo_data( $karyo_file );
346 chromosome_layout( $svg, $karyo, $data );
354 # X q26.1 129700001 130200000 gneg
356 # color: /etc/X11/rgb.txt
361 my ( $fh, $chr, $line, $name, $beg, $end, $color, %features, %color_hash );
367 gpos75 => "DarkGrey",
368 gpos66 => "DarkGrey",
370 gpos33 => "LightGrey",
371 gpos25 => "LightGrey",
374 # gpos75 => "rgb(169,169,169)",
375 # gpos66 => "gray66",
376 # gpos66 => "#8e8e8e",
377 # gpos50 => "gray50",
378 # gpos33 => "#e3e3e3",
379 # gpos33 => "gray33",
380 # gpos25 => "gray25",
381 # stalk => "rgb(169,169,169)",
385 $fh = Maasha::Filesys::file_read_open( $file );
387 while ( $line = <$fh> )
391 next if $line =~ /^#/;
393 # ( $chr, $name, $beg, $end, $color ) = split "\t", $line;
394 ( $chr, $beg, $end, $name, $color ) = split "\t", $line;
396 # if ( $color =~ /^gpos(\d+)/ ) {
397 # $color = color_intensity( $1 );
398 # } elsif ( exists $color_hash{ $color } ) {
399 $color = $color_hash{ $color };
401 # die qq(ERROR: Unknown color->$color\n);
404 if ( exists $features{ $chr } )
406 push @{ $features{ $chr } }, [ $name, $beg, $end, $color ];
410 $features{ $chr } = [ [ $name, $beg, $end, $color ] ];
416 return wantarray ? %features : \%features;
422 # Martin A. Hansen, September 2007.
424 # Converts a gray scale intensity in percent to rgb.
426 my ( $percent, # color intensity
433 $num = int( $percent * 256 / 100 );
437 $hex = sprintf "%x", $num;
439 return "#$hex$hex$hex";
441 # return "rgb($num,$num,$num)";
447 # Martin A. Hansen, September 2005.
449 # initializes svg image.
451 # returns an image object
467 sub chromosome_layout
469 # Martin A. Hansen, January 2004 - August 2007.
471 # Plots all chromosomes in a single
473 my ( $svg, # image object
474 $karyo_list, # hashref with karyo data
475 $feat_list, # hashref with features
478 # returns an image object
480 my ( $layout_obj, $i, $x, $y, $max, $factor, $chr_len, $chr_width, $chr_cent, $chr, $feat, $karyo, @list, $A, $B );
482 $layout_obj = $svg->group(
486 $max = $karyo_list->{ "chr1" }->[ -1 ]->[ 2 ];
487 $factor = ( HEIGHT / 2 ) / $max;
488 $chr_width = ( HEIGHT / 4 ) / 13;
490 foreach $karyo ( keys %{ $karyo_list } ) {
491 map { $_->[ 1 ] *= $factor; $_->[ 2 ] *= $factor } @{ $karyo_list->{ $karyo } };
494 foreach $feat ( keys %{ $feat_list } ) {
495 map { $_->[ 0 ] *= $factor; $_->[ 1 ] *= $factor } @{ $feat_list->{ $feat } };
498 # @list = sort { $A = $a; $B = $b; $A =~ s/chr//; $B =~ s/chr//; $A <=> $B } keys %{ $karyo_list };
500 # splice @list, 0, 2;
501 # push @list, "chrX", "chrY";
508 $chr_len = $karyo_list->{ $chr }->[ -1 ]->[ 2 ];
509 $chr_cent = find_cent( $karyo_list->{ $list[ $i ] } );
511 $y = HEIGHT / 2 - $chr_len;
512 $x = ( WIDTH / ( @list + 2 ) ) * ( $i + 1 );
514 draw_chr( $layout_obj, $x, $y, $chr_len, $chr_width, $chr_cent, $chr, $karyo_list, $feat_list );
523 # Martin A. Hansen, December 2003.
525 # Finds the centromeric region in the karyo data.
529 my ( $acen, @nums, $cent );
531 @{ $acen } = grep { grep { /^DarkGrey$/ } @{ $_ } } @{ $list };
533 push @nums, $acen->[ 0 ]->[ 1 ];
534 push @nums, $acen->[ 0 ]->[ 2 ];
535 push @nums, $acen->[ 1 ]->[ 1 ];
536 push @nums, $acen->[ 1 ]->[ 2 ];
538 @nums = sort { $a <=> $b } @nums;
540 $cent = ( $nums[ 1 ] + $nums[ 2 ] ) / 2;
548 # Martin A. Hansen, December 2003.
550 # draws a whole cromosome with or without centromeric region
552 my ( $svg, # image object
555 $chr_len, # lenght of chromosome
556 $chr_width, # width of chromosome
557 $chr_cent, # position of centromeric region
559 $karyo_list, # hashref with karyo data
560 $feat_list, # hashref with features
563 # returns image object
565 my ( $chr_obj, $clip_obj, $gr_obj );
567 $chr_obj = $svg->group(
571 if ( exists $feat_list->{ $chr } ) {
572 draw_chr_feat( $chr_obj, $x, $y, $chr_width, $feat_list->{ $chr } );
575 $clip_obj = $chr_obj->clipPath(
576 id => $chr . "_clipPath",
579 $clip_obj->rectangle(
580 x => sprintf( "%.3f", $x ),
581 y => sprintf( "%.3f", $y ),
582 width => sprintf( "%.3f", $chr_width ),
583 height => sprintf( "%.3f", $chr_cent ),
588 $clip_obj->rectangle(
589 x => sprintf( "%.3f", $x ),
590 y => sprintf( "%.3f", $y + $chr_cent ),
591 width => sprintf( "%.3f", $chr_width ),
592 height => sprintf( "%.3f", $chr_len - $chr_cent ),
597 $gr_obj = $chr_obj->group(
598 "clip-path" => "url(#$chr" . "_clipPath)",
601 if ( exists $karyo_list->{ $chr } ) {
602 draw_karyo_data( $gr_obj, $x, $y, $chr_width, $karyo_list->{ $chr } );
606 x => sprintf( "%.3f", $x ),
607 y => sprintf( "%.3f", $y ),
608 width => sprintf( "%.3f", $chr_width ),
609 height => sprintf( "%.3f", $chr_cent ),
616 x => sprintf( "%.3f", $x ),
617 y => sprintf( "%.3f", $y + $chr_cent ),
618 width => sprintf( "%.3f", $chr_width ),
619 height => sprintf( "%.3f", $chr_len - $chr_cent ),
625 draw_chr_num( $chr_obj, $x, $y, $chr_len, $chr_width, $chr );
631 # Martin A. Hansen, December 2003.
633 # draws a cromosome number
635 my ( $svg, # image object
638 $chr_len, # lenght of chromosome
639 $chr_width, # width of chromosome
640 $chr, # chromosome number
643 # returns image object
645 my ( $chr_num, $chars, @a, $word_width );
650 $chars = @a = split "", $chr_num;
652 $word_width = ( $chars * 8 ) / 2;
655 x => sprintf("%.3f", $x + ( $chr_width / 2 ) - $word_width ),
656 y => sprintf("%.3f", $y + $chr_len + 15 ),
657 )->cdata( $chr_num );
663 # Martin A. Hansen, February 2004.
665 # Plots chromosome features
674 # returns an image object
676 my ( $feat_beg, $feat_end, $feat_height, $i, $color, $label );
678 for ( $i = 0; $i < @{ $list }; $i++ )
680 ( $label, $feat_beg, $feat_end, $color ) = @{ $list->[ $i ] };
682 $feat_height = $feat_end - $feat_beg;
685 x => sprintf("%.3f", $x ),
686 y => sprintf("%.3f", $y + $feat_beg ),
687 width => sprintf("%.3f", $chr_width ),
688 height => sprintf("%.3f", $feat_height ),
698 # Martin A. Hansen, February 2004.
700 # Plots chromosome features
709 # returns an image object
711 my ( $feat_beg, $feat_end, $feat_height, $i, $color, $height, $width, $x1, $y1, %lookup );
713 for ( $i = 0; $i < @{ $list }; $i++ )
715 ( $feat_beg, $feat_end, $color ) = @{ $list->[ $i ] };
717 $feat_height = $feat_end - $feat_beg;
719 $x1 = sprintf("%.0f", $x + ( $chr_width / 2 ) ),
720 $y1 = sprintf("%.0f", $y + $feat_beg ),
721 $width = sprintf("%.0f", ( $chr_width / 2 ) + 5 ),
722 $height = sprintf("%.0f", $feat_height );
728 if ( exists $lookup{ $x1 . $y1 } ) {
731 $lookup{ $x1 . $y1 } = 1;
747 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SEQUENCE LOGO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
752 # Martin A. Hansen, August 2007.
754 # Calculates and renders a sequence logo in SVG format.
756 my ( $entries, # aligned sequence entries - list of tuples
761 my ( $type, $bit_max, $logo_data, $svg );
763 $type = Maasha::Seq::seq_guess_type( $entries->[ 0 ]->[ 1 ] );
765 if ( $type =~ /^p/i ) {
771 $logo_data = Maasha::Seq::seqlogo_calc( $bit_max, $entries );
773 $svg = Maasha::Plot::svg_init();
775 svg_draw_logo( $svg, $logo_data, $bit_max, $type );
776 svg_draw_logo_scale( $svg, $bit_max );
784 # Martin A. Hansen, October 2005.
786 # inititalizes SVG object, which is returned.
792 'font-weight' => 'normal',
793 'font-family' => 'Courier New',
804 # Martin A. Hansen, January 2007.
806 # Renders a sequence logo in SVG using a
807 # given data structure with logo details.
809 my ( $svg, # SVG object,
810 $logo_data, # data structure
811 $bit_max, # maximum bit height
812 $type, # sequence type
813 $nocolor, # render black and white - OPTIONAL
816 my ( $pos, $elem, $char, $char_height_bit, $char_height_px, $block, $x, $y, $scale_factor, $color );
820 foreach $pos ( @{ $logo_data } )
824 foreach $elem ( @{ $pos } )
826 ( $char, $char_height_bit ) = @{ $elem };
828 $char_height_px = $char_height_bit * ( 30 / $bit_max );
830 $block = $svg->group(
831 transform => "translate($x,$y)",
834 $scale_factor = $char_height_px / 7;
838 } elsif ( $type eq "dna" or $type eq "rna" ) {
839 $color = Maasha::Seq::color_nuc( $char );
841 $color = Maasha::Seq::color_pep( $char );
845 transform => "scale(1,$scale_factor)",
849 'font-weight' => 'bold',
850 fill => Maasha::Seq::color_palette( $color ),
854 $y -= $char_height_px;
862 sub svg_draw_logo_scale
864 # Martin A. Hansen, January 2007.
866 # draws the bit scale for the sequence logo
868 my ( $svg, # SVG object,
869 $bit_max, # maximum bit height
874 $scale = $svg->group(
875 transform => "translate(-10)",
878 'font-size' => '8px',
883 # transform => "translate(0,$logo_y)",
884 transform => "rotate(-90)",
899 for ( $i = 0; $i <= $bit_max; $i++ )
904 y1 => ( 30 / $bit_max ) * $i,
905 y2 => ( 30 / $bit_max ) * $i,
910 y => ( 30 / $bit_max ) * $i + 2,
914 )->cdata( $bit_max - $i );
919 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<