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 = $population->genotype_file($c);
993 my $phe_dataset_file = $population->phenotype_file($c);
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 $basepath = $c->get_conf("basepath");
1126 my $tempfile_dir = $c->get_conf("tempfiles_subdir");
1127 my $prod_temp_path = $c->get_conf('r_qtl_temp_path');
1129 mkdir $prod_temp_path;
1130 my $prod_cache_path = "$prod_temp_path/cache";
1131 mkdir $prod_cache_path;
1132 $prod_temp_path = "$prod_temp_path/tempfiles";
1133 mkdir $prod_temp_path;
1135 or die "temp dir '$prod_temp_path' not found, and could not create!";
1136 -r
$prod_temp_path or die "temp dir '$prod_temp_path' not readable!";
1137 -w
$prod_temp_path or die "temp dir '$prod_temp_path' not writable!";
1139 my $tempimages_path =
1140 File
::Spec
->catfile( $basepath, $tempfile_dir, "temp_images" );
1142 return $prod_cache_path, $prod_temp_path, $tempimages_path;
1148 =head2 crosstype_file
1150 Usage: my $cross_file = $self->crosstype_file();
1151 Desc: creates the crosstype file in the /data/prod/tmp/r_qtl/temp,
1153 Ret: crosstype filename (with absolute path)
1163 my $pop_id = $self->get_object_id();
1164 my $population = $self->get_object();
1166 my $cross_type = 'bc' if ($population->get_cross_type_id() == 2);
1167 $cross_type = 'f2' if ($population->get_cross_type_id() == 1);
1169 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1170 $self->cache_temp_path();
1172 my $cross_temp = File
::Temp
->new(
1173 TEMPLATE
=> "cross_type_${pop_id}-XXXXXX",
1174 DIR
=> $prod_temp_path,
1179 my $cross_file = $cross_temp->filename;
1181 open CF
, ">$cross_file" or die "can't open $cross_file: $!\n";
1182 print CF
$cross_type;
1193 Usage: my ($qtl_summary, $flanking_markers) = $self->run_r();
1194 Desc: run R in the cluster; copies permutation file from the /data/prod..
1195 to the tempimages dir; returns the R output files (with abosulate filepath) with qtl mapping data
1196 and flanking markers
1208 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1209 $self->cache_temp_path();
1210 my $prod_permu_file = $self->permu_file();
1211 my $file_in = $self->infile_list();
1212 my ( $file_out, $qtl_summary, $flanking_markers ) = $self->outfile_list();
1213 my $stat_file = $self->stat_files();
1215 CXGN
::Tools
::Run
->temp_base($prod_temp_path);
1217 my ( $r_in_temp, $r_out_temp ) =
1219 my ( undef, $filename ) =
1221 File
::Spec
->catfile(
1222 CXGN
::Tools
::Run
->temp_base(),
1223 "population_indls.pl-$_-XXXXXX",
1229 #copy our R commands into a cluster-accessible tempfile
1230 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1233 my $r_cmd_file = $doc->path_to('/cgi-bin/phenome/cvterm_qtl.r');
1234 copy
( $r_cmd_file, $r_in_temp )
1235 or die "could not copy '$r_cmd_file' to '$r_in_temp'";
1238 # now run the R job on the cluster
1239 my $r_process = CXGN
::Tools
::Run
->run_cluster(
1240 'R', 'CMD', 'BATCH',
1242 "--args $file_in $file_out $stat_file",
1246 working_dir
=> $prod_temp_path,
1248 # don't block and wait if the cluster looks full
1249 max_cluster_jobs
=> 1_000_000_000
,
1253 sleep 1 while $r_process->alive; #< wait for R to finish
1254 #unlink( $r_in_temp, $r_out_temp );
1256 copy
( $prod_permu_file, $tempimages_path )
1257 or die "could not copy '$prod_permu_file' to '$tempimages_path'";
1259 return $qtl_summary, $flanking_markers;
1265 Usage: my $permu_file = $self->permu_file();
1266 Desc: creates the permutation file in the /data/prod/tmp/r_qtl/cache,
1267 if it does not exist yet and caches it for R.
1268 Ret: permutation filename (with abosolute path)
1278 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1279 my ( $pop_id, $cvterm_id ) =
1280 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1282 my $dbh = CXGN
::DB
::Connection
->new();
1284 my $population = CXGN
::Phenome
::Population
->new( $dbh, $pop_id );
1285 my $pop_name = $population->get_name();
1287 my ( $term_obj, $term_name, $term_id );
1289 if ( $population->get_web_uploaded() )
1291 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1292 $term_name = $term_obj->get_name();
1293 $term_id = $term_obj->get_user_trait_id();
1297 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1298 $term_name = $term_obj->get_cvterm_name();
1299 $term_id = $term_obj->get_cvterm_id();
1302 my $ac = $population->cvterm_acronym($term_name);
1304 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1305 $self->cache_temp_path();
1307 my $file_cache = Cache
::File
->new( cache_root
=> $prod_cache_path );
1309 my $key_permu = "$ac" . "_" . $pop_id . "_permu";
1310 my $filename = "permu_" . $ac . "_" . $pop_id;
1312 my $permu_file = $file_cache->get($key_permu);
1314 unless ($permu_file)
1319 my $permu_file = "$prod_cache_path/$filename";
1321 open OUT
, ">$permu_file" or die "can't open $permu_file: !$\n";
1325 $file_cache->set( $key_permu, $permu_file, '30 days' );
1326 $permu_file = $file_cache->get($key_permu);
1335 Usage: my $permu_values = $self->permu_values();
1336 Desc: reads the permutation output from R,
1337 creates a hash with the probality level as key and LOD threshold as the value,
1339 Ret: a hash ref of the permutation values
1349 my $prod_permu_file = $self->permu_file();
1351 my %permu_threshold = {};
1353 my $permu_file = fileparse
($prod_permu_file);
1354 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1355 $self->cache_temp_path();
1356 $permu_file = File
::Spec
->catfile( $tempimages_path, $permu_file );
1358 my $round1 = Math
::Round
::Var
->new(0.1);
1360 open PERMUTATION
, "<$permu_file"
1361 or die "can't open $permu_file: !$\n";
1363 my $header = <PERMUTATION
>;
1365 while ( my $row = <PERMUTATION
> )
1367 my ( $significance, $lod_threshold ) = split( /\t/, $row );
1368 $lod_threshold = $round1->round($lod_threshold);
1369 $permu_threshold{$significance} = $lod_threshold;
1374 return \
%permu_threshold;
1378 =head2 permu_values_exist
1380 Usage: my $permu_value = $self->permu_values_exist();
1381 Desc: checks if there is permutation value in the permutation file.
1382 Ret: undef or some value
1389 sub permu_values_exist
1392 my $prod_permu_file = $self->permu_file();
1394 my ( $size, $permu_file, $permu_data, $tempimages_path, $prod_cache_path,
1397 if ($prod_permu_file)
1400 $permu_file = fileparse
($prod_permu_file);
1401 ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1402 $self->cache_temp_path();
1408 $permu_file = File
::Spec
->catfile( $tempimages_path, $permu_file );
1411 if ( -e
$permu_file )
1414 open P
, "<$permu_file" or die "can't open $permu_file: !$\n";
1416 while ( $permu_data = <P
> )
1418 last if ($permu_data);
1420 # #just checking if there is data in there
1437 =head2 qtl_images_exist
1439 Usage: my $qtl_images_ref = $self->qtl_images_exist();
1440 Desc: checks and returns a scalar ref if the qtl plots (with thickbox and their links to the comparative viewer) exist in the cache
1441 Ret: scalar ref to the images or undef
1448 sub qtl_images_exist
1451 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1453 my ( $pop_id, $cvterm_id ) =
1454 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1456 my $dbh = $self->get_dbh();
1458 my $population = $self->get_object();
1459 my $pop_name = $population->get_name();
1461 my @linkage_groups = $population->linkage_groups();
1462 @linkage_groups = sort ( { $a <=> $b } @linkage_groups );
1464 my ( $term_obj, $term_name, $term_id );
1466 if ( $population->get_web_uploaded() )
1468 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1469 $term_name = $term_obj->get_name();
1470 $term_id = $term_obj->get_user_trait_id();
1474 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1475 $term_name = $term_obj->get_cvterm_name();
1476 $term_id = $term_obj->get_cvterm_id();
1479 my $ac = $population->cvterm_acronym($term_name);
1481 my $vh = SGN
::Context
->new();
1482 my $basepath = $vh->get_conf("basepath");
1483 my $tempfile_dir = $vh->get_conf("tempfiles_subdir");
1485 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1486 $self->cache_temp_path();
1488 my $cache_tempimages = Cache
::File
->new( cache_root
=> $tempimages_path );
1489 $cache_tempimages->purge();
1491 my ( $qtl_image, $image, $image_t, $image_url, $image_html, $image_t_url,
1492 $thickbox, $title );
1495 IMAGES
: foreach my $lg (@linkage_groups)
1497 my $cache_qtl_plot = CXGN
::Tools
::WebImageCache
->new();
1498 $cache_qtl_plot->set_basedir($basepath);
1499 $cache_qtl_plot->set_temp_dir( $tempfile_dir . "/temp_images" );
1501 my $key = "qtlplot" . $lg . "small" . $pop_id . $term_id;
1502 $cache_qtl_plot->set_key($key);
1504 my $key_h_marker = "$ac" . "_pop_" . "$pop_id" . "_chr_" . $lg;
1505 my $h_marker = $cache_tempimages->get($key_h_marker);
1507 if ( $cache_qtl_plot->is_valid )
1509 $image = $cache_qtl_plot->get_image_tag();
1510 $image_url = $cache_qtl_plot->get_image_url();
1513 my $cache_qtl_plot_t = CXGN
::Tools
::WebImageCache
->new();
1514 $cache_qtl_plot_t->set_basedir($basepath);
1515 $cache_qtl_plot_t->set_temp_dir( $tempfile_dir . "/temp_images" );
1517 my $key_t = "qtlplot_" . $lg . "_thickbox_" . $pop_id . $term_id;
1518 $cache_qtl_plot_t->set_key($key_t);
1520 if ( $cache_qtl_plot_t->is_valid )
1523 $image_t = $cache_qtl_plot_t->get_image_tag();
1524 $image_t_url = $cache_qtl_plot_t->get_image_url();
1527 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
> |;
1529 $qtl_image .= $thickbox;
1547 # =head2 user_stat_file
1558 # sub user_stat_file {
1560 # my $pop = $self->get_object();
1561 # my $pop_id = $self->get_object_id();
1562 # my $sp_person_id = $pop->get_sp_person_id();
1563 # my $qtl = CXGN::Phenome::Qtl->new($sp_person_id);
1564 # #$qtl->set_population_id($pop_id);
1566 # my ($qtl_dir, $user_dir) = $qtl->get_user_qtl_dir();
1568 # my $stat_file = "$user_dir/user_stat_pop_$pop_id.txt";
1569 # print STDERR "stat_file: $stat_file";
1571 # if (-e $stat_file) {
1572 # return $stat_file;
1573 # } else {return 0;}
1579 Usage: my $stat_param_files = $self->stat_files();
1580 Desc: creates a master file containing individual files
1581 in /data/prod/tmp/r_qtl for each statistical parameter
1582 which are feed to R.
1583 Ret: an absolute path to the statistical parameter's
1584 master file (and individual files)
1594 my $pop_id = $self->get_object_id();
1595 my $pop = $self->get_object();
1596 my $sp_person_id = $pop->get_sp_person_id();
1597 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1598 my $c = SGN
::Context
->new();
1599 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1601 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1602 $self->cache_temp_path();
1604 open F
, "<$user_stat_file" or die "can't open file: !$\n";
1610 my ( $parameter, $value ) = split( /\t/, $_ );
1612 my $stat_temp = File
::Temp
->new(
1613 TEMPLATE
=> "${parameter}_$pop_id-XXXXXX",
1614 DIR
=> $prod_temp_path,
1617 my $stat_file = $stat_temp->filename;
1619 open SF
, ">$stat_file" or die "can't open file: !$\n";
1623 $stat_files .= $stat_file . "\t";
1629 my $stat_param_files =
1630 $prod_temp_path . "/" . "stat_temp_files_pop_id_${pop_id}";
1632 open STAT
, ">$stat_param_files" or die "can't open file: !$\n";
1633 print STAT
$stat_files;
1636 return $stat_param_files;
1640 =head2 stat_param_hash
1642 Usage: my %stat_param = $self->stat_param_hash();
1643 Desc: creates a hash (with the statistical parameters (as key) and
1644 their corresponding values) out of a tab delimited
1645 statistical parameters file.
1646 Ret: a hash statistics file
1656 my $pop_id = $self->get_object_id();
1657 my $pop = $self->get_object();
1658 my $sp_person_id = $pop->get_sp_person_id();
1659 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1660 my $c = SGN
::Context
->new();
1661 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1663 open F
, "<$user_stat_file" or die "can't open file: !$\n";
1669 my ( $parameter, $value ) = split( /\t/, $_ );
1671 $stat_param{$parameter} = $value;
1675 return \
%stat_param;
1681 my $population = $self->get_object();
1682 my $sp_person_id = $population->get_sp_person_id();
1683 my $submitter = CXGN
::People
::Person
->new( $self->get_dbh(),
1684 $population->get_sp_person_id() );
1685 my $submitter_name =
1686 $submitter->get_first_name() . " " . $submitter->get_last_name();
1687 my $submitter_link =
1688 qq |<a href
="/solpeople/personal-info.pl?sp_person_id=$sp_person_id">$submitter_name</a
> |;
1690 return $submitter, $submitter_link;
1694 #move to qtl or population object
1698 my $sp_person_id = $pop->get_sp_person_id();
1699 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1700 my $stat_file = $qtl->get_stat_file($c, $pop->get_population_id());
1704 open my $sf, "<", $stat_file or die "$! reading $stat_file\n";
1705 while (my $row = <$sf>)
1708 my ( $parameter, $value ) = split( /\t/, $row );
1709 if ($parameter =~/qtl_method/) {$parameter = 'Mapping method';}
1710 if ($parameter =~/qtl_model/) {$parameter = 'Mapping model';}
1711 if ($parameter =~/prob_method/) {$parameter = 'QTL genotype probability method';}
1712 if ($parameter =~/step_size/) {$parameter = 'Genome scan size (cM)';}
1713 if ($parameter =~/permu_level/) {$parameter = 'Permutation significance level';}
1714 if ($parameter =~/permu_test/) {$parameter = 'No. of permutations';}
1715 if ($parameter =~/prob_level/) {$parameter = 'QTL genotype signifance level';}
1716 if ($parameter =~/stat_no_draws/) {$parameter = 'No. of imputations';}
1718 if ($value eq 'zero' || $value eq 'Marker Regression') {$ci = 'none';}
1720 unless (($parameter =~/No. of imputations/ && !$value ) ||
1721 ($parameter =~/QTL genotype probability/ && !$value ) ||
1722 ($parameter =~/Permutation significance level/ && !$value)
1726 push @stat, [map{$_} ($parameter, $value)];
1733 foreach my $st (@stat) {
1734 foreach my $i (@
$st) {
1736 foreach my $s (@stat) {
1737 foreach my $j (@
$s) {
1738 $j =~ s/Maximum Likelihood/Marker Regression/;
1747 my $permu_threshold_ref = $self->permu_values();
1748 my %permu_threshold = %$permu_threshold_ref;
1752 foreach my $key ( keys %permu_threshold )
1754 if ( $key =~ m/^\d./ )
1760 my $lod1 = $permu_threshold{ $keys[0] };
1761 # my $lod2 = $permu_threshold{ $keys[1] };
1765 $lod1 = qq |<i
>Not calculated
</i
>|;
1770 map {$_} ('LOD threshold', $lod1)
1777 map {$_} ('Confidence interval', 'Based on 95% Bayesian Credible Interval')
1782 map {$_} ('QTL software', "<a href=http://www.rqtl.org>R/QTL</a>")
1784 my $legend_data = columnar_table_html
(
1799 return $legend_data;