3 SGN::Controller::Qtl- controller for solQTL
7 package SGN
::Controller
::Qtl
;
10 use namespace
::autoclean
;
11 use File
::Spec
::Functions
;
12 use File
::Temp qw
/ tempfile /;
13 use File
::Path qw
/ mkpath /;
18 use URI
::FromHash
'uri';
21 use Bio
::Chado
::Schema
;
22 use CXGN
::Phenome
::Qtl
;
24 BEGIN { extends
'Catalyst::Controller'}
26 sub view
: PathPart
('qtl/view') Chained Args
(1) {
27 my ($self, $c, $id) = @_;
28 $c->res->redirect("/qtl/population/$id");
32 sub population
: PathPart
('qtl/population') Chained Args
(1) {
33 my ( $self, $c, $id) = @_;
37 $c->throw_404("$id is not a valid population id.");
41 my $schema = $c->dbic_schema('CXGN::Phenome::Schema');
42 my $rs = $schema->resultset('Population')->find($id);
45 $self->_is_qtl_pop($c, $id);
46 if ( $c->stash->{is_qtl_pop
} )
48 my $userid = $c->user->get_object->get_sp_person_id if $c->user;
49 $c->stash(template
=> '/qtl/population/index.mas',
50 pop => CXGN
::Phenome
::Population
->new($c->dbc->dbh, $id),
51 referer
=> $c->req->path,
55 $self->_show_data($c);
56 $self->_list_traits($c);
57 $self->genetic_map($c);
61 $c->stash(heatmap_file
=> undef,
62 corre_table_file
=> undef,
64 $self->_get_trait_acronyms($c);
69 $self->_correlation_output($c);
74 $c->throw_404("$id is not a QTL population.");
79 $c->throw_404("There is no QTL population for $id");
85 $c->throw_404("You must provide a valid population id argument");
89 sub download_phenotype
: PathPart
('qtl/download/phenotype') Chained Args
(1) {
90 my ($self, $c, $id) = @_;
91 my $pop = CXGN
::Phenome
::Population
->new($c->dbc->dbh, $id);
92 my $phenotype_file = $pop->phenotype_file($c);
94 unless (!-e
$phenotype_file || -s
$phenotype_file <= 1)
97 foreach ( read_file
($phenotype_file) )
99 push @pheno_data, [ split(/,/) ];
101 $c->stash->{'csv'}={ data
=> \
@pheno_data};
102 $c->forward("SGN::View::Download::CSV");
106 sub download_genotype
: PathPart
('qtl/download/genotype') Chained Args
(1) {
107 my ($self, $c, $id) = @_;
108 my $pop = CXGN
::Phenome
::Population
->new($c->dbc->dbh, $id);
109 my $genotype_file = $pop->genotype_file($c);
111 unless (!-e
$genotype_file || -s
$genotype_file <= 1)
114 foreach ( read_file
($genotype_file))
116 push @geno_data, [ split(/,/) ];
118 $c->stash->{'csv'}={ data
=> \
@geno_data};
119 $c->forward("SGN::View::Download::CSV");
123 sub download_correlation
: PathPart
('qtl/download/correlation') Chained Args
(1) {
124 my ($self, $c, $id) = @_;
126 $c->stash(pop => CXGN
::Phenome
::Population
->new($c->dbc->dbh, $id));
127 $self->_correlation_output($c);
128 my $corr_file = $c->stash->{corre_table_file
};
129 my $base_path = $c->config->{basepath
};
130 $corr_file = $base_path . $corr_file;
132 unless (!-e
$corr_file || -s
$corr_file <= 1)
137 foreach ( read_file
($corr_file) )
139 if ($count==1) { $_ = "Traits " . $_;}
141 push @corr_data, [ split (/,/) ];
145 $c->stash->{'csv'}={ data
=> \
@corr_data };
146 $c->forward("SGN::View::Download::CSV");
150 sub download_acronym
: PathPart
('qtl/download/acronym') Chained Args
(1) {
151 my ($self, $c, $id) = @_;
152 my $pop = CXGN
::Phenome
::Population
->new($c->dbc->dbh, $id);
153 $c->stash->{'csv'}={ data
=> $pop->get_cvterm_acronyms};
154 $c->forward("SGN::View::Download::CSV");
158 sub _analyze_correlation
{
160 my $pop_id = $c->stash->{pop}->get_population_id();
161 my $pheno_file = $c->stash->{pop}->phenotype_file($c);
162 my $base_path = $c->config->{basepath
};
163 my $temp_image_dir = $c->config->{tempfiles_subdir
};
164 my $r_qtl_dir = $c->config->{r_qtl_temp_path
};
165 my $corre_image_dir = catfile
($base_path, $temp_image_dir, "correlation");
166 my $corre_temp_dir = catfile
($r_qtl_dir, "tempfiles");
170 foreach my $dir ($corre_temp_dir, $corre_image_dir)
174 mkpath
($dir, 0, 0755);
178 my (undef, $heatmap_file) = tempfile
( "heatmap_${pop_id}-XXXXXX",
179 DIR
=> $corre_temp_dir,
184 my (undef, $corre_table_file) = tempfile
( "corre_table_${pop_id}-XXXXXX",
185 DIR
=> $corre_temp_dir,
190 my ( $corre_commands_temp, $corre_output_temp ) =
193 my ( undef, $filename ) =
196 CXGN
::Tools
::Run
->temp_base($corre_temp_dir),
197 "corre_pop_${pop_id}-$_-XXXXXX"
205 my $corre_commands_file = $c->path_to('/cgi-bin/phenome/correlation.r');
206 copy
( $corre_commands_file, $corre_commands_temp )
207 or die "could not copy '$corre_commands_file' to '$corre_commands_temp'";
211 my $r_process = CXGN
::Tools
::Run
->run_cluster(
214 "--args $heatmap_file $corre_table_file $pheno_file",
215 $corre_commands_temp,
218 working_dir
=> $corre_temp_dir,
219 max_cluster_jobs
=> 1_000_000_000
,
228 $err =~ s/\n at .+//s; #< remove any additional backtrace
229 # # try to append the R output
230 try
{ $err .= "\n=== R output ===\n".file
($corre_output_temp)->slurp."\n=== end R output ===\n" };
231 # die with a backtrace
235 copy
( $heatmap_file, $corre_image_dir )
236 or die "could not copy $heatmap_file to $corre_image_dir";
237 copy
( $corre_table_file, $corre_image_dir )
238 or die "could not copy $corre_table_file to $corre_image_dir";
240 $heatmap_file = fileparse
($heatmap_file);
241 $heatmap_file = $c->generated_file_uri("correlation", $heatmap_file);
242 $corre_table_file = fileparse
($corre_table_file);
243 $corre_table_file = $c->generated_file_uri("correlation", $corre_table_file);
245 $c->stash( heatmap_file
=> $heatmap_file,
246 corre_table_file
=> $corre_table_file
251 sub _correlation_output
{
253 my $pop = $c->{stash
}->{pop};
254 my $base_path = $c->config->{basepath
};
255 my $temp_image_dir = $c->config->{tempfiles_subdir
};
256 my $corre_image_dir = catfile
($base_path, $temp_image_dir, "correlation");
257 my $cache = Cache
::File
->new( cache_root
=> $corre_image_dir,
262 my $key_h = "heat_" . $pop->get_population_id();
263 my $key_t = "corr_table_" . $pop->get_population_id();
264 my $heatmap = $cache->get($key_h);
265 my $corre_table = $cache->get($key_t);
270 $self->_analyze_correlation($c);
271 $heatmap = $c->stash->{heatmap_file
};
272 $corre_table = $c->stash->{corre_table_file
};
273 $cache->set($key_h, "$heatmap", "24h");
274 $cache->set($key_t, "$corre_table", "24h");
278 $heatmap = undef if -z
$c->get_conf('basepath') . $heatmap;
279 $corre_table = undef if -z
$c->get_conf('basepath') . $corre_table;
281 $c->stash( heatmap_file
=> $heatmap,
282 corre_table_file
=> $corre_table,
285 $self->_get_trait_acronyms($c) if $heatmap;
291 my $population_id = $c->stash->{pop}->get_population_id();
294 if ($c->stash->{pop}->get_web_uploaded())
296 my @traits = $c->stash->{pop}->get_cvterms();
298 foreach my $trait (@traits)
300 my $trait_id = $trait->get_user_trait_id();
301 my $trait_name = $trait->get_name();
302 my $definition = $trait->get_definition();
304 my ($min, $max, $avg, $std, $count)= $c->stash->{pop}->get_pop_data_summary($trait_id);
306 $c->stash( trait_id
=> $trait_id,
307 trait_name
=> $trait_name
310 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
311 my $cvterm = $schema->resultset('Cv::Cvterm')->find(name
=> $trait_name);
316 $c->stash(cvterm_id
=>$cvterm->id);
318 $trait_link = $c->stash->{cvterm_page
};
322 $trait_link = $c->stash->{trait_page
};
325 my $qtl_analysis_page = $c->stash->{qtl_analysis_page
};
326 push @phenotype, [ map { $_ } ( $trait_link, $min, $max, $avg, $count, $qtl_analysis_page ) ];
331 my @cvterms = $c->stash->{pop}->get_cvterms();
332 foreach my $cvterm( @cvterms )
334 my $cvterm_id = $cvterm->get_cvterm_id();
335 my $cvterm_name = $cvterm->get_cvterm_name();
336 my ($min, $max, $avg, $std, $count)= $c->stash->{pop}->get_pop_data_summary($cvterm_id);
338 $c->stash( trait_name
=> $cvterm_name,
339 cvterm_id
=> $cvterm_id
343 my $graph_icon = $c->stash->{graph_icon
};
344 my $qtl_analysis_page = $c->stash->{qtl_analysis_page
};
345 my $cvterm_page = $c->stash->{cvterm_page
};
346 push @phenotype, [ map { $_ } ( $cvterm_page, $min, $max, $avg, $count, $qtl_analysis_page ) ];
349 $c->stash->{traits_list
} = \
@phenotype;
354 my ($self, $c, $id) = @_;
355 my $qtltool = CXGN
::Phenome
::Qtl
::Tools
->new();
356 my @qtl_pops = $qtltool->has_qtl_data();
358 foreach my $qtl_pop ( @qtl_pops )
360 my $pop_id = $qtl_pop->get_population_id();
363 $c->stash->{is_qtl_pop
} = 1;
372 my $pop_id = $c->stash->{pop}->get_population_id();
375 no warnings
'uninitialized';
376 my $trait_id = $c->stash->{trait_id
};
377 my $cvterm_id = $c->stash->{cvterm_id
};
378 my $trait_name = $c->stash->{trait_name
};
379 my $term_id = $trait_id ?
$trait_id : $cvterm_id;
380 my $graph_icon = qq | <img src
="/../../../documents/img/pop_graph.png" alt
="run solqtl"/> |;
382 $self->_get_owner_details($c);
383 my $owner_name = $c->stash->{owner_name
};
384 my $owner_id = $c->stash->{owner_id
};
387 $c->stash( cvterm_page
=> qq |<a href
="/chado/cvterm.pl?cvterm_id=$cvterm_id">$trait_name</a
> |,
388 trait_page
=> qq |<a href
="/phenome/trait.pl?trait_id=$trait_id">$trait_name</a
> |,
389 owner_page
=> qq |<a href
="/solpeople/personal-info.pl?sp_person_id=$owner_id">$owner_name</a
> |,
390 guideline
=> $self->guideline,
391 phenotype_download
=> qq |<a href
="/qtl/download/phenotype/$pop_id">Phenotype data
</a
> |,
392 genotype_download
=> qq |<a href
="/qtl/download/genotype/$pop_id">Genotype data
</a
> |,
393 corre_download
=> qq |<a href
="/qtl/download/correlation/$pop_id">Correlation data
</a
> |,
394 acronym_download
=> qq |<a href
="/qtl/download/acronym/$pop_id">Trait
-acronym key
</a
> |,
395 qtl_analysis_page
=> qq |<a href
="/phenome/qtl_analysis.pl?population_id=$pop_id&cvterm_id=$term_id" onclick
="Qtl.waitPage()">$graph_icon</a
> |,
401 sub _get_trait_acronyms
{
403 $c->stash(trait_acronym_pairs
=> $c->stash->{pop}->get_cvterm_acronyms());
406 sub _get_owner_details
{
408 my $owner_id = $c->stash->{pop}->get_sp_person_id();
409 my $owner = CXGN
::People
::Person
->new($c->dbc->dbh, $owner_id);
410 my $owner_name = $owner->get_first_name()." ".$owner->get_last_name();
412 $c->stash( owner_name
=> $owner_name,
413 owner_id
=> $owner_id
420 my $user_id = $c->stash->{userid
};
421 my $user_type = $c->user->get_object->get_user_type() if $c->user;
422 my $is_public = $c->stash->{pop}->get_privacy_status();
423 my $owner_id = $c->stash->{pop}->get_sp_person_id();
427 ($user_id == $owner_id || $user_type eq 'curator') ?
$c->stash(show_data
=> 1)
428 : $c->stash(show_data
=> undef)
432 $is_public ?
$c->stash(show_data
=> 1)
433 : $c->stash(show_data
=> undef)
438 sub search_help
: PathPart
('search/qtl/help') Chained Args
(0) {
440 $c->stash(template
=> '/qtl/search/help/index.mas')
443 sub set_stat_option
: PathPart
('qtl/stat/option') Chained Args
(0) {
445 my $pop_id = $c->req->param('pop_id');
446 my $stat_params = $c->req->param('stat_params');
447 my $file = $self->stat_options_file($c, $pop_id);
451 my $f = file
( $file )->openw
452 or die "Can't create file: $! \n";
454 if ( $stat_params eq 'default' )
456 $f->print( "default parameters\tYes" );
460 $f->print( "default parameters\tNo" );
463 $c->res->content_type('application/json');
464 $c->res->body({undef});
468 sub stat_options_file
{
469 my ($self, $c, $pop_id) = @_;
470 my $login_id = $c->user()->get_object->get_sp_person_id() if $c->user;
474 my $qtl = CXGN
::Phenome
::Qtl
->new($login_id);
475 my ($temp_qtl_dir, $temp_user_dir) = $qtl->create_user_qtl_dir($c);
476 return catfile
( $temp_user_dir, "stat_options_pop_${pop_id}.txt" );
485 sub qtl_form
: PathPart
('qtl/form') Chained Args
{
486 my ($self, $c, $type, $pop_id) = @_;
488 my $userid = $c->user()->get_object->get_sp_person_id() if $c->user;
492 $c->res->redirect($c->uri_for('/solpeople/login.pl'));
495 $type = 'intro' if !$type;
497 if (!$pop_id and $type !~ /intro|pop_form/ )
499 $c->throw_404("Population id argument is missing");
502 $c->stash( template
=> $self->get_template($c, $type),
504 guide
=> $self->guideline,
505 referer
=> $c->req->path,
513 my %template_of = ( intro
=> '/qtl/qtl_form/intro.mas',
514 pop_form
=> '/qtl/qtl_form/pop_form.mas',
515 pheno_form
=> '/qtl/qtl_form/pheno_form.mas',
516 geno_form
=> '/qtl/qtl_form/geno_form.mas',
517 trait_form
=> '/qtl/qtl_form/trait_form.mas',
518 stat_form
=> '/qtl/qtl_form/stat_form.mas',
519 confirm
=> '/qtl/qtl_form/confirm.mas'
521 return \
%template_of;
526 my ($self, $c, $type) = @_;
527 return $self->templates->{$type};
532 return qq |<a href
="http://docs.google.com/View?id=dgvczrcd_1c479cgfb">Guidelines
</a
> |;
538 my $mapv_id = $c->stash->{pop}->mapversion_id();
539 my $map = CXGN
::Map
->new( $c->dbc->dbh, { map_version_id
=> $mapv_id } );
540 my $map_name = $map->get_long_name();
541 my $map_sh_name = $map->get_short_name();
543 $c->stash( genetic_map
=> qq | <a href
=/cview/map.pl?map_version_id
=$mapv_id>$map_name ($map_sh_name)</a
> | );
547 sub search_form
: PathPart
('qtl/search') Chained Args
(0) {
549 $c->res->redirect('/search/qtl');
552 sub search_results
: PathPart
('qtl/search/results') Chained Args
(0) {
554 my $trait = $c->req->param('trait');
555 $trait =~ s/(^\s+|\s+$)//g;
558 my $schema = $c->dbic_schema("Bio::Chado::Schema", "sgn_chado");
559 my $rs = $schema->resultset("Cv::Cvterm")->search(
560 { name
=> { 'LIKE' => '%'.$trait .'%'} },
561 { columns
=> [ qw
/ cvterm_id name definition/ ] },
562 {page
=> $c->req->param('page') || 1,
567 my $rows = $self->mark_qtl_traits($c, $rs);
569 $c->stash(template
=> '/qtl/search/results.mas',
571 query
=> $c->req->param('trait'),
573 page_links
=> sub {uri
( query
=> { trait
=> $c->req->param('trait'), page
=> shift } ) }
577 sub mark_qtl_traits
{
578 my ($self, $c, $rs) = @_;
587 my $qtltool = CXGN
::Phenome
::Qtl
::Tools
->new();
588 my $yes_mark = qq |<font size
=4 color
="#0033FF"> ✓</font> |;
589 my $no_mark = qq |<font size
=4 color
="#FF0000"> X
</font
> |;
591 while (my $cv = $rs->next)
593 my $id = $cv->cvterm_id;
594 my $name = $cv->name;
595 my $def = $cv->definition;
597 if ( $qtltool->is_from_qtl( $id ) )
599 push @rows, [ qq | <a href
="/chado/cvterm.pl?cvterm_id=$id">$name</a
> |, $def, $yes_mark ];
604 push @rows, [ qq | <a href
="/chado/cvterm.pl?cvterm_id=$id">$name</a
> |, $def, $no_mark ];