3 Creates a trait/cvterm page with a description of
4 the population on which the trait/cvterm was evaluated,
5 displays the frequency distribution of its phenotypic data
6 and most importantly produces the on-the-fly QTL analysis
7 output for the trait and more....
11 Isaak Y Tecle (iyt2@cornell.edu)
18 my $population_indls_detail_page =
19 CXGN
::Phenome
::PopulationIndlsDetailPage
->new();
21 package CXGN
::Phenome
::PopulationIndlsDetailPage
;
26 use CXGN
::Page
::FormattingHelpers qw
/info_section_html
35 use CXGN
::Phenome
::Population
;
36 use CXGN
::Phenome
::Qtl
;
37 use CXGN
::Phenome
::PopulationDbxref
;
38 use CXGN
::Tools
::WebImageCache
;
39 use CXGN
::People
::PageComment
;
40 use CXGN
::People
::Person
;
41 use CXGN
::Chado
::Publication
;
42 use CXGN
::Chado
::Pubauthor
;
47 use GD
::Graph
::points
;
49 use Statistics
::Descriptive
;
51 use File
::Temp qw
/tempfile tempdir/;
54 use File
::Path qw
/ mkpath /;
60 use CXGN
::Scrap
::AjaxPage
;
63 use base qw
/ CXGN::Page::Form::SimpleFormPage CXGN::Phenome::Main/;
65 use CatalystX
::GlobalContext
qw( $c );
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, #< don't 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, $legend);
425 #using standard deviation of 0.05 as an arbitrary cut off to run
426 #qtl analysis. Probably, need to think of better solution.
428 $qtl_image = $self->qtl_plot();
429 $legend = $self->legend($population);
432 $qtl_image = 'There is no statistically significant phenotypic
433 variation for this trait to run
438 my $qtl_html = qq | <table
><tr
><td width
=70%>$qtl_image</td><td width=30%>$legend</td
></tr></table
> |;
440 print info_section_html
(
442 contents
=> $qtl_html,
445 print info_section_html
(
446 title
=> 'Phenotype Frequency Distribution',
447 contents
=> $plot_html,
450 print info_section_html
(
451 title
=> 'Phenotype Data',
452 contents
=> $data_view . " " . $data_download,
459 "The QTL data for this trait in this population is not public yet.
460 If you would like to know more about this data,
461 please contact the owner of the data: <b>$submitter_link</b>
463 <a href=mailto:sgn-feedback\@sgn.cornell.edu>
464 sgn-feedback\@sgn.cornell.edu</a>.\n";
466 print info_section_html
( title
=> 'QTL(s)',
467 contents
=> $message );
470 print info_section_html
(
471 title
=> 'Literature Annotation',
475 if ($population_name)
477 my $page_comment_obj =
478 CXGN
::People
::PageComment
->new( $self->get_dbh(), "population",
480 $self->get_page()->{request
}->uri()."?".$self->get_page()->{request
}->args()
482 print $page_comment_obj->get_html();
485 $self->get_page()->footer();
490 # override store to check if a locus with the submitted symbol/name already exists in the database
495 my $population = $self->get_object();
496 my $population_id = $self->get_object_id();
497 my %args = $self->get_args();
499 $self->SUPER::store
(0);
504 sub population_distribution
507 my $doc = CXGN
::Scrap
::AjaxPage
->new();
509 my ( $pop_id, $cvterm_id ) =
510 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
512 my $dbh = CXGN
::DB
::Connection
->new();
514 my ( $term_obj, $term_name, $term_id );
516 my $pop = CXGN
::Phenome
::Population
->new( $dbh, $pop_id );
517 my $pop_name = $pop->get_name();
519 if ( $pop->get_web_uploaded() )
521 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
522 $term_name = $term_obj->get_name();
523 $term_id = $term_obj->get_user_trait_id();
527 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
528 $term_name = $term_obj->get_cvterm_name();
529 $term_id = $term_obj->get_cvterm_id();
532 my $basepath = $c->get_conf("basepath");
533 my $tempfile_dir = $c->get_conf("tempfiles_subdir");
535 my $cache = CXGN
::Tools
::WebImageCache
->new();
536 $cache->set_basedir($basepath);
537 $cache->set_temp_dir( $tempfile_dir . "/temp_images" );
538 $cache->set_expiration_time(259200);
539 $cache->set_key( "popluation_distribution" . $pop_id . $term_id );
540 $cache->set_map_name("popmap$pop_id$term_id");
542 my ( @value, @indl_id, @indl_name );
544 $cache->set_force(0);
545 if ( !$cache->is_valid() )
548 my ( $indl_id, $indl_name, $value ) = $pop->plot_cvterm($term_id);
551 my $stat = Statistics
::Descriptive
::Full
->new();
552 $stat->add_data(@value);
553 my %f = $stat->frequency_distribution(10);
555 my ( @keys, @counts );
557 for ( sort { $a <=> $b } keys %f )
559 my $round = Math
::Round
::Var
->new(0.001);
560 my $key = $round->round($_);
562 push @counts, $f{$_};
565 my $min = $stat->min();
571 my @keys_range = $min . '-' . $keys[0];
574 my $previous_k = $keys[0];
575 my $keys_shifted = shift(@keys);
577 foreach my $k (@keys)
579 $range = $previous_k . '-' . $k;
580 push @keys_range, $range;
584 my $max = $counts[0];
585 foreach my $i ( @counts[ 1 .. $#counts ] )
587 if ( $i > $max ) { $max = $i; }
589 $max = int( $max + ( $max * 0.1 ) );
593 my ( $lower, $upper );
595 foreach my $k (@keys_range)
597 ( $lower, $upper ) = split( /-/, $k );
599 qq | /phenome/indls_range_cvterm
.pl?cvterm_id
=$term_id&
;lower
=$lower&
;upper
=$upper&
;population_id
=$pop_id |;
600 push @c_html, $c_html;
604 my @bar_clr = ("orange");
605 my @data = ( [@keys_range], [@counts] );
606 my $graph = new GD
::Graph
::bars
();
608 $graph->set_title_font('gdTinyFont');
611 x_label
=> "Ranges for $term_name",
612 y_label
=> "Frequency",
622 x_labels_vertical
=> 1,
628 $cache->set_image_data( $graph->plot( \
@data )->png );
630 my $map = new GD
::Graph
::Map
(
632 hrefs
=> [ \
@c_html ],
634 mapName
=> "popmap$pop_id$term_id",
635 info
=> "%x: %y lines",
637 $cache->set_image_map_data(
638 $map->imagemap( "popimage$pop_id$term_id.png", \
@data ) );
642 my $image_map = $cache->get_image_map_data();
643 my $image = $cache->get_image_tag();
645 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
. |;
647 return $image, $title, $image_map;
654 my $doc = CXGN
::Scrap
::AjaxPage
->new();
656 my ( $pop_id, $cvterm_id ) =
657 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
661 my $dbh = $self->get_dbh();
663 my $population = $self->get_object();
664 my $pop_name = $population->get_name();
665 my $mapversion = $population->mapversion_id();
666 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 $basepath = $c->get_conf("basepath");
686 my $tempfile_dir = $c->get_conf("tempfiles_subdir");
688 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
689 $self->cache_temp_path();
690 my $cache_tempimages = Cache
::File
->new( cache_root
=> $tempimages_path );
691 $cache_tempimages->purge();
693 my ( @marker, @chr, @pos, @lod );
694 my ( @chr_qtl, @left, @right, @peak );
695 my ( $qtl_image, $image, $image_t, $image_url, $image_html, $image_t_url,
696 $thickbox, $title, $l_m, $p_m, $r_m );
698 my $round1 = Math
::Round
::Var
->new(0.1);
699 my $round2 = Math
::Round
::Var
->new(1);
701 $qtl_image = $self->qtl_images_exist();
702 my $permu_data = $self->permu_values_exist();
704 unless ( $qtl_image && $permu_data )
707 my ( $qtl_summary, $flanking_markers ) = $self->run_r();
709 open my $qtl_fh, "<", $qtl_summary or die "can't open $qtl_summary: $!\n";
711 my $header = <$qtl_fh>;
712 while ( my $row = <$qtl_fh> )
714 my ( $marker, $chr, $pos, $lod ) = split( /\t/, $row );
715 push @marker, $marker;
717 $pos = $round2->round($pos);
719 $lod = $round1->round($lod);
723 my @o_lod = sort(@lod);
724 my $max = $o_lod[-1];
728 open my $markers_fh, "<", $flanking_markers
729 or die "can't open $flanking_markers: !$\n";
731 $header = <$markers_fh>;
732 while ( my $row = <$markers_fh> )
736 my ($trash, $chr_qtl, $left, $peak, $right, $peakmarker ) = split( /\t/, $row );
737 push @chr_qtl, $chr_qtl;
740 push @peak, $peakmarker;
743 my (@h_markers, @chromosomes, @lk_groups);
747 @lk_groups = @linkage_groups;
748 @lk_groups = sort ( { $a <=> $b } @lk_groups );
749 for ( my $i = 0 ; $i < @left ; $i++ )
751 my $lg = shift(@lk_groups);
752 my $key_h_marker = "$ac" . "_pop_" . "$pop_id" . "_chr_" . $lg;
753 $h_marker = $cache_tempimages->get($key_h_marker);
758 push @chromosomes, $lg;
762 s/\s//g for $l_m, $r_m, $p_m;
765 $population->get_marker_position( $mapversion, $l_m );
767 $population->get_marker_position( $mapversion, $r_m );
771 my $permu_threshold_ref = $self->permu_values();
772 my %permu_threshold = %$permu_threshold_ref;
774 foreach my $key ( keys %permu_threshold )
776 if ( $key =~ m/^\d./ )
782 my $lod1 = $permu_threshold{ $p_keys[0] };
785 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|;
788 $cache_tempimages->set( $key_h_marker, $h_marker, '30 days' );
791 push @h_markers, $h_marker;
797 $chr_chr, $image, $image_t,
798 $thickbox, $max_chr, $chr_chr_e, $marker_chr_e,
799 $pos_chr_e, $lod_chr_e
801 my $chrs = ( scalar(@chromosomes) ) + 1;
803 for ( my $i = 1 ; $i < $chrs ; $i++ )
805 my ( @marker_chr, @chr_chr, @pos_chr, @lod_chr, @data, @m_html ) =
807 my ( $marker_chr, $pos_chr, $lod_chr, $max_chr );
809 $h_marker = shift(@h_markers);
811 if ( ( $i == $old_chr_chr ) && ( $i != 12 ) )
813 push @marker_chr, $marker_chr_e;
814 push @chr_chr, $chr_chr_e;
815 $pos_chr_e = $round2->round($pos_chr_e);
816 push @pos_chr, $pos_chr_e;
817 $lod_chr = $round1->round($lod_chr_e);
818 push @lod_chr, $lod_chr_e;
821 my $cache_qtl_plot = CXGN
::Tools
::WebImageCache
->new();
822 $cache_qtl_plot->set_basedir($basepath);
823 $cache_qtl_plot->set_temp_dir( $tempfile_dir . "/temp_images" );
824 $cache_qtl_plot->set_expiration_time(259200);
825 $cache_qtl_plot->set_key(
826 "qtlplot" . $i . "small" . $pop_id . $term_id );
827 $cache_qtl_plot->set_force(0);
829 if ( !$cache_qtl_plot->is_valid() )
832 for ( my $j = 0 ; $j < @marker ; $j++ )
837 if ( $i == $chr_chr )
839 $marker_chr = $marker[$j];
844 push @marker_chr, $marker_chr;
845 push @chr_chr, $chr_chr;
846 $pos_chr = $round2->round($pos_chr);
847 push @pos_chr, $pos_chr;
848 $lod_chr = $round1->round($lod_chr);
849 push @lod_chr, $lod_chr;
851 ( $chr_chr_e, $marker_chr_e, $pos_chr_e, $lod_chr_e ) =
855 elsif ( $i != $chr_chr )
858 $chr_chr_e = $chr[$j];
859 $marker_chr_e = $marker[$j];
860 $pos_chr_e = $pos[$j];
861 $lod_chr_e = $lod[$j];
866 @data = ( [ (@pos_chr) ], [@lod_chr] );
867 my $graph = new GD
::Graph
::lines
( 110, 110 );
868 $graph->set_title_font('gdTinyFont');
871 x_label
=> "Chr $i (cM)",
880 x_labels_vertical
=> 1,
884 $cache_qtl_plot->set_image_data( $graph->plot( \
@data )->png );
888 $image = $cache_qtl_plot->get_image_tag();
889 $image_url = $cache_qtl_plot->get_image_url();
893 my $cache_qtl_plot_t = CXGN
::Tools
::WebImageCache
->new();
894 $cache_qtl_plot_t->set_basedir($basepath);
895 $cache_qtl_plot_t->set_temp_dir( $tempfile_dir . "/temp_images" );
896 $cache_qtl_plot_t->set_expiration_time(259200);
897 $cache_qtl_plot_t->set_key(
898 "qtlplot_" . $i . "_thickbox_" . $pop_id . $term_id );
899 $cache_qtl_plot_t->set_force(0);
901 if ( !$cache_qtl_plot_t->is_valid() )
903 my @o_lod_chr = sort { $a <=> $b } @lod_chr;
904 $max_chr = pop(@o_lod_chr);
905 $max_chr = $max_chr + (0.5);
907 my $graph_t = new GD
::Graph
::lines
( 420, 420 );
908 $graph_t->set_title_font('gdTinyFont');
911 x_label
=> "Chromosome $i (cM)",
913 y_max_value
=> $max_chr,
920 x_labels_vertical
=> 1,
924 $cache_qtl_plot_t->set_image_data(
925 $graph_t->plot( \
@data )->png );
929 $image_t = $cache_qtl_plot_t->get_image_tag();
930 $image_t_url = $cache_qtl_plot_t->get_image_url();
933 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
> |;
935 $qtl_image .= $thickbox;
937 $old_chr_chr = $chr_chr;
945 Usage: my $file_in = $self->infile_list();
946 Desc: returns an R input tempfile containing a tempfile
947 holding the cvterm acronym, pop id, a filepath to the phenotype dataset file,
948 a filepath to genotype dataset file, a filepath to the permuation file.
949 Ret: an R input tempfile name (with abosulte path)
961 my $doc = CXGN
::Scrap
::AjaxPage
->new();
963 my ( $pop_id, $cvterm_id ) =
964 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
966 my $dbh = $self->get_dbh();
968 my ( $term_obj, $term_name, $term_id );
969 my $population = $self->get_object();
971 if ( $population->get_web_uploaded() )
973 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
974 $term_name = $term_obj->get_name();
975 $term_id = $term_obj->get_user_trait_id();
979 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
980 $term_name = $term_obj->get_cvterm_name();
981 $term_id = $term_obj->get_cvterm_id();
984 my $ac = $population->cvterm_acronym($term_name);
986 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
987 $self->cache_temp_path();
989 my $prod_permu_file = $self->permu_file();
990 my $gen_dataset_file = $population->genotype_file($c);
991 my $phe_dataset_file = $population->phenotype_file($c);
992 my $crosstype_file = $self->crosstype_file();
994 my $input_file_list_temp =
996 TEMPLATE
=> "infile_list_${ac}_$pop_id-XXXXXX",
997 DIR
=> $prod_temp_path,
1000 my $file_in = $input_file_list_temp->filename();
1002 my $file_cvin = File
::Temp
->new(
1003 TEMPLATE
=> 'cv_input-XXXXXX',
1004 DIR
=> $prod_temp_path,
1007 my $file_cv_in = $file_cvin->filename();
1009 open my $cv_fh, ">", $file_cv_in or die "can't open $file_cv_in: $!\n";
1013 my $file_in_list = join( "\t",
1014 $file_cv_in, "P$pop_id",
1015 $gen_dataset_file, $phe_dataset_file,
1016 $prod_permu_file, $crosstype_file);
1018 open my $fi_fh, ">", $file_in or die "can't open $file_in: $!\n";
1019 $fi_fh->print ($file_in_list);
1027 Usage: my ($file_out, $qtl_summary, $flanking_markers) = $self->outfile_list();
1028 Desc: returns an R output tempfile containing a tempfile supposed to hold the qtl
1029 mapping output and another tempfile for the qtl flanking markers
1030 and the qtl mapping output and qtl flanking markers files separately
1031 (convenient for reading their data when plotting the qtl)
1032 Ret: R output file names (with abosulte path)
1043 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1045 my ( $pop_id, $cvterm_id ) =
1046 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1048 my $dbh = $self->get_dbh();
1050 my ( $term_obj, $term_name, $term_id );
1051 my $population = $self->get_object();
1053 if ( $population->get_web_uploaded() )
1055 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1056 $term_name = $term_obj->get_name();
1057 $term_id = $term_obj->get_user_trait_id();
1061 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1062 $term_name = $term_obj->get_cvterm_name();
1063 $term_id = $term_obj->get_cvterm_id();
1066 my $ac = $population->cvterm_acronym($term_name);
1068 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1069 $self->cache_temp_path();
1071 my $output_file_list_temp =
1073 TEMPLATE
=> "outfile_list_${ac}_$pop_id-XXXXXX",
1074 DIR
=> $prod_temp_path,
1077 my $file_out = $output_file_list_temp->filename();
1079 my $qtl_temp = File
::Temp
->new(
1080 TEMPLATE
=> "qtl_summary_${ac}_$pop_id-XXXXXX",
1081 DIR
=> $prod_temp_path,
1084 my $qtl_summary = $qtl_temp->filename;
1086 my $marker_temp = File
::Temp
->new(
1087 TEMPLATE
=> "flanking_markers_${ac}_$pop_id-XXXXXX",
1088 DIR
=> $prod_temp_path,
1092 my $flanking_markers = $marker_temp->filename;
1094 my $ci_lod = $population->ci_lod_file($c, $ac);
1096 my $file_out_list = join (
1103 open my $fo_fh, ">", $file_out or die "can't open $file_out: $!\n";
1104 $fo_fh->print ($file_out_list);
1106 return $file_out, $qtl_summary, $flanking_markers;
1109 =head2 cache_temp_path
1111 Usage: my ($rqtl_cache_path, $rqtl_temp_path, $tempimages_path) = $self->cache_temp_path();
1112 Desc: creates the 'r_qtl/cache' and 'r_qtl/tempfiles' subdirs in the /data/prod/tmp,
1113 Ret: /data/prod/tmp/r_qtl/cache, /data/prod/tmp/r_qtl/tempfiles,
1114 /data/local/cxgn/sgn/documents/tempfiles/temp_images
1123 my $basepath = $c->get_conf("basepath");
1124 my $tempfile_dir = $c->get_conf("tempfiles_subdir");
1126 my $tempimages_path =
1127 File
::Spec
->catfile( $basepath, $tempfile_dir, "temp_images" );
1129 my $prod_rqtl_path = $c->get_conf('r_qtl_temp_path');
1130 my $rqtl_cache_path = "$prod_rqtl_path/cache";
1131 my $rqtl_temp_path = "$prod_rqtl_path/tempfiles";
1133 mkpath
([$rqtl_cache_path, $rqtl_temp_path, $tempimages_path], 0, 0755);
1135 return $rqtl_cache_path, $rqtl_temp_path, $tempimages_path;
1141 =head2 crosstype_file
1143 Usage: my $cross_file = $self->crosstype_file();
1144 Desc: creates the crosstype file in the /data/prod/tmp/r_qtl/tempfiles,
1146 Ret: crosstype filename (with absolute path)
1153 sub crosstype_file
{
1155 my $pop_id = $self->get_object_id();
1156 my $population = $self->get_object();
1158 my $type_id = $population->get_cross_type_id
1159 or die "population '$pop_id' has no cross_type, does not seem to be the product of a cross!";
1160 my ($cross_type) = $self->get_dbh->selectrow_array(<<'', undef, $type_id);
1163 where cross_type_id
= ?
1165 my $rqtl_cross_type = { 'Back cross' => 'bc', 'F2' => 'f2' }->{$cross_type}
1166 or die "unknown cross_type '$cross_type' for population '$pop_id'";
1168 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1169 $self->cache_temp_path();
1171 my $cross_temp = File
::Temp
->new(
1172 TEMPLATE
=> "cross_type_${pop_id}-XXXXXX",
1173 DIR
=> $prod_temp_path,
1177 $cross_temp->print( $rqtl_cross_type );
1178 return $cross_temp->filename;
1185 Usage: my ($qtl_summary, $flanking_markers) = $self->run_r();
1186 Desc: run R in the cluster; copies permutation file from the /data/prod..
1187 to the tempimages dir; returns the R output files (with abosulate filepath) with qtl mapping data
1188 and flanking markers
1200 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1201 $self->cache_temp_path();
1202 my $prod_permu_file = $self->permu_file();
1203 my $file_in = $self->infile_list();
1204 my ( $file_out, $qtl_summary, $flanking_markers ) = $self->outfile_list();
1205 my $stat_file = $self->stat_files();
1207 CXGN
::Tools
::Run
->temp_base($prod_temp_path);
1209 my ( $r_in_temp, $r_out_temp ) =
1211 my ( undef, $filename ) =
1213 File
::Spec
->catfile(
1214 CXGN
::Tools
::Run
->temp_base(),
1215 "population_indls.pl-$_-XXXXXX",
1221 #copy our R commands into a cluster-accessible tempfile
1222 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1225 my $r_cmd_file = $doc->path_to('/cgi-bin/phenome/cvterm_qtl.r');
1226 copy
( $r_cmd_file, $r_in_temp )
1227 or die "could not copy '$r_cmd_file' to '$r_in_temp'";
1231 # now run the R job on the cluster
1232 my $r_process = CXGN
::Tools
::Run
->run_cluster(
1233 'R', 'CMD', 'BATCH',
1235 "--args $file_in $file_out $stat_file",
1239 working_dir
=> $prod_temp_path,
1241 # don't block and wait if the cluster looks full
1242 max_cluster_jobs
=> 1_000_000_000
,
1246 $r_process->wait; #< wait for R to finish
1249 $err =~ s/\n at .+//s; #< remove any additional backtrace
1250 # # try to append the R output
1251 try
{ $err .= "\n=== R output ===\n".file
($r_out_temp)->slurp."\n=== end R output ===\n" };
1252 # die with a backtrace
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;
1311 my $permu_file = $file_cache->get($key_permu);
1313 unless ($permu_file)
1318 my $permu_file = File
::Spec
->catfile( $prod_cache_path, $filename );
1320 open my $permu_fh, ">", $permu_file or die "can't open $permu_file: !$\n";
1321 $permu_fh->print($permu);
1324 $file_cache->set( $key_permu, $permu_file, '30 days' );
1325 $permu_file = $file_cache->get($key_permu);
1334 Usage: my $permu_values = $self->permu_values();
1335 Desc: reads the permutation output from R,
1336 creates a hash with the probality level as key and LOD threshold as the value,
1338 Ret: a hash ref of the permutation values
1348 my $prod_permu_file = $self->permu_file();
1350 my %permu_threshold = {};
1352 my $permu_file = fileparse
($prod_permu_file);
1353 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1354 $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 my $permu_fh, "<", $permu_file
1361 or die "can't open $permu_file: !$\n";
1363 my $header = <$permu_fh>;
1365 while ( my $row = <$permu_fh> )
1367 my ( $significance, $lod_threshold ) = split( /\t/, $row );
1368 $lod_threshold = $round1->round($lod_threshold);
1369 $permu_threshold{$significance} = $lod_threshold;
1372 return \
%permu_threshold;
1376 =head2 permu_values_exist
1378 Usage: my $permu_value = $self->permu_values_exist();
1379 Desc: checks if there is permutation value in the permutation file.
1380 Ret: undef or some value
1387 sub permu_values_exist
1390 my $prod_permu_file = $self->permu_file();
1392 my ( $size, $permu_file, $permu_data, $tempimages_path, $prod_cache_path,
1395 if ($prod_permu_file)
1398 $permu_file = fileparse
($prod_permu_file);
1399 ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1400 $self->cache_temp_path();
1406 $permu_file = File
::Spec
->catfile( $tempimages_path, $permu_file );
1409 if ( -e
$permu_file )
1412 open my $pf_fh, "<", $permu_file or die "can't open $permu_file: !$\n";
1414 while ( $permu_data = <$pf_fh> )
1416 last if ($permu_data);
1418 # #just checking if there is data in there
1434 =head2 qtl_images_exist
1436 Usage: my $qtl_images_ref = $self->qtl_images_exist();
1437 Desc: checks and returns a scalar ref if the qtl plots (with thickbox and their links to the comparative viewer) exist in the cache
1438 Ret: scalar ref to the images or undef
1445 sub qtl_images_exist
1448 my $doc = CXGN
::Scrap
::AjaxPage
->new();
1450 my ( $pop_id, $cvterm_id ) =
1451 $doc->get_encoded_arguments( "population_id", "cvterm_id" );
1453 my $dbh = $self->get_dbh();
1455 my $population = $self->get_object();
1456 my $pop_name = $population->get_name();
1458 my @linkage_groups = $population->linkage_groups();
1459 @linkage_groups = sort ( { $a <=> $b } @linkage_groups );
1461 my ( $term_obj, $term_name, $term_id );
1463 if ( $population->get_web_uploaded() )
1465 $term_obj = CXGN
::Phenome
::UserTrait
->new( $dbh, $cvterm_id );
1466 $term_name = $term_obj->get_name();
1467 $term_id = $term_obj->get_user_trait_id();
1471 $term_obj = CXGN
::Chado
::Cvterm
->new( $dbh, $cvterm_id );
1472 $term_name = $term_obj->get_cvterm_name();
1473 $term_id = $term_obj->get_cvterm_id();
1476 my $ac = $population->cvterm_acronym($term_name);
1478 my $basepath = $c->get_conf("basepath");
1479 my $tempfile_dir = $c->get_conf("tempfiles_subdir");
1481 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1482 $self->cache_temp_path();
1484 my $cache_tempimages = Cache
::File
->new( cache_root
=> $tempimages_path );
1485 $cache_tempimages->purge();
1487 my ( $qtl_image, $image, $image_t, $image_url, $image_html, $image_t_url,
1488 $thickbox, $title );
1491 IMAGES
: foreach my $lg (@linkage_groups)
1493 my $cache_qtl_plot = CXGN
::Tools
::WebImageCache
->new();
1494 $cache_qtl_plot->set_basedir($basepath);
1495 $cache_qtl_plot->set_temp_dir( $tempfile_dir . "/temp_images" );
1497 my $key = "qtlplot" . $lg . "small" . $pop_id . $term_id;
1498 $cache_qtl_plot->set_key($key);
1500 my $key_h_marker = "$ac" . "_pop_" . "$pop_id" . "_chr_" . $lg;
1501 my $h_marker = $cache_tempimages->get($key_h_marker);
1503 if ( $cache_qtl_plot->is_valid )
1505 $image = $cache_qtl_plot->get_image_tag();
1506 $image_url = $cache_qtl_plot->get_image_url();
1509 my $cache_qtl_plot_t = CXGN
::Tools
::WebImageCache
->new();
1510 $cache_qtl_plot_t->set_basedir($basepath);
1511 $cache_qtl_plot_t->set_temp_dir( $tempfile_dir . "/temp_images" );
1513 my $key_t = "qtlplot_" . $lg . "_thickbox_" . $pop_id . $term_id;
1514 $cache_qtl_plot_t->set_key($key_t);
1516 if ( $cache_qtl_plot_t->is_valid )
1519 $image_t = $cache_qtl_plot_t->get_image_tag();
1520 $image_t_url = $cache_qtl_plot_t->get_image_url();
1523 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
> |;
1525 $qtl_image .= $thickbox;
1543 # =head2 user_stat_file
1554 # sub user_stat_file {
1556 # my $pop = $self->get_object();
1557 # my $pop_id = $self->get_object_id();
1558 # my $sp_person_id = $pop->get_sp_person_id();
1559 # my $qtl = CXGN::Phenome::Qtl->new($sp_person_id);
1560 # #$qtl->set_population_id($pop_id);
1562 # my ($qtl_dir, $user_dir) = $qtl->get_user_qtl_dir();
1564 # my $stat_file = "$user_dir/user_stat_pop_$pop_id.txt";
1565 # print STDERR "stat_file: $stat_file";
1567 # if (-e $stat_file) {
1568 # return $stat_file;
1569 # } else {return 0;}
1575 Usage: my $stat_param_files = $self->stat_files();
1576 Desc: creates a master file containing individual files
1577 in /data/prod/tmp/r_qtl for each statistical parameter
1578 which are feed to R.
1579 Ret: an absolute path to the statistical parameter's
1580 master file (and individual files)
1590 my $pop_id = $self->get_object_id();
1591 my $pop = $self->get_object();
1592 my $sp_person_id = $pop->get_sp_person_id();
1593 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1594 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1596 my ( $prod_cache_path, $prod_temp_path, $tempimages_path ) =
1597 $self->cache_temp_path();
1599 open my $user_stat_fh, "<", $user_stat_file or die "can't open file: !$\n";
1603 while (<$user_stat_fh>)
1605 my ( $parameter, $value ) = split( /\t/, $_ );
1607 my $stat_temp = File
::Temp
->new(
1608 TEMPLATE
=> "${parameter}_$pop_id-XXXXXX",
1609 DIR
=> $prod_temp_path,
1612 my $stat_file = $stat_temp->filename;
1614 open my $sf_fh, ">", $stat_file or die "can't open file: !$\n";
1615 $sf_fh->print($value);
1618 $stat_files .= $stat_file . "\t";
1624 my $stat_param_files =
1625 $prod_temp_path . "/" . "stat_temp_files_pop_id_${pop_id}";
1627 open my $stat_param_fh, ">", $stat_param_files or die "can't open file: !$\n";
1628 $stat_param_fh->print ($stat_files);
1631 return $stat_param_files;
1635 =head2 stat_param_hash
1637 Usage: my %stat_param = $self->stat_param_hash();
1638 Desc: creates a hash (with the statistical parameters (as key) and
1639 their corresponding values) out of a tab delimited
1640 statistical parameters file.
1641 Ret: a hash statistics file
1651 my $pop_id = $self->get_object_id();
1652 my $pop = $self->get_object();
1653 my $sp_person_id = $pop->get_sp_person_id();
1654 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1655 my $user_stat_file = $qtl->get_stat_file($c, $pop_id);
1657 open my $user_stat_fh, "<", $user_stat_file or die "can't open file: !$\n";
1661 while (<$user_stat_fh>)
1663 my ( $parameter, $value ) = split( /\t/, $_ );
1665 $stat_param{$parameter} = $value;
1669 return \
%stat_param;
1675 my $population = $self->get_object();
1676 my $sp_person_id = $population->get_sp_person_id();
1677 my $submitter = CXGN
::People
::Person
->new( $self->get_dbh(),
1678 $population->get_sp_person_id() );
1679 my $submitter_name =
1680 $submitter->get_first_name() . " " . $submitter->get_last_name();
1681 my $submitter_link =
1682 qq |<a href
="/solpeople/personal-info.pl?sp_person_id=$sp_person_id">$submitter_name</a
> |;
1684 return $submitter, $submitter_link;
1688 #move to qtl or population object
1692 my $sp_person_id = $pop->get_sp_person_id();
1693 my $qtl = CXGN
::Phenome
::Qtl
->new($sp_person_id);
1694 my $stat_file = $qtl->get_stat_file($c, $pop->get_population_id());
1698 open my $sf, "<", $stat_file or die "$! reading $stat_file\n";
1699 while (my $row = <$sf>)
1702 my ( $parameter, $value ) = split( /\t/, $row );
1703 if ($parameter =~/qtl_method/) {$parameter = 'Mapping method';}
1704 if ($parameter =~/qtl_model/) {$parameter = 'Mapping model';}
1705 if ($parameter =~/prob_method/) {$parameter = 'QTL genotype probability method';}
1706 if ($parameter =~/step_size/) {$parameter = 'Genome scan size (cM)';}
1707 if ($parameter =~/permu_level/) {$parameter = 'Permutation significance level';}
1708 if ($parameter =~/permu_test/) {$parameter = 'No. of permutations';}
1709 if ($parameter =~/prob_level/) {$parameter = 'QTL genotype signifance level';}
1710 if ($parameter =~/stat_no_draws/) {$parameter = 'No. of imputations';}
1712 if ($value eq 'zero' || $value eq 'Marker Regression') {$ci = 0;}
1714 unless (($parameter =~/No. of imputations/ && !$value ) ||
1715 ($parameter =~/QTL genotype probability/ && !$value ) ||
1716 ($parameter =~/Permutation significance level/ && !$value)
1720 push @stat, [map{$_} ($parameter, $value)];
1727 foreach my $st (@stat) {
1728 foreach my $i (@
$st) {
1730 foreach my $s (@stat) {
1731 foreach my $j (@
$s) {
1732 $j =~ s/Maximum Likelihood/Marker Regression/;
1741 my $permu_threshold_ref = $self->permu_values();
1742 my %permu_threshold = %$permu_threshold_ref;
1746 foreach my $key ( keys %permu_threshold )
1748 if ( $key =~ m/^\d./ )
1754 my $lod1 = $permu_threshold{ $keys[0] };
1755 # my $lod2 = $permu_threshold{ $keys[1] };
1759 $lod1 = qq |<i
>Not calculated
</i
>|;
1764 map {$_} ('LOD threshold', $lod1)
1771 map {$_} ('Confidence interval', 'Based on 95% Bayesian Credible Interval')
1777 map {$_} ('QTL software', "<a href=http://www.rqtl.org>R/QTL</a>")
1780 my $legend_data = columnar_table_html
(
1794 return $legend_data;