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 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
39 use vars qw ( @ISA @EXPORT );
47 @ISA = qw( Exporter );
50 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
53 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LINEPLOTS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
58 # Martin A. Hansen, January 2008.
60 # Plots a simple lineplot using Gnuplot.
62 my ( $data, # data table - each column will be plottet as one line.
63 $options, # options hash
64 $tmp_dir, # temporary directory
69 my ( $tmp_file, $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines, $xtic_space, @plot_cmd );
71 $tmp_dir ||= $ENV{ 'BP_TMP' };
73 $tmp_file = "$tmp_dir/lineplot_simple.tab";
75 $fh_out = Maasha::Filesys::file_write_open( $tmp_file );
77 map { print $fh_out join( "\t", @{ $_ } ), "\n" } @{ $data };
81 $options->{ "terminal" } ||= "dumb";
85 $pid = open2( $fh_out, $fh_in, $cmd );
89 print $fh_in "set terminal $options->{ 'terminal' }\n";
90 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
91 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
92 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
93 print $fh_in "set grid\n" if not $options->{ "terminal" } eq "dumb";
94 print $fh_in "set autoscale\n";
95 print $fh_in "unset key\n";
96 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
98 for ( $i = 1; $i < scalar @{ $data->[ 0 ] } + 1; $i++ ) {
99 push @plot_cmd, qq("$tmp_file" using $i with lines ls 1);
102 print $fh_in "plot " . join( ", ", @plot_cmd ) . "\n";
106 while ( $line = <$fh_out> )
119 return wantarray ? @lines : \@lines;
123 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> HISTOGRAMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
128 # Martin A. Hansen, August 2007.
130 # Plots a simple histogram using Gnuplot.
132 my ( $data, # list of [ xlabel, data value ] tuples
133 $options, # options hash
138 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines );
140 $options->{ "terminal" } ||= "dumb";
144 $pid = open2( $fh_out, $fh_in, $cmd );
148 # 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.
149 print $fh_in "set terminal $options->{ 'terminal' }\n";
150 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
151 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
152 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
153 print $fh_in "set autoscale\n";
154 print $fh_in "unset key\n";
155 print $fh_in "set style fill solid\n";
156 print $fh_in "set style histogram title offset character 0, 0, 0\n";
157 print $fh_in "set style data histograms\n";
158 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
160 print $fh_in "plot '-' using 2:xticlabels(1)\n";
162 for ( $i = 0; $i < @{ $data }; $i++ )
164 print $fh_in join( "\t", "\"$data->[ $i ]->[ 0 ]\"", $data->[ $i ]->[ 1 ] ), "\n";
169 while ( $line = <$fh_out> )
180 return wantarray ? @lines : \@lines;
184 sub histogram_lendist
186 # Martin A. Hansen, August 2007.
188 # Plots a histogram using Gnuplot.
190 my ( $data, # list of [ xlabel, data value ] tuples
191 $options, # options hash
196 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines, $xtic_space );
198 $options->{ "terminal" } ||= "dumb";
200 if ( $data->[ -1 ]->[ 0 ] <= 10 ) {
202 } elsif ( $data->[ -1 ]->[ 0 ] <= 100 ) {
204 } elsif ( $data->[ -1 ]->[ 0 ] <= 250 ) {
206 } elsif ( $data->[ -1 ]->[ 0 ] <= 500 ) {
208 } elsif ( $data->[ -1 ]->[ 0 ] <= 1000 ) {
210 } elsif ( $data->[ -1 ]->[ 0 ] <= 2500 ) {
212 } elsif ( $data->[ -1 ]->[ 0 ] <= 5000 ) {
214 } elsif ( $data->[ -1 ]->[ 0 ] <= 10000 ) {
216 } elsif ( $data->[ -1 ]->[ 0 ] <= 50000 ) {
218 } elsif ( $data->[ -1 ]->[ 0 ] <= 100000 ) {
224 $pid = open2( $fh_out, $fh_in, $cmd );
226 print $fh_in "set terminal $options->{ 'terminal' }\n";
227 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
228 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
229 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
230 print $fh_in "set autoscale\n";
231 print $fh_in "unset key\n";
232 print $fh_in "set style fill solid\n";
233 print $fh_in "set style histogram clustered gap 1 title offset character 0, 0, 0\n";
234 print $fh_in "set style data histograms\n";
235 print $fh_in "set xtics 0,$xtic_space border out nomirror\n";
237 print $fh_in "plot '-' using 1\n";
239 for ( $i = 0; $i < @{ $data }; $i++ )
241 $data->[ $i ]->[ 0 ] = "." if $data->[ $i ]->[ 0 ] % 10 != 0;
243 print $fh_in join( "\t", $data->[ $i ]->[ 1 ] ), "\n";
248 while ( $line = <$fh_out> )
259 return wantarray ? @lines : \@lines;
263 sub histogram_chrdist
265 # Martin A. Hansen, August 2007.
267 # Plots a histogram using Gnuplot.
269 my ( $data, # list of [ xlabel, data value ] tuples
270 $options, # options hash
275 my ( $pid, $fh_in, $fh_out, $cmd, $i, $line, @lines );
277 $options->{ "terminal" } ||= "dumb";
281 $pid = open2( $fh_out, $fh_in, $cmd );
283 print $fh_in "set terminal $options->{ 'terminal' }\n";
284 print $fh_in "set title \"$options->{ 'title' }\"\n" if $options->{ "title" };
285 print $fh_in "set xlabel \"$options->{ 'xlabel' }\"\n" if $options->{ "xlabel" };
286 print $fh_in "set ylabel \"$options->{ 'ylabel' }\"\n" if $options->{ "ylabel" };
287 print $fh_in "set autoscale\n";
288 print $fh_in "unset key\n";
289 print $fh_in "set style fill solid\n";
290 print $fh_in "set style histogram title offset character 0, 0, 0\n";
291 print $fh_in "set style data histograms\n";
292 print $fh_in "set xtics border in scale 0 nomirror rotate by 90 offset character 0, 0, 0\n";
294 print $fh_in "plot '-' using 2:xticlabels(1)\n";
296 for ( $i = 0; $i < @{ $data }; $i++ ) {
297 print $fh_in join( "\t", "\"$data->[ $i ]->[ 0 ]\"", $data->[ $i ]->[ 1 ] ), "\n";
302 while ( $line = <$fh_out> )
313 return wantarray ? @lines : \@lines;
317 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KARYOGRAM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
322 # Martin A. Hansen, August 2007.
324 # Plot hits on a karyogram for a given genome.
326 my ( $data, # list of [ chr, beg, end ] triples
327 $options, # hashref with options
332 my ( $karyo_file, $svg, $features, $karyo );
334 if ( $options->{ "genome" } eq "hg18" )
336 $karyo_file = $ENV{ 'BP_DIR' } . "/bp_data/human_cytobands.txt";
338 elsif( $options->{ "genome" } eq "mm9" )
340 $karyo_file = $ENV{ 'BP_DIR' } . "/bp_data/mouse_cytobands.txt";
343 $karyo = parse_karyo_data( $karyo_file );
347 chromosome_layout( $svg, $karyo, $data );
355 # X q26.1 129700001 130200000 gneg
357 # color: /etc/X11/rgb.txt
362 my ( $fh, $chr, $line, $name, $beg, $end, $color, %features, %color_hash );
368 gpos75 => "DarkGrey",
369 gpos66 => "DarkGrey",
371 gpos33 => "LightGrey",
372 gpos25 => "LightGrey",
375 # gpos75 => "rgb(169,169,169)",
376 # gpos66 => "gray66",
377 # gpos66 => "#8e8e8e",
378 # gpos50 => "gray50",
379 # gpos33 => "#e3e3e3",
380 # gpos33 => "gray33",
381 # gpos25 => "gray25",
382 # stalk => "rgb(169,169,169)",
386 $fh = Maasha::Filesys::file_read_open( $file );
388 while ( $line = <$fh> )
392 next if $line =~ /^#/;
394 # ( $chr, $name, $beg, $end, $color ) = split "\t", $line;
395 ( $chr, $beg, $end, $name, $color ) = split "\t", $line;
397 # if ( $color =~ /^gpos(\d+)/ ) {
398 # $color = color_intensity( $1 );
399 # } elsif ( exists $color_hash{ $color } ) {
400 $color = $color_hash{ $color };
402 # die qq(ERROR: Unknown color->$color\n);
405 if ( exists $features{ $chr } )
407 push @{ $features{ $chr } }, [ $name, $beg, $end, $color ];
411 $features{ $chr } = [ [ $name, $beg, $end, $color ] ];
417 return wantarray ? %features : \%features;
423 # Martin A. Hansen, September 2007.
425 # Converts a gray scale intensity in percent to rgb.
427 my ( $percent, # color intensity
434 $num = int( $percent * 256 / 100 );
438 $hex = sprintf "%x", $num;
440 return "#$hex$hex$hex";
442 # return "rgb($num,$num,$num)";
448 # Martin A. Hansen, September 2005.
450 # initializes svg image.
452 # returns an image object
468 sub chromosome_layout
470 # Martin A. Hansen, January 2004 - August 2007.
472 # Plots all chromosomes in a single
474 my ( $svg, # image object
475 $karyo_list, # hashref with karyo data
476 $feat_list, # hashref with features
479 # returns an image object
481 my ( $layout_obj, $i, $x, $y, $max, $factor, $chr_len, $chr_width, $chr_cent, $chr, $feat, $karyo, @list, $A, $B );
483 $layout_obj = $svg->group(
487 $max = $karyo_list->{ "chr1" }->[ -1 ]->[ 2 ];
488 $factor = ( HEIGHT / 2 ) / $max;
489 $chr_width = ( HEIGHT / 4 ) / 13;
491 foreach $karyo ( keys %{ $karyo_list } ) {
492 map { $_->[ 1 ] *= $factor; $_->[ 2 ] *= $factor } @{ $karyo_list->{ $karyo } };
495 foreach $feat ( keys %{ $feat_list } ) {
496 map { $_->[ 0 ] *= $factor; $_->[ 1 ] *= $factor } @{ $feat_list->{ $feat } };
499 # @list = sort { $A = $a; $B = $b; $A =~ s/chr//; $B =~ s/chr//; $A <=> $B } keys %{ $karyo_list };
501 # splice @list, 0, 2;
502 # push @list, "chrX", "chrY";
509 $chr_len = $karyo_list->{ $chr }->[ -1 ]->[ 2 ];
510 $chr_cent = find_cent( $karyo_list->{ $list[ $i ] } );
512 $y = HEIGHT / 2 - $chr_len;
513 $x = ( WIDTH / ( @list + 2 ) ) * ( $i + 1 );
515 draw_chr( $layout_obj, $x, $y, $chr_len, $chr_width, $chr_cent, $chr, $karyo_list, $feat_list );
524 # Martin A. Hansen, December 2003.
526 # Finds the centromeric region in the karyo data.
530 my ( $acen, @nums, $cent );
532 @{ $acen } = grep { grep { /^DarkGrey$/ } @{ $_ } } @{ $list };
534 push @nums, $acen->[ 0 ]->[ 1 ];
535 push @nums, $acen->[ 0 ]->[ 2 ];
536 push @nums, $acen->[ 1 ]->[ 1 ];
537 push @nums, $acen->[ 1 ]->[ 2 ];
539 @nums = sort { $a <=> $b } @nums;
541 $cent = ( $nums[ 1 ] + $nums[ 2 ] ) / 2;
549 # Martin A. Hansen, December 2003.
551 # draws a whole cromosome with or without centromeric region
553 my ( $svg, # image object
556 $chr_len, # lenght of chromosome
557 $chr_width, # width of chromosome
558 $chr_cent, # position of centromeric region
560 $karyo_list, # hashref with karyo data
561 $feat_list, # hashref with features
564 # returns image object
566 my ( $chr_obj, $clip_obj, $gr_obj );
568 $chr_obj = $svg->group(
572 if ( exists $feat_list->{ $chr } ) {
573 draw_chr_feat( $chr_obj, $x, $y, $chr_width, $feat_list->{ $chr } );
576 $clip_obj = $chr_obj->clipPath(
577 id => $chr . "_clipPath",
580 $clip_obj->rectangle(
581 x => sprintf( "%.3f", $x ),
582 y => sprintf( "%.3f", $y ),
583 width => sprintf( "%.3f", $chr_width ),
584 height => sprintf( "%.3f", $chr_cent ),
589 $clip_obj->rectangle(
590 x => sprintf( "%.3f", $x ),
591 y => sprintf( "%.3f", $y + $chr_cent ),
592 width => sprintf( "%.3f", $chr_width ),
593 height => sprintf( "%.3f", $chr_len - $chr_cent ),
598 $gr_obj = $chr_obj->group(
599 "clip-path" => "url(#$chr" . "_clipPath)",
602 if ( exists $karyo_list->{ $chr } ) {
603 draw_karyo_data( $gr_obj, $x, $y, $chr_width, $karyo_list->{ $chr } );
607 x => sprintf( "%.3f", $x ),
608 y => sprintf( "%.3f", $y ),
609 width => sprintf( "%.3f", $chr_width ),
610 height => sprintf( "%.3f", $chr_cent ),
617 x => sprintf( "%.3f", $x ),
618 y => sprintf( "%.3f", $y + $chr_cent ),
619 width => sprintf( "%.3f", $chr_width ),
620 height => sprintf( "%.3f", $chr_len - $chr_cent ),
626 draw_chr_num( $chr_obj, $x, $y, $chr_len, $chr_width, $chr );
632 # Martin A. Hansen, December 2003.
634 # draws a cromosome number
636 my ( $svg, # image object
639 $chr_len, # lenght of chromosome
640 $chr_width, # width of chromosome
641 $chr, # chromosome number
644 # returns image object
646 my ( $chr_num, $chars, @a, $word_width );
651 $chars = @a = split "", $chr_num;
653 $word_width = ( $chars * 8 ) / 2;
656 x => sprintf("%.3f", $x + ( $chr_width / 2 ) - $word_width ),
657 y => sprintf("%.3f", $y + $chr_len + 15 ),
658 )->cdata( $chr_num );
664 # Martin A. Hansen, February 2004.
666 # Plots chromosome features
675 # returns an image object
677 my ( $feat_beg, $feat_end, $feat_height, $i, $color, $label );
679 for ( $i = 0; $i < @{ $list }; $i++ )
681 ( $label, $feat_beg, $feat_end, $color ) = @{ $list->[ $i ] };
683 $feat_height = $feat_end - $feat_beg;
686 x => sprintf("%.3f", $x ),
687 y => sprintf("%.3f", $y + $feat_beg ),
688 width => sprintf("%.3f", $chr_width ),
689 height => sprintf("%.3f", $feat_height ),
699 # Martin A. Hansen, February 2004.
701 # Plots chromosome features
710 # returns an image object
712 my ( $feat_beg, $feat_end, $feat_height, $i, $color, $height, $width, $x1, $y1, %lookup );
714 for ( $i = 0; $i < @{ $list }; $i++ )
716 ( $feat_beg, $feat_end, $color ) = @{ $list->[ $i ] };
718 $feat_height = $feat_end - $feat_beg;
720 $x1 = sprintf("%.0f", $x + ( $chr_width / 2 ) ),
721 $y1 = sprintf("%.0f", $y + $feat_beg ),
722 $width = sprintf("%.0f", ( $chr_width / 2 ) + 5 ),
723 $height = sprintf("%.0f", $feat_height );
729 if ( exists $lookup{ $x1 . $y1 } ) {
732 $lookup{ $x1 . $y1 } = 1;
748 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SEQUENCE LOGO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
753 # Martin A. Hansen, August 2007.
755 # Calculates and renders a sequence logo in SVG format.
757 my ( $entries, # aligned sequence entries - list of tuples
762 my ( $type, $bit_max, $logo_data, $svg );
764 $type = Maasha::Seq::seq_guess_type( $entries->[ 0 ]->[ 1 ] );
766 if ( $type =~ /^p/i ) {
772 $logo_data = Maasha::Seq::seqlogo_calc( $bit_max, $entries );
774 $svg = Maasha::Plot::svg_init();
776 svg_draw_logo( $svg, $logo_data, $bit_max, $type );
777 svg_draw_logo_scale( $svg, $bit_max );
785 # Martin A. Hansen, October 2005.
787 # inititalizes SVG object, which is returned.
793 'font-weight' => 'normal',
794 'font-family' => 'Courier New',
805 # Martin A. Hansen, January 2007.
807 # Renders a sequence logo in SVG using a
808 # given data structure with logo details.
810 my ( $svg, # SVG object,
811 $logo_data, # data structure
812 $bit_max, # maximum bit height
813 $type, # sequence type
814 $nocolor, # render black and white - OPTIONAL
817 my ( $pos, $elem, $char, $char_height_bit, $char_height_px, $block, $x, $y, $scale_factor, $color );
821 foreach $pos ( @{ $logo_data } )
825 foreach $elem ( @{ $pos } )
827 ( $char, $char_height_bit ) = @{ $elem };
829 $char_height_px = $char_height_bit * ( 30 / $bit_max );
831 $block = $svg->group(
832 transform => "translate($x,$y)",
835 $scale_factor = $char_height_px / 7;
839 } elsif ( $type eq "dna" or $type eq "rna" ) {
840 $color = Maasha::Seq::color_nuc( $char );
842 $color = Maasha::Seq::color_pep( $char );
846 transform => "scale(1,$scale_factor)",
850 'font-weight' => 'bold',
851 fill => Maasha::Seq::color_palette( $color ),
855 $y -= $char_height_px;
863 sub svg_draw_logo_scale
865 # Martin A. Hansen, January 2007.
867 # draws the bit scale for the sequence logo
869 my ( $svg, # SVG object,
870 $bit_max, # maximum bit height
875 $scale = $svg->group(
876 transform => "translate(-10)",
879 'font-size' => '8px',
884 # transform => "translate(0,$logo_y)",
885 transform => "rotate(-90)",
900 for ( $i = 0; $i <= $bit_max; $i++ )
905 y1 => ( 30 / $bit_max ) * $i,
906 y2 => ( 30 / $bit_max ) * $i,
911 y => ( 30 / $bit_max ) * $i + 2,
915 )->cdata( $bit_max - $i );
920 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<