5 Creates a trait/cvterm page with a description of
6 the population on which the trait/cvterm was evaluated,
7 displays the frequency distribution of its phenotypic data
8 and most importantly produces the on-the-fly QTL analysis
9 output for the trait and more....
13 Isaak Y Tecle (iyt2@cornell.edu)
21 my $population_indls_detail_page =
22 CXGN
::Phenome
::PopulationIndlsDetailPage
->new();
24 package CXGN
::Phenome
::PopulationIndlsDetailPage
;
27 use CXGN
::Page
::FormattingHelpers qw
/info_section_html
36 use CXGN
::Phenome
::Population
;
37 use CXGN
::Phenome
::Qtl
;
38 use CXGN
::Phenome
::PopulationDbxref
;
39 use CXGN
::Tools
::WebImageCache
;
41 use CXGN
::People
::PageComment
;
42 use CXGN
::People
::Person
;
43 use CXGN
::Chado
::Publication
;
44 use CXGN
::Chado
::Pubauthor
;
49 use GD
::Graph
::points
;
51 use Statistics
::Descriptive
;
53 use File
::Temp qw
/tempfile tempdir/;
59 use CXGN
::Scrap
::AjaxPage
;
61 use Storable qw
/ store /;
64 use CXGN
::Page
::UserPrefs
;
65 use base qw
/ CXGN::Page::Form::SimpleFormPage CXGN::Phenome::Main/;
70 my $self = $class->SUPER::new
(@_);
71 $self->set_script_name("population_indls.pl");
80 $self->set_dbh( CXGN
::DB
::Connection
->new() );
81 my %args = $self->get_args();
82 my $population_id = $args{population_id
};
83 unless ( !$population_id || $population_id =~ m
/^\d+$/ )
85 $self->get_page->message_page(
86 "No population exists for identifier $population_id");
88 $self->set_object_id($population_id);
90 CXGN
::Phenome
::Population
->new(
91 $self->get_dbh(), $self->get_object_id()
94 $self->set_primary_key("population_id");
95 $self->set_owners( $self->get_object()->get_owners() );
104 my %args = $self->get_args();
106 my $population = $self->get_object();
107 my $population_id = $self->get_object_id();
108 my $type_id = $args{type_id
};
109 my $type = $args{type
};
110 my $pop_name = $population->get_name();
112 qq |<a href
="/phenome/population.pl?population_id=$population_id">$pop_name</a
> |;
114 my $sp_person_id = $population->get_sp_person_id();
115 my $submitter = CXGN
::People
::Person
->new( $self->get_dbh(),
116 $population->get_sp_person_id() );
118 $submitter->get_first_name() . " " . $submitter->get_last_name();
120 qq |<a href
="/solpeople/personal-info.pl?sp_person_id=$sp_person_id">$submitter_name </a
> |;
122 my $login_user = $self->get_user();
123 my $login_user_id = $login_user->get_sp_person_id();
126 $self->get_action() =~ /edit|store/
127 && ( $login_user_id = $submitter
128 || $self->get_user()->get_user_type() eq 'curator' )
131 $form = CXGN
::Page
::Form
::Editable
->new();
135 $form = CXGN
::Page
::Form
::Static
->new();
139 display_name
=> "Name:",
140 field_name
=> "name",
141 contents
=> $pop_link,
145 display_name
=> "Description: ",
146 field_name
=> "description",
147 object
=> $population,
148 getter
=> "get_description",
149 setter
=> "set_description",
155 display_name
=> "Uploaded by: ",
156 field_name
=> "submitter",
157 contents
=> $submitter_link,
159 $form->add_hidden( field_name
=> "population_id",
160 contents
=> $args{population_id
} );
163 field_name
=> "sp_person_id",
164 contents
=> $self->get_user()->get_sp_person_id(),
165 object
=> $population,
166 setter
=> "set_sp_person_id",
169 $form->add_hidden( field_name
=> "action", contents
=> "store" );
171 $self->set_form($form);
173 if ( $self->get_action =~ /view|edit/ )
175 $self->get_form->from_database();
178 elsif ( $self->get_action =~ /store/ )
180 $self->get_form->from_request( $self->get_args() );
190 $self->get_page->jsan_use("jQuery");
191 $self->get_page->jsan_use("thickbox");
193 $self->get_page->add_style( text
=> <<EOS);
194 a.abstract_optional_show {
199 div.abstract_optional_show {
201 border: 1px solid #9F9FC7;
202 margin: 0.2em 1em 0.2em 1em;
203 padding: 0.2em 0.5em 0.2em 1em;
207 my %args = $self->get_args();
208 my $cvterm_id = $args{cvterm_id
};
210 my $dbh = $self->get_dbh();
212 my $population = $self->get_object();
213 my $population_id = $self->get_object_id();
214 my $population_name = $population->get_name();
216 my ( $term_obj, $term_name, $term_id );
218 if ( $population->get_web_uploaded() )
220 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
221 $term_name = $term_obj->get_name();
222 $term_id = $term_obj->get_user_trait_id();
226 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
227 $term_name = $term_obj->get_cvterm_name();
228 $term_id = $term_obj->get_cvterm_id();
231 #used to show certain elements to only the proper users
232 my $login_user = $self->get_user();
233 my $login_user_id = $login_user->get_sp_person_id();
234 my $login_user_type = $login_user->get_user_type();
237 ->header(" SGN: $term_name values in population $population_name");
239 print page_title_html
(
240 "SGN: $term_name values in population $population_name \n");
242 my $population_html = $self->get_edit_link_html() . qq |<a href
="qtl_form.pl">[New QTL Population
]</a><br/>|;
244 #print all editable form fields
245 $population_html .= $self->get_form()->as_table_string();
246 my $population_obj = $self->get_object();
250 "../phenome/population_indls.pl?population_id=$population_id&cvterm_id=$term_id";
251 $args{calling_page
} = $page;
254 my $url_pubmed = qq | http
://www
.ncbi
.nlm
.nih
.gov
/pubmed/|;
256 my @publications = $population->get_population_publications();
258 my $abstract_count = 0;
260 foreach my $pub (@publications)
263 $title, $abstract, $authors, $journal,
264 $pyear, $volume, $issue, $pages,
265 $obsolete, $pub_id, $accession
269 my @dbxref_objs = $pub->get_dbxrefs();
270 my $dbxref_obj = shift(@dbxref_objs);
272 $population_obj->get_population_dbxref($dbxref_obj)->get_obsolete();
274 if ( $obsolete eq 'f' )
276 $pub_id = $pub->get_pub_id();
278 $title = $pub->get_title();
279 $abstract = $pub->get_abstract();
280 $pyear = $pub->get_pyear();
281 $volume = $pub->get_volume();
282 $journal = $pub->get_series_name();
283 $pages = $pub->get_pages();
284 $issue = $pub->get_issue();
286 $accession = $dbxref_obj->get_accession();
288 qq|<a href
="/chado/publication.pl?pub_id=$pub_id" >PMID
:$accession</a
> |;
295 my @pubauthors_ids = $pub->get_pubauthors_ids($pub_id);
297 foreach my $pubauthor_id (@pubauthors_ids)
300 CXGN
::Chado
::Pubauthor
->new( $self->get_dbh,
302 my $last_name = $pubauthor_obj->get_surname();
303 my $first_names = $pubauthor_obj->get_givennames();
304 my @first_names = split( /,/, $first_names );
305 $first_names = shift(@first_names);
306 push @authors, ( "$first_names" . " " . "$last_name" );
307 $authors = join( ", ", @authors );
311 $abstract_view = html_optional_show
(
312 "abstracts$abstract_count",
313 'Show/hide abstract',
314 qq|$abstract <b
> <i
>$authors.</i> $journal. $pyear. $volume($issue). $pages.</b
>|,
315 0, #< do not show by default
316 'abstract_optional_show'
317 , #< don't use the default button-like style
321 qq|<div
><a href
="$url_pubmed$accession" target
="blank">$pub_info</a> $title $abstract_view </div
> |;
325 print info_section_html
( title
=> 'Population Details',
326 contents
=> $population_html, );
328 my $is_public = $population->get_privacy_status();
329 my ( $submitter_obj, $submitter_link ) = $self->submitter();
332 || $login_user_type eq 'curator'
333 || $login_user_id == $population->get_sp_person_id() )
339 my ( $indl_id, $indl_name, $indl_value ) =
340 $population->get_all_indls_cvterm($term_id);
342 my ( $min, $max, $avg, $std, $count ) =
343 $population->get_pop_data_summary($term_id);
345 for ( my $i = 0 ; $i < @
$indl_name ; $i++ )
351 qq | <a href
="/phenome/individual.pl?individual_id=$indl_id->[$i]">$indl_name->[$i]</a
>|,
357 my ( $phenotype_data, $data_view, $data_download );
358 my $all_indls_count = scalar(@
$indl_name);
362 $phenotype_data = columnar_table_html
(
375 $data_view = html_optional_show
(
377 'View/hide phenotype raw data',
378 qq |$phenotype_data|,
379 0, #< show data by default
382 qq { Download population
: <span
><a href
="pop_download.pl?population_id=$population_id"><b
>\
[Phenotype raw data\
]</b></a><a href
="genotype_download.pl?population_id=$population_id"><b
>[Genotype raw data
]</b></a></span
> };
387 $image_pheno, $title_pheno, $image_map_pheno,
390 ( $image_pheno, $title_pheno, $image_map_pheno ) =
391 population_distribution
($population_id);
392 $plot_html .= qq | <table cellpadding
= 5><tr
><td
> |;
393 $plot_html .= $image_pheno . $image_map_pheno;
394 $plot_html .= qq | </td
><td
> |;
395 $plot_html .= $title_pheno . qq | <br
/> |;
398 my @phe_summ = ( [ 'No. of obs units', $all_indls_count ],
402 [ 'Standard deviation', $std ]
406 foreach my $phe_summ ( @phe_summ )
408 push @summ, [ map { $_ } ( $phe_summ->[0], $phe_summ->[1] ) ];
411 my $summ_data = columnar_table_html
(
412 headings
=> [ '', ''],
421 $plot_html .= $summ_data;
422 $plot_html .= qq | </td></tr
></table
> |;
424 my $qtl_image = $self->qtl_plot();
426 my $legend = $self->legend($population);
427 my $qtl_html = qq | <table
><tr
><td width
=70%>$qtl_image</td><td width=30%>$legend</td
></tr></table
> |;
429 print info_section_html
(
431 contents
=> $qtl_html,
434 print info_section_html
(
435 title
=> 'Phenotype Frequency Distribution',
436 contents
=> $plot_html,
439 print info_section_html
(
440 title
=> 'Phenotype Data',
441 contents
=> $data_view . " " . $data_download,
448 "The QTL data for this trait in this population is not public yet.
449 If you would like to know more about this data,
450 please contact the owner of the data: <b>$submitter_link</b>
452 <a href=mailto:sgn-feedback\@sgn.cornell.edu>
453 sgn-feedback\@sgn.cornell.edu</a>.\n";
455 print info_section_html
( title
=> 'QTL(s)',
456 contents
=> $message );
459 print info_section_html
(
460 title
=> 'Literature Annotation',
464 if ($population_name)
466 my $page_comment_obj =
467 CXGN
::People
::PageComment
->new( $self->get_dbh(), "population",
469 $self->get_page()->{request
}->uri()."?".$self->get_page()->{request
}->args()
471 print $page_comment_obj->get_html();
474 $self->get_page()->footer();
479 # override store to check if a locus with the submitted symbol/name already exists in the database
484 my $population = $self->get_object();
485 my $population_id = $self->get_object_id();
486 my %args = $self->get_args();
488 $self->SUPER::store
(0);
493 sub population_distribution
496 my $doc = CXGN
::Scrap
::AjaxPage
->new();
498 my ( $pop_id, $cvterm_id ) =
499 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
501 my $dbh = CXGN
::DB
::Connection
->new();
503 my ( $term_obj, $term_name, $term_id );
505 my $pop = CXGN
::Phenome
::Population
->new( $dbh, $pop_id );
507 if ( $pop->get_web_uploaded() )
509 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
510 $term_name = $term_obj->get_name();
511 $term_id = $term_obj->get_user_trait_id();
515 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
516 $term_name = $term_obj->get_cvterm_name();
517 $term_id = $term_obj->get_cvterm_id();
520 my $vh = SGN
::Context
->new();
521 my $basepath = $vh->get_conf("basepath");
522 my $tempfile_dir = $vh->get_conf("tempfiles_subdir");
524 my $cache = CXGN
::Tools
::WebImageCache
->new();
525 $cache->set_basedir($basepath);
526 $cache->set_temp_dir( $tempfile_dir . "/temp_images" );
527 $cache->set_expiration_time(259200);
528 $cache->set_key( "popluation_distribution" . $pop_id . $term_id );
529 $cache->set_map_name("popmap$pop_id$term_id");
532 my ( $variance, $std, $mean );
533 my ( @value, @indl_id, @indl_name );
535 $cache->set_force(0);
536 if ( !$cache->is_valid() )
538 my $pop_obj = CXGN
::Phenome
::Population
->new( $dbh, $pop_id );
539 $pop_name = $pop_obj->get_name();
540 my ( $indl_id, $indl_name, $value ) = $pop_obj->plot_cvterm($term_id);
541 my @indl_id = @
{$indl_id};
542 my @indl_name = @
{$indl_name};
545 my $round = Math
::Round
::Var
->new(0.001);
547 my $stat = Statistics
::Descriptive
::Full
->new();
549 $stat->add_data(@value);
551 my $stat_para = Statistics
::Descriptive
::Sparse
->new();
552 $stat_para->add_data(@value);
553 $std = $stat_para->standard_deviation();
554 $mean = $stat_para->mean();
556 my %f = $stat->frequency_distribution(10);
558 my ( @keys, @counts );
560 for ( sort { $a <=> $b } keys %f )
562 my $key = $round->round($_);
564 push @counts, $f{$_};
567 my $min = $stat->min();
573 my @keys_range = $min . '-' . $keys[0];
576 my $previous_k = $keys[0];
577 my $keys_shifted = shift(@keys);
578 foreach my $k (@keys)
580 $range = $previous_k . '-' . $k;
581 push @keys_range, $range;
585 my $max = $counts[0];
586 foreach my $i ( @counts[ 1 .. $#counts ] )
588 if ( $i > $max ) { $max = $i; }
590 $max = int( $max + ( $max * 0.1 ) );
594 my ( $lower, $upper );
596 foreach my $k (@keys_range)
598 ( $lower, $upper ) = split( /-/, $k );
600 qq | /phenome/indls_range_cvterm
.pl?cvterm_id
=$term_id&
;lower
=$lower&
;upper
=$upper&
;population_id
=$pop_id |;
601 push @c_html, $c_html;
605 my @bar_clr = ("orange");
606 my @data = ( [@keys_range], [@counts] );
607 my $graph = new GD
::Graph
::bars
();
609 $graph->set_title_font('gdTinyFont');
612 x_label
=> "Ranges for $term_name",
613 y_label
=> "Frequency",
623 x_labels_vertical
=> 1,
629 $cache->set_image_data( $graph->plot( \
@data )->png );
631 my $map = new GD
::Graph
::Map
(
633 hrefs
=> [ \
@c_html ],
635 mapName
=> "popmap$pop_id$term_id",
636 info
=> "%x: %y lines",
638 $cache->set_image_map_data(
639 $map->imagemap( "popimage$pop_id$term_id.png", \
@data ) );
643 my $image_map = $cache->get_image_map_data();
644 my $image = $cache->get_image_tag();
646 qq | Frequency distribution of experimental lines evaluated
for $term_name. Bars represent the number of experimental lines with
$term_name values greater than the lower limit but less
or equal to the upper limit of the range
. |;
648 return $image, $title, $image_map;
655 my $doc = CXGN
::Scrap
::AjaxPage
->new();
657 my ( $pop_id, $cvterm_id ) =
658 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
660 my $dbh = $self->get_dbh();
662 my $population = $self->get_object();
663 my $pop_name = $population->get_name();
664 my $mapversion = $population->mapversion_id();
665 my @linkage_groups = $population->linkage_groups();
668 my ( $term_obj, $term_name, $term_id );
670 if ( $population->get_web_uploaded() )
672 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
673 $term_name = $term_obj->get_name();
674 $term_id = $term_obj->get_user_trait_id();
678 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
679 $term_name = $term_obj->get_cvterm_name();
680 $term_id = $term_obj->get_cvterm_id();
683 my $ac = $population->cvterm_acronym($term_name);
685 my $vh = SGN
::Context
->new();
686 my $basepath = $vh->get_conf("basepath");
687 my $tempfile_dir = $vh->get_conf("tempfiles_subdir");
689 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
690 $self->cache_temp_path();
691 my $cache_tempimages = Cache
::File
->new( cache_root
=> $tempimages_path );
692 $cache_tempimages->purge();
694 my ( @marker, @chr, @pos, @lod );
695 my ( @chr_qtl, @left, @right, @peak );
696 my ( $qtl_image, $image, $image_t, $image_url, $image_html, $image_t_url,
697 $thickbox, $title, $l_m, $p_m, $r_m );
699 my $round1 = Math
::Round
::Var
->new(0.1);
700 my $round2 = Math
::Round
::Var
->new(1);
702 $qtl_image = $self->qtl_images_exist();
703 my $permu_data = $self->permu_values_exist();
705 unless ( $qtl_image && $permu_data )
708 my ( $qtl_summary, $flanking_markers ) = $self->run_r();
710 open QTLSUMMARY
, "<$qtl_summary" or die "can't open $qtl_summary: $!\n";
712 my $header = <QTLSUMMARY
>;
713 while ( my $row = <QTLSUMMARY
> )
715 my ( $marker, $chr, $pos, $lod ) = split( /\t/, $row );
716 push @marker, $marker;
718 $pos = $round2->round($pos);
720 $lod = $round1->round($lod);
724 my @o_lod = sort(@lod);
725 my $max = $o_lod[-1];
730 open MARKERS
, "<$flanking_markers"
731 or die "can't open $flanking_markers: !$\n";
734 while ( my $row = <MARKERS
> )
738 my ($trash, $chr_qtl, $left, $peak, $right, $peakmarker ) = split( /\t/, $row );
739 push @chr_qtl, $chr_qtl;
742 push @peak, $peakmarker;
746 my (@h_markers, @chromosomes, @lk_groups);
750 @lk_groups = @linkage_groups;
751 @lk_groups = sort ( { $a <=> $b } @lk_groups );
752 for ( my $i = 0 ; $i < @left ; $i++ )
754 my $lg = shift(@lk_groups);
755 my $key_h_marker = "$ac" . "_pop_" . "$pop_id" . "_chr_" . $lg;
756 $h_marker = $cache_tempimages->get($key_h_marker);
761 push @chromosomes, $lg;
765 s/\s//g for $l_m, $r_m, $p_m;
768 $population->get_marker_position( $mapversion, $l_m );
770 $population->get_marker_position( $mapversion, $r_m );
774 my $permu_threshold_ref = $self->permu_values();
775 my %permu_threshold = %$permu_threshold_ref;
777 foreach my $key ( keys %permu_threshold )
779 if ( $key =~ m/^\d./ )
785 my $lod1 = $permu_threshold{ $p_keys[0] };
787 qq |/phenome/qtl
.pl?population_id
=$pop_id&
;term_id
=$term_id&
;chr=$lg&
;l_marker
=$l_m&
;p_marker
=$p_m&
;r_marker
=$r_m&
;lod
=$lod1|;
790 $cache_tempimages->set( $key_h_marker, $h_marker, '30 days' );
793 push @h_markers, $h_marker;
799 $chr_chr, $image, $image_t,
800 $thickbox, $max_chr, $chr_chr_e, $marker_chr_e,
801 $pos_chr_e, $lod_chr_e
803 my $chrs = ( scalar(@chromosomes) ) + 1;
805 for ( my $i = 1 ; $i < $chrs ; $i++ )
807 my ( @marker_chr, @chr_chr, @pos_chr, @lod_chr, @data, @m_html ) =
809 my ( $marker_chr, $pos_chr, $lod_chr, $max_chr );
811 $h_marker = shift(@h_markers);
813 if ( ( $i == $old_chr_chr ) && ( $i != 12 ) )
815 push @marker_chr, $marker_chr_e;
816 push @chr_chr, $chr_chr_e;
817 $pos_chr_e = $round2->round($pos_chr_e);
818 push @pos_chr, $pos_chr_e;
819 $lod_chr = $round1->round($lod_chr_e);
820 push @lod_chr, $lod_chr_e;
823 my $cache_qtl_plot = CXGN
::Tools
::WebImageCache
->new();
824 $cache_qtl_plot->set_basedir($basepath);
825 $cache_qtl_plot->set_temp_dir( $tempfile_dir . "/temp_images" );
826 $cache_qtl_plot->set_expiration_time(259200);
827 $cache_qtl_plot->set_key(
828 "qtlplot" . $i . "small" . $pop_id . $term_id );
829 $cache_qtl_plot->set_force(0);
831 if ( !$cache_qtl_plot->is_valid() )
834 for ( my $j = 0 ; $j < @marker ; $j++ )
839 if ( $i == $chr_chr )
841 $marker_chr = $marker[$j];
846 push @marker_chr, $marker_chr;
847 push @chr_chr, $chr_chr;
848 $pos_chr = $round2->round($pos_chr);
849 push @pos_chr, $pos_chr;
850 $lod_chr = $round1->round($lod_chr);
851 push @lod_chr, $lod_chr;
853 ( $chr_chr_e, $marker_chr_e, $pos_chr_e, $lod_chr_e ) =
857 elsif ( $i != $chr_chr )
860 $chr_chr_e = $chr[$j];
861 $marker_chr_e = $marker[$j];
862 $pos_chr_e = $pos[$j];
863 $lod_chr_e = $lod[$j];
868 @data = ( [ (@pos_chr) ], [@lod_chr] );
869 my $graph = new GD
::Graph
::lines
( 110, 110 );
870 $graph->set_title_font('gdTinyFont');
873 x_label
=> "Chr $i (cM)",
882 x_labels_vertical
=> 1,
886 $cache_qtl_plot->set_image_data( $graph->plot( \
@data )->png );
890 $image = $cache_qtl_plot->get_image_tag();
891 $image_url = $cache_qtl_plot->get_image_url();
895 my $cache_qtl_plot_t = CXGN
::Tools
::WebImageCache
->new();
896 $cache_qtl_plot_t->set_basedir($basepath);
897 $cache_qtl_plot_t->set_temp_dir( $tempfile_dir . "/temp_images" );
898 $cache_qtl_plot_t->set_expiration_time(259200);
899 $cache_qtl_plot_t->set_key(
900 "qtlplot_" . $i . "_thickbox_" . $pop_id . $term_id );
901 $cache_qtl_plot_t->set_force(0);
903 if ( !$cache_qtl_plot_t->is_valid() )
905 my @o_lod_chr = sort { $a <=> $b } @lod_chr;
906 $max_chr = pop(@o_lod_chr);
907 $max_chr = $max_chr + (0.5);
909 my $graph_t = new GD
::Graph
::lines
( 420, 420 );
910 $graph_t->set_title_font('gdTinyFont');
913 x_label
=> "Chromosome $i (cM)",
915 y_max_value
=> $max_chr,
922 x_labels_vertical
=> 1,
926 $cache_qtl_plot_t->set_image_data(
927 $graph_t->plot( \
@data )->png );
931 $image_t = $cache_qtl_plot_t->get_image_tag();
932 $image_t_url = $cache_qtl_plot_t->get_image_url();
935 qq | <a href
="$image_t_url" title
="<a href=$h_marker&qtl=$image_t_url><font color=#f87431><b>>>>Go to the QTL page>>>> </b></font></a>" class="thickbox" rel
="gallary-qtl"> <img src
="$image_url" alt
="Chromosome $i $image_t_url $image_url" /> </a
> |;
937 $qtl_image .= $thickbox;
939 $old_chr_chr = $chr_chr;
947 Usage: my $file_in = $self->infile_list();
948 Desc: returns an R input tempfile containing a tempfile
949 holding the cvterm acronym, pop id, a filepath to the phenotype dataset file,
950 a filepath to genotype dataset file, a filepath to the permuation file.
951 Ret: an R input tempfile name (with abosulte path)
963 my $doc = CXGN
::Scrap
::AjaxPage
->new();
965 my ( $pop_id, $cvterm_id ) =
966 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
968 my $dbh = $self->get_dbh();
970 my ( $term_obj, $term_name, $term_id );
971 my $population = $self->get_object();
973 if ( $population->get_web_uploaded() )
975 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
976 $term_name = $term_obj->get_name();
977 $term_id = $term_obj->get_user_trait_id();
981 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
982 $term_name = $term_obj->get_cvterm_name();
983 $term_id = $term_obj->get_cvterm_id();
986 my $ac = $population->cvterm_acronym($term_name);
988 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
989 $self->cache_temp_path();
991 my $prod_permu_file = $self->permu_file();
992 my $gen_dataset_file = $self->genotype_file();
993 my $phe_dataset_file = $self->phenotype_file();
994 my $crosstype_file = $self->crosstype_file();
996 my $input_file_list_temp =
998 TEMPLATE
=> "infile_list_${ac}_$pop_id-XXXXXX",
999 DIR
=> $prod_temp_path,
1002 my $file_in = $input_file_list_temp->filename();
1004 my $file_cvin = File
::Temp
->new(
1005 TEMPLATE
=> 'cv_input-XXXXXX',
1006 DIR
=> $prod_temp_path,
1009 my $file_cv_in = $file_cvin->filename();
1011 open CV
, ">$file_cv_in" or die "can't open $file_cv_in: $!\n";
1015 my $file_in_list = join( "\t",
1016 $file_cv_in, "P$pop_id",
1017 $gen_dataset_file, $phe_dataset_file,
1018 $prod_permu_file, $crosstype_file);
1020 open FI
, ">$file_in" or die "can't open $file_in: $!\n";
1021 print FI
$file_in_list;
1030 Usage: my ($file_out, $qtl_summary, $flanking_markers) = $self->outfile_list();
1031 Desc: returns an R output tempfile containing a tempfile supposed to hold the qtl
1032 mapping output and another tempfile for the qtl flanking markers
1033 and the qtl mapping output and qtl flanking markers files separately
1034 (convenient for reading their data when plotting the qtl)
1035 Ret: R output file names (with abosulte path)
1046 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1048 my ( $pop_id, $cvterm_id ) =
1049 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1051 my $dbh = $self->get_dbh();
1053 my ( $term_obj, $term_name, $term_id );
1054 my $population = $self->get_object();
1056 if ( $population->get_web_uploaded() )
1058 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1059 $term_name = $term_obj->get_name();
1060 $term_id = $term_obj->get_user_trait_id();
1064 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1065 $term_name = $term_obj->get_cvterm_name();
1066 $term_id = $term_obj->get_cvterm_id();
1069 my $ac = $population->cvterm_acronym($term_name);
1071 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1072 $self->cache_temp_path();
1074 my $output_file_list_temp =
1076 TEMPLATE
=> "outfile_list_${ac}_$pop_id-XXXXXX",
1077 DIR
=> $prod_temp_path,
1080 my $file_out = $output_file_list_temp->filename();
1082 my $qtl_temp = File
::Temp
->new(
1083 TEMPLATE
=> "qtl_summary_${ac}_$pop_id-XXXXXX",
1084 DIR
=> $prod_temp_path,
1087 my $qtl_summary = $qtl_temp->filename;
1089 my $marker_temp = File
::Temp
->new(
1090 TEMPLATE
=> "flanking_markers_${ac}_$pop_id-XXXXXX",
1091 DIR
=> $prod_temp_path,
1095 my $flanking_markers = $marker_temp->filename;
1097 my $file_out_list = join(
1102 open FO
, ">$file_out" or die "can't open $file_out: $!\n";
1103 print FO
$file_out_list;
1106 return $file_out, $qtl_summary, $flanking_markers;
1109 =head2 cache_temp_path
1111 Usage: my ($prod_cache_path, $prod_temp_path, $tempimages_path) = $self->cache_temp_path();
1112 Desc: creates the 'r_qtl' dir in the '/data/prod/tmp/' dir;
1113 'cache' and 'tempfiles' in the /data/prod/tmp/r_qtl/,
1114 and 'temp_images' in the /data/local/cxgn/sgn/documents/tempfiles'
1115 Ret: /data/prod/tmp/r_qtl/cache, /data/prod/tmp/r_qtl/tempfiles,
1116 /data/local/cxgn/sgn/documents/tempfiles/temp_images
1125 my $vh = SGN
::Context
->new();
1126 my $basepath = $vh->get_conf("basepath");
1127 my $tempfile_dir = $vh->get_conf("tempfiles_subdir");
1129 my $tempimages_path =
1130 File
::Spec
->catfile( $basepath, $tempfile_dir, "temp_images" );
1132 my $prod_temp_path = $vh->get_conf('r_qtl_temp_path');
1133 mkdir $prod_temp_path;
1134 my $prod_cache_path = "$prod_temp_path/cache";
1135 mkdir $prod_cache_path;
1136 $prod_temp_path = "$prod_temp_path/tempfiles";
1137 mkdir $prod_temp_path;
1139 or die "temp dir '$prod_temp_path' not found, and could not create!";
1140 -r
$prod_temp_path or die "temp dir '$prod_temp_path' not readable!";
1141 -w
$prod_temp_path or die "temp dir '$prod_temp_path' not writable!";
1143 return $prod_cache_path, $prod_temp_path, $tempimages_path;
1147 =head2 genotype_file
1149 Usage: my $gen_file = $self->genotype_file();
1150 Desc: creates the genotype file in the /data/prod/tmp/r_qtl/cache,
1151 if it does not exist yet and caches it for R.
1152 Ret: genotype filename (with abosolute path)
1162 my $pop_id = $self->get_object_id();
1163 my $population = $self->get_object();
1165 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1166 $self->cache_temp_path();
1167 my $file_cache = Cache
::File
->new( cache_root
=> $prod_cache_path );
1168 $file_cache->purge();
1170 my $key_gen = "popid_" . $pop_id . "_genodata";
1171 my $gen_dataset_file = $file_cache->get($key_gen);
1173 unless ($gen_dataset_file)
1175 my $genodata = $population->genotype_dataset();
1176 my $geno_dataset = ${$genodata};
1178 my $filename = "genodata_" . $pop_id . ".csv";
1179 my $file = "$prod_cache_path/$filename";
1181 open OUT
, ">$file" or die "can't open $file: !$\n";
1182 print OUT
$geno_dataset;
1185 $file_cache->set( $key_gen, $file, '30 days' );
1186 $gen_dataset_file = $file_cache->get($key_gen);
1189 return $gen_dataset_file;
1193 =head2 phenotype_file
1195 Usage: my $gen_file = $self->phenotype_file();
1196 Desc: creates the phenotype file in the /data/prod/tmp/r_qtl/cache,
1197 if it does not exist yet and caches it for R.
1198 Ret: phenotype filename (with abosolute path)
1208 my $pop_id = $self->get_object_id();
1209 my $population = $self->get_object();
1211 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1212 $self->cache_temp_path();
1213 my $file_cache = Cache
::File
->new( cache_root
=> $prod_cache_path );
1215 my $key_phe = "popid_" . $pop_id . "_phenodata";
1216 my $phe_dataset_file = $file_cache->get($key_phe);
1218 unless ($phe_dataset_file)
1220 my $phenodata = $population->phenotype_dataset();
1221 my $pheno_dataset = ${$phenodata};
1222 my $filename = "phenodata_" . $pop_id . ".csv";
1224 my $file = "$prod_cache_path/$filename";
1226 open OUT
, ">$file" or die "can't open $file: !$\n";
1227 print OUT
$pheno_dataset;
1230 $file_cache->set( $key_phe, $file, '30 days' );
1231 $phe_dataset_file = $file_cache->get($key_phe);
1234 return $phe_dataset_file;
1238 =head2 crosstype_file
1240 Usage: my $gen_file = $self->crosstype_file();
1241 Desc: creates the crosstype file in the /data/prod/tmp/r_qtl/temp,
1243 Ret: crossotype filename (with abosolute path)
1253 my $pop_id = $self->get_object_id();
1254 my $population = $self->get_object();
1256 my $cross_type = 'bc' if ($population->get_cross_type_id() == 2);
1257 $cross_type = 'f2' if ($population->get_cross_type_id() == 1);
1259 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1260 $self->cache_temp_path();
1262 my $cross_temp = File
::Temp
->new(
1263 TEMPLATE
=> "cross_type_${pop_id}-XXXXXX",
1264 DIR
=> $prod_temp_path,
1269 my $cross_file = $cross_temp->filename;
1271 open CF
, ">$cross_file" or die "can't open $cross_file: $!\n";
1272 print CF
$cross_type;
1283 Usage: my ($qtl_summary, $flanking_markers) = $self->run_r();
1284 Desc: run R in the cluster; copies permutation file from the /data/prod..
1285 to the tempimages dir; returns the R output files (with abosulate filepath) with qtl mapping data
1286 and flanking markers
1298 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1299 $self->cache_temp_path();
1300 my $prod_permu_file = $self->permu_file();
1301 my $file_in = $self->infile_list();
1302 my ( $file_out, $qtl_summary, $flanking_markers ) = $self->outfile_list();
1303 my $stat_file = $self->stat_files();
1305 CXGN
::Tools
::Run
->temp_base($prod_temp_path);
1307 my ( $r_in_temp, $r_out_temp ) =
1309 my ( undef, $filename ) =
1311 File
::Spec
->catfile(
1312 CXGN
::Tools
::Run
->temp_base(),
1313 "population_indls.pl-$_-XXXXXX",
1319 #copy our R commands into a cluster-accessible tempfile
1320 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1323 my $r_cmd_file = $doc->path_to('/cgi-bin/phenome/cvterm_qtl.r');
1324 copy
( $r_cmd_file, $r_in_temp )
1325 or die "could not copy '$r_cmd_file' to '$r_in_temp'";
1328 # now run the R job on the cluster
1329 my $r_process = CXGN
::Tools
::Run
->run_cluster(
1330 'R', 'CMD', 'BATCH',
1332 "--args $file_in $file_out $stat_file",
1336 working_dir
=> $prod_temp_path,
1338 # don't block and wait if the cluster looks full
1339 max_cluster_jobs
=> 1_000_000_000
,
1343 sleep 1 while $r_process->alive; #< wait for R to finish
1344 #unlink( $r_in_temp, $r_out_temp );
1346 copy
( $prod_permu_file, $tempimages_path )
1347 or die "could not copy '$prod_permu_file' to '$tempimages_path'";
1349 return $qtl_summary, $flanking_markers;
1355 Usage: my $permu_file = $self->permu_file();
1356 Desc: creates the permutation file in the /data/prod/tmp/r_qtl/cache,
1357 if it does not exist yet and caches it for R.
1358 Ret: permutation filename (with abosolute path)
1368 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1369 my ( $pop_id, $cvterm_id ) =
1370 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1372 my $dbh = CXGN
::DB
::Connection
->new();
1374 my $population = CXGN
::Phenome
::Population
->new( $dbh, $pop_id );
1375 my $pop_name = $population->get_name();
1377 my ( $term_obj, $term_name, $term_id );
1379 if ( $population->get_web_uploaded() )
1381 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1382 $term_name = $term_obj->get_name();
1383 $term_id = $term_obj->get_user_trait_id();
1387 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1388 $term_name = $term_obj->get_cvterm_name();
1389 $term_id = $term_obj->get_cvterm_id();
1392 my $ac = $population->cvterm_acronym($term_name);
1394 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1395 $self->cache_temp_path();
1397 my $file_cache = Cache
::File
->new( cache_root
=> $prod_cache_path );
1399 my $key_permu = "$ac" . "_" . $pop_id . "_permu";
1400 my $filename = "permu_" . $ac . "_" . $pop_id;
1402 my $permu_file = $file_cache->get($key_permu);
1404 unless ($permu_file)
1409 my $permu_file = "$prod_cache_path/$filename";
1411 open OUT
, ">$permu_file" or die "can't open $permu_file: !$\n";
1415 $file_cache->set( $key_permu, $permu_file, '30 days' );
1416 $permu_file = $file_cache->get($key_permu);
1425 Usage: my $permu_values = $self->permu_values();
1426 Desc: reads the permutation output from R,
1427 creates a hash with the probality level as key and LOD threshold as the value,
1429 Ret: a hash ref of the permutation values
1439 my $prod_permu_file = $self->permu_file();
1441 my %permu_threshold = {};
1443 my $permu_file = fileparse
($prod_permu_file);
1444 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1445 $self->cache_temp_path();
1446 $permu_file = File
::Spec
->catfile( $tempimages_path, $permu_file );
1448 my $round1 = Math
::Round
::Var
->new(0.1);
1450 open PERMUTATION
, "<$permu_file"
1451 or die "can't open $permu_file: !$\n";
1453 my $header = <PERMUTATION
>;
1455 while ( my $row = <PERMUTATION
> )
1457 my ( $significance, $lod_threshold ) = split( /\t/, $row );
1458 $lod_threshold = $round1->round($lod_threshold);
1459 $permu_threshold{$significance} = $lod_threshold;
1464 return \
%permu_threshold;
1468 =head2 permu_values_exist
1470 Usage: my $permu_value = $self->permu_values_exist();
1471 Desc: checks if there is permutation value in the permutation file.
1472 Ret: undef or some value
1479 sub permu_values_exist
1482 my $prod_permu_file = $self->permu_file();
1484 my ( $size, $permu_file, $permu_data, $tempimages_path, $prod_cache_path,
1487 if ($prod_permu_file)
1490 $permu_file = fileparse
($prod_permu_file);
1491 ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1492 $self->cache_temp_path();
1498 $permu_file = File
::Spec
->catfile( $tempimages_path, $permu_file );
1501 if ( -e
$permu_file )
1504 open P
, "<$permu_file" or die "can't open $permu_file: !$\n";
1506 while ( $permu_data = <P
> )
1508 last if ($permu_data);
1510 # #just checking if there is data in there
1527 =head2 qtl_images_exist
1529 Usage: my $qtl_images_ref = $self->qtl_images_exist();
1530 Desc: checks and returns a scalar ref if the qtl plots (with thickbox and their links to the comparative viewer) exist in the cache
1531 Ret: scalar ref to the images or undef
1538 sub qtl_images_exist
1541 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1543 my ( $pop_id, $cvterm_id ) =
1544 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1546 my $dbh = $self->get_dbh();
1548 my $population = $self->get_object();
1549 my $pop_name = $population->get_name();
1551 my @linkage_groups = $population->linkage_groups();
1552 @linkage_groups = sort ( { $a <=> $b } @linkage_groups );
1554 my ( $term_obj, $term_name, $term_id );
1556 if ( $population->get_web_uploaded() )
1558 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1559 $term_name = $term_obj->get_name();
1560 $term_id = $term_obj->get_user_trait_id();
1564 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1565 $term_name = $term_obj->get_cvterm_name();
1566 $term_id = $term_obj->get_cvterm_id();
1569 my $ac = $population->cvterm_acronym($term_name);
1571 my $vh = SGN
::Context
->new();
1572 my $basepath = $vh->get_conf("basepath");
1573 my $tempfile_dir = $vh->get_conf("tempfiles_subdir");
1575 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1576 $self->cache_temp_path();
1578 my $cache_tempimages = Cache
::File
->new( cache_root
=> $tempimages_path );
1579 $cache_tempimages->purge();
1581 my ( $qtl_image, $image, $image_t, $image_url, $image_html, $image_t_url,
1582 $thickbox, $title );
1585 IMAGES
: foreach my $lg (@linkage_groups)
1587 my $cache_qtl_plot = CXGN
::Tools
::WebImageCache
->new();
1588 $cache_qtl_plot->set_basedir($basepath);
1589 $cache_qtl_plot->set_temp_dir( $tempfile_dir . "/temp_images" );
1591 my $key = "qtlplot" . $lg . "small" . $pop_id . $term_id;
1592 $cache_qtl_plot->set_key($key);
1594 my $key_h_marker = "$ac" . "_pop_" . "$pop_id" . "_chr_" . $lg;
1595 my $h_marker = $cache_tempimages->get($key_h_marker);
1597 if ( $cache_qtl_plot->is_valid )
1599 $image = $cache_qtl_plot->get_image_tag();
1600 $image_url = $cache_qtl_plot->get_image_url();
1603 my $cache_qtl_plot_t = CXGN
::Tools
::WebImageCache
->new();
1604 $cache_qtl_plot_t->set_basedir($basepath);
1605 $cache_qtl_plot_t->set_temp_dir( $tempfile_dir . "/temp_images" );
1607 my $key_t = "qtlplot_" . $lg . "_thickbox_" . $pop_id . $term_id;
1608 $cache_qtl_plot_t->set_key($key_t);
1610 if ( $cache_qtl_plot_t->is_valid )
1613 $image_t = $cache_qtl_plot_t->get_image_tag();
1614 $image_t_url = $cache_qtl_plot_t->get_image_url();
1617 qq | <a href
="$image_t_url" title
= "<a href=$h_marker&qtl=$image_t_url><font color=#f87431><b>>>>Go to the QTL page>>>> </b></font></a>" class="thickbox" rel
="gallary-qtl"> <img src
="$image_url" alt
="Chromosome $lg $image_t_url $image_url" /> </a
> |;
1619 $qtl_image .= $thickbox;
1637 # =head2 user_stat_file
1648 # sub user_stat_file {
1650 # my $pop = $self->get_object();
1651 # my $pop_id = $self->get_object_id();
1652 # my $sp_person_id = $pop->get_sp_person_id();
1653 # my $qtl = CXGN::Phenome::Qtl->new($sp_person_id);
1654 # #$qtl->set_population_id($pop_id);
1656 # my ($qtl_dir, $user_dir) = $qtl->get_user_qtl_dir();
1658 # my $stat_file = "$user_dir/user_stat_pop_$pop_id.txt";
1659 # print STDERR "stat_file: $stat_file";
1661 # if (-e $stat_file) {
1662 # return $stat_file;
1663 # } else {return 0;}
1669 Usage: my $stat_param_files = $self->stat_files();
1670 Desc: creates a master file containing individual files
1671 in /data/prod/tmp/r_qtl for each statistical parameter
1672 which are feed to R.
1673 Ret: an absolute path to the statistical parameter's
1674 master file (and individual files)
1684 my $pop_id = $self->get_object_id();
1685 my $pop = $self->get_object();
1686 my $sp_person_id = $pop->get_sp_person_id();
1687 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1688 my $c = SGN
::Context
->new();
1689 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1691 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1692 $self->cache_temp_path();
1694 open F
, "<$user_stat_file" or die "can't open file: !$\n";
1700 my ( $parameter, $value ) = split( /\t/, $_ );
1702 my $stat_temp = File
::Temp
->new(
1703 TEMPLATE
=> "${parameter}_$pop_id-XXXXXX",
1704 DIR
=> $prod_temp_path,
1707 my $stat_file = $stat_temp->filename;
1709 open SF
, ">$stat_file" or die "can't open file: !$\n";
1713 $stat_files .= $stat_file . "\t";
1719 my $stat_param_files =
1720 $prod_temp_path . "/" . "stat_temp_files_pop_id_${pop_id}";
1722 open STAT
, ">$stat_param_files" or die "can't open file: !$\n";
1723 print STAT
$stat_files;
1726 return $stat_param_files;
1730 =head2 stat_param_hash
1732 Usage: my %stat_param = $self->stat_param_hash();
1733 Desc: creates a hash (with the statistical parameters (as key) and
1734 their corresponding values) out of a tab delimited
1735 statistical parameters file.
1736 Ret: a hash statistics file
1746 my $pop_id = $self->get_object_id();
1747 my $pop = $self->get_object();
1748 my $sp_person_id = $pop->get_sp_person_id();
1749 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1750 my $c = SGN
::Context
->new();
1751 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1753 open F
, "<$user_stat_file" or die "can't open file: !$\n";
1759 my ( $parameter, $value ) = split( /\t/, $_ );
1761 $stat_param{$parameter} = $value;
1765 return \
%stat_param;
1771 my $population = $self->get_object();
1772 my $sp_person_id = $population->get_sp_person_id();
1773 my $submitter = CXGN
::People
::Person
->new( $self->get_dbh(),
1774 $population->get_sp_person_id() );
1775 my $submitter_name =
1776 $submitter->get_first_name() . " " . $submitter->get_last_name();
1777 my $submitter_link =
1778 qq |<a href
="/solpeople/personal-info.pl?sp_person_id=$sp_person_id">$submitter_name</a
> |;
1780 return $submitter, $submitter_link;
1784 #move to qtl or population object
1788 my $sp_person_id = $pop->get_sp_person_id();
1789 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1790 my $stat_file = $qtl->get_stat_file($c, $pop->get_population_id());
1794 open my $sf, "<", $stat_file or die "$! reading $stat_file\n";
1795 while (my $row = <$sf>)
1798 my ( $parameter, $value ) = split( /\t/, $row );
1799 if ($parameter =~/qtl_method/) {$parameter = 'Mapping method';}
1800 if ($parameter =~/qtl_model/) {$parameter = 'Mapping model';}
1801 if ($parameter =~/prob_method/) {$parameter = 'QTL genotype probability method';}
1802 if ($parameter =~/step_size/) {$parameter = 'Genome scan size (cM)';}
1803 if ($parameter =~/permu_level/) {$parameter = 'Permutation significance level';}
1804 if ($parameter =~/permu_test/) {$parameter = 'No. of permutations';}
1805 if ($parameter =~/prob_level/) {$parameter = 'QTL genotype signifance level';}
1806 if ($parameter =~/stat_no_draws/) {$parameter = 'No. of imputations';}
1808 if ($value eq 'zero' || $value eq 'Marker Regression') {$ci = 'none';}
1810 unless (($parameter =~/No. of imputations/ && !$value ) ||
1811 ($parameter =~/QTL genotype probability/ && !$value ) ||
1812 ($parameter =~/Permutation significance level/ && !$value)
1816 push @stat, [map{$_} ($parameter, $value)];
1823 foreach my $st (@stat) {
1824 foreach my $i (@
$st) {
1826 foreach my $s (@stat) {
1827 foreach my $j (@
$s) {
1828 $j =~ s/Maximum Likelihood/Marker Regression/;
1837 my $permu_threshold_ref = $self->permu_values();
1838 my %permu_threshold = %$permu_threshold_ref;
1842 foreach my $key ( keys %permu_threshold )
1844 if ( $key =~ m/^\d./ )
1850 my $lod1 = $permu_threshold{ $keys[0] };
1851 # my $lod2 = $permu_threshold{ $keys[1] };
1855 $lod1 = qq |<i
>Not calculated
</i
>|;
1860 map {$_} ('LOD threshold', $lod1)
1867 map {$_} ('Confidence interval', 'Based on 95% Bayesian Credible Interval')
1872 map {$_} ('QTL software', "<a href=http://www.rqtl.org>R/QTL</a>")
1874 my $legend_data = columnar_table_html
(
1889 return $legend_data;