calc plot pheno
[sgn.git] / lib / SGN / Controller / AJAX / DeriveTrait.pm
blob1bf0ff2b41bdf7472e9e087287ac1ffe02d54cfc
1 package SGN::Controller::AJAX::DeriveTrait;
3 use Moose;
4 use Data::Dumper;
5 use List::Util 'max';
6 use Bio::Chado::Schema;
7 use List::Util qw | any sum |;
8 use DBI;
9 use DBIx::Class;
10 use SGN::Model::Cvterm;
11 use JSON;
12 use POSIX;
14 BEGIN {extends 'Catalyst::Controller::REST'}
16 __PACKAGE__->config(
17 default => 'application/json',
18 stash_key => 'rest',
19 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
22 has 'trial_id' => (isa => 'Int',
23 is => 'rw',
24 reader => 'get_trial_id',
25 writer => 'set_trial_id',
29 sub get_all_derived_trait : Path('/ajax/breeders/trial/trait_formula') Args(0) {
30 my $self = shift;
31 my $c = shift;
32 my $schema = $c->dbic_schema('Bio::Chado::Schema');
33 my $dbh = $c->dbc->dbh();
34 my (@cvterm_ids, @derived_traits, @formulas, @derived_traits_array, @trait_ids, @trait_db_ids, @formulas_array, @formulas_array_msg, $formula_json_array);
36 my $h = $dbh->prepare("select cvterm.name, cvterm.cvterm_id, a.value, dbxref.accession, db.name from cvterm join cvtermprop as a using(cvterm_id) join dbxref using(dbxref_id) join db using(db_id) join cvterm as b on (a.type_id=b.cvterm_id) where b.name='formula';");
38 $h->execute();
39 while (my ($cvterm_id, $derived_trait, $derived_trait_formula, $trait_id, $trait_db_id) = $h->fetchrow_array()) {
40 push @cvterm_ids, $cvterm_id;
41 push @derived_traits, $derived_trait;
42 push @formulas, $derived_trait_formula;
43 push @trait_ids, $trait_id;
44 push @trait_db_ids, $trait_db_id;
47 for (my $n=0; $n<scalar(@derived_traits); $n++) {
48 push @formulas_array, $formulas[$n];
49 push @derived_traits_array, $cvterm_ids[$n]."|".$trait_db_ids[$n].":".$trait_ids[$n];
52 print STDERR Dumper (@formulas_array);
53 $c->stash->{rest} = { derived_traits => \@derived_traits_array, formula => \@formulas_array };
57 sub compute_derive_traits : Path('/ajax/phenotype/create_derived_trait') Args(0) {
59 my $self = shift;
60 my $c = shift;
61 my $trial_id = $c->req->param('trial_id');
62 my $selected_trait = $c->req->param('trait');
63 my %parse_result;
64 my $trait_found;
65 my $time = DateTime->now();
66 my $timestamp = $time->ymd()."_".$time->hms();
68 print "TRAIT NAME: $selected_trait\n";
69 print "TRIAl ID: $trial_id\n";
71 my $schema = $c->dbic_schema('Bio::Chado::Schema');
72 my $selected_trait_cvterm = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, $selected_trait);
73 if (!$selected_trait_cvterm) {
74 print STDERR "The trait $selected_trait is not in the database.\n";
77 my $selected_trait_cvterm_id = $selected_trait_cvterm->cvterm_id();
78 print "Selected Trait Cvterm_id: $selected_trait_cvterm_id\n";
80 if (!$c->user()) {
81 print STDERR "User not logged in... not computing trait.\n";
82 $c->stash->{rest} = {error => "You need to be logged in to compute trait." };
83 return;
86 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
87 $c->stash->{rest} = {error => "You have insufficient privileges to compute trait." };
88 return;
91 my $trait_id = shift;
92 my $trial = CXGN::Trial->new({ bcs_schema => $schema,
93 trial_id => $trial_id
94 });
96 my $triat_name = $trial->get_traits_assayed();
98 print STDERR Dumper($triat_name);
101 if (scalar(@{$triat_name}) == 0) {
102 $c->stash->{rest} = {error => "No trait assayed for this trial." };
103 return;
107 foreach $trait_found (@{$triat_name}) {
108 if ($selected_trait_cvterm_id && ($trait_found->[0] eq $selected_trait_cvterm_id)) {
109 print "Trait found = $trait_found->[1] with id $trait_found->[0]\n";
110 $c->stash->{rest} = {error => "$trait_found->[1] has been computed and uploaded for this trial." };
111 return;
114 elsif ($selected_trait_cvterm_id eq '') {
115 $c->stash->{rest} = {error => "Select trait to compute." };
116 return;
120 my $dbh = $c->dbc->dbh();
121 my @plots;
122 my %data;
123 my @traits;
124 my @trait_cvterm_id;
125 my $trait = 0;
126 my $counter_trait = 0;
127 push @traits, $selected_trait;
129 my (@cvterm_ids, @formulas, @regres, $formula_json_array, @formulas_array_msg, $eval_formula, $msg_formula);
131 my $h = $dbh->prepare("select cvterm.cvterm_id, a.value from cvterm join cvtermprop as a using(cvterm_id) join cvterm as b on (a.type_id=b.cvterm_id) where b.name='formula';");
133 $h->execute();
134 while (my ($cvterm_id, $derived_trait_formula ) = $h->fetchrow_array()) {
135 push @cvterm_ids, $cvterm_id;
136 push @formulas, $derived_trait_formula;
140 for (my $n=0; $n<scalar(@formulas); $n++) {
141 if ($selected_trait_cvterm_id eq $cvterm_ids[$n]) {
142 print "formula_msg: $formulas[$n]\n";
143 $msg_formula = $formulas[$n];
148 my @dependent_trait_ids;
149 my ($db_id, $accession, @traits_cvterm_ids, $cvterm_id, @found_trait_cvterm_ids, @accessions, @trait_values);
150 my (%hash1, %hash2, %hash3, @trait_values1, @trait_values2, @trait_values3);
151 while ($msg_formula =~ /(\w{2}\:\d+)/g){
152 push @dependent_trait_ids, [$1];
153 ($db_id,$accession) = split (/:/, $1);
154 push @accessions, $accession;
156 print "DB ID: $db_id\n";
157 #print STDERR Dumper (\@dependent_trait_ids);
158 foreach my $accession (@accessions) {
159 my $h1 = $dbh->prepare("select cvterm.cvterm_id from cvterm join dbxref using(dbxref_id) join db using(db_id) where dbxref.accession=? and db.name=?;");
161 $h1->execute($accession, $db_id);
162 while ($cvterm_id = $h1->fetchrow_array()) {
163 push @traits_cvterm_ids, $cvterm_id;
166 #print STDERR Dumper (\@traits_cvterm_ids);
167 for (my $x=0; $x<scalar(@traits_cvterm_ids); $x++){
168 foreach $trait_found (@{$triat_name}) {
169 if ($trait_found->[0] eq $traits_cvterm_ids[$x]) {
170 push @found_trait_cvterm_ids, $trait_found->[0];
175 while ($msg_formula =~ /([\w\s-]+\|\w{2}\:\d+)/g){
176 my $full_name = $1;
177 if ($full_name =~ m/\s-\s/g){
178 $full_name =~ s/-\s//g;
180 push @regres, $full_name;
182 print STDERR Dumper (\@regres);
183 my ($stock_name, $stock_id, $plot_name, $value);
184 if (@found_trait_cvterm_ids != @traits_cvterm_ids) {
185 $c->stash->{rest} = {error => "Upload or compute trait(s) required for computing \n\n$selected_trait = $msg_formula." };
186 return;
188 else {
190 print Dumper (\@found_trait_cvterm_ids);
191 my $h2 = $dbh->prepare("SELECT object.uniquename AS stock_name, object.stock_id AS stock_id, me.uniquename AS plot_name, phenotype.value FROM stock me LEFT JOIN
192 nd_experiment_stock nd_experiment_stocks ON nd_experiment_stocks.stock_id =
193 me.stock_id LEFT JOIN nd_experiment nd_experiment ON nd_experiment.nd_experiment_id = nd_experiment_stocks.nd_experiment_id LEFT JOIN nd_experiment_phenotype nd_experiment_phenotypes ON nd_experiment_phenotypes.nd_experiment_id = nd_experiment.nd_experiment_id LEFT JOIN phenotype phenotype ON phenotype.phenotype_id =
194 nd_experiment_phenotypes.phenotype_id LEFT JOIN cvterm observable ON
195 observable.cvterm_id = phenotype.observable_id LEFT JOIN nd_experiment_project
196 nd_experiment_projects ON nd_experiment_projects.nd_experiment_id =
197 nd_experiment.nd_experiment_id LEFT JOIN project project ON project.project_id =
198 nd_experiment_projects.project_id LEFT JOIN stock_relationship
199 stock_relationship_subjects ON stock_relationship_subjects.subject_id =
200 me.stock_id LEFT JOIN stock object ON object.stock_id =
201 stock_relationship_subjects.object_id WHERE ( ( observable.cvterm_id =? AND
202 project.project_id=? ) );");
204 my @array;
205 my %cvterm_hash;
206 my %plot_hash;
207 my %valid_plots;
208 foreach (@found_trait_cvterm_ids) {
209 $h2->execute($_, $trial_id);
210 while ( ($stock_name, $stock_id, $plot_name, $value) = $h2->fetchrow_array()) {
211 $cvterm_hash{$_}->{$plot_name} = $value;
212 $plot_hash{$plot_name}->{$_} = $value;
214 @array, $cvterm_hash{$_}->{$plot_name};
218 foreach my $plot_name (keys %plot_hash) {
219 my $valid_plot_check = 1;
220 my @value_array;
221 foreach (@found_trait_cvterm_ids) {
222 if (!exists ($plot_hash{$plot_name}->{$_})) {
223 $valid_plot_check = 0;
225 push @value_array, $plot_hash{$plot_name}->{$_};
228 if ($valid_plot_check) {
229 $valid_plots{$plot_name} = \@value_array;
230 push @plots, $plot_name;
234 foreach my $valid_plot_name (keys %valid_plots){
235 my $value_array = $valid_plots{$valid_plot_name};
236 print STDERR Dumper $value_array;
237 my %map_hash;
238 for( my $i =0; $i<scalar(@regres); $i++) {
239 $map_hash{$regres[$i]} = $value_array->[$i];
241 print STDERR Dumper \%map_hash;
242 my $msg_formula_sub = $msg_formula;
243 foreach my $full_trait (keys %map_hash) {
244 $full_trait =~ /([\w\s-]+)\|(\w{2}\:\d+)/g;
245 print STDERR Dumper $full_trait;
246 $msg_formula_sub =~ s/($1\|$2)/$map_hash{$full_trait}/g;
248 print STDERR Dumper $msg_formula_sub;
249 my $calc_value = eval "$msg_formula_sub";
250 print STDERR Dumper $calc_value;
251 $data{$valid_plot_name}->{$selected_trait} = [$calc_value,$timestamp];
256 print STDERR Dumper (\%data);
257 print STDERR Dumper (\@plots);
258 print STDERR Dumper (\@traits);
260 $parse_result{'data'} = \%data;
261 $parse_result{'plots'} = \@plots;
262 $parse_result{'traits'} = \@traits;
264 my $size = scalar(@plots) * scalar(@traits);
265 my %phenotype_metadata;
266 $phenotype_metadata{'archived_file'} = 'none';
267 $phenotype_metadata{'archived_file_type'}="generated from derived traits";
268 $phenotype_metadata{'operator'}=$c->user()->get_object()->get_sp_person_id();
269 $phenotype_metadata{'date'}="$timestamp";
271 my $store = CXGN::Phenotypes::StorePhenotypes->store($c, $size, \@plots, \@traits, \%data, \%phenotype_metadata);
274 $c->stash->{rest} = {success => 1};
278 sub generate_plot_phenotypes : Path('/ajax/breeders/trial/generate_plot_phenotypes') Args(0) {
279 my $self = shift;
280 my $c = shift;
281 my $trial_id = $c->req->param('trial_id');
282 my $trait_id = $c->req->param('trait_id');
283 my $method = $c->req->param('method');
284 my $rounding = $c->req->param('rounding');
285 print STDERR "Trial: $trial_id\n";
286 print STDERR "Trait: $trait_id\n";
287 print STDERR "Method: $method\n";
288 print STDERR "Round: $rounding\n";
289 my $schema = $c->dbic_schema('Bio::Chado::Schema');
291 my $trial = CXGN::Trial->new( { bcs_schema => $schema, trial_id => $trial_id });
292 my $plant_phenotypes_for_trait = $trial->get_stock_phenotypes_for_trait($trait_id, 'plant', 'plant_of', 'plot');
293 print STDERR Dumper $plant_phenotypes_for_trait;
295 my %plot_plant_values;
296 foreach (@$plant_phenotypes_for_trait) {
297 my @value_array;
298 my $plot_id = $_->[5];
299 if (exists($plot_plant_values{$plot_id})) {
300 @value_array = @{$plot_plant_values{$plot_id}};
302 push @value_array, $_->[4];
303 $plot_plant_values{$plot_id} = \@value_array;
305 print STDERR Dumper \%plot_plant_values;
307 my @return;
308 foreach my $plot_id (keys %plot_plant_values) {
309 my %info;
310 $info{'method'} = $method;
311 if ($method eq 'arithmetic_mean') {
312 my $average = $self->_get_mean($plot_plant_values{$plot_id});
313 $info{'plant_values'} = $plot_plant_values{$plot_id};
314 $info{'output'} = $average;
315 $info{'value_to_store'} = $average;
316 $info{'notes'} = '';
318 if ($method eq 'mode') {
319 my $modes = $self->_get_mode($plot_plant_values{$plot_id});
320 $info{'plant_values'} = $plot_plant_values{$plot_id};
321 $info{'output'} = encode_json($modes);
322 if (scalar(@$modes > 1)) {
323 $info{'notes'} = 'More than one mode!';
324 $info{'value_to_store'} = '';
325 } else {
326 $info{'notes'} = 'A single mode was found!';
327 $info{'value_to_store'} = $modes->[0];
330 if ($method eq 'maximum') {
331 my $maximum = $self->_get_max($plot_plant_values{$plot_id});
332 $info{'plant_values'} = $plot_plant_values{$plot_id};
333 $info{'output'} = $maximum;
334 $info{'value_to_store'} = $maximum;
335 $info{'notes'} = '';
337 if ($method eq 'minimum') {
338 my $minimum = $self->_get_min($plot_plant_values{$plot_id});
339 $info{'plant_values'} = $plot_plant_values{$plot_id};
340 $info{'output'} = $minimum;
341 $info{'value_to_store'} = $minimum;
342 $info{'notes'} = '';
344 if ($method eq 'median') {
345 my $median = $self->_get_median(@{$plot_plant_values{$plot_id}});
346 $info{'plant_values'} = $plot_plant_values{$plot_id};
347 $info{'output'} = $median;
348 $info{'value_to_store'} = $median;
349 $info{'notes'} = '';
351 push @return, \%info;
353 print STDERR Dumper \@return;
354 $c->stash->{rest} = {success => 1, info=>\@return};
357 sub _get_mean {
358 my $self = shift;
359 my $array = shift;
360 my $sum = 0;
361 foreach (@$array) {
362 $sum += $_;
364 my $average = $sum/scalar(@$array);
365 return $average;
368 sub _get_max {
369 my $self = shift;
370 my $array = shift;
371 my @sorted = sort {$b <=> $a} @$array;
372 my $max = $sorted[0];
373 return $max;
376 sub _get_min {
377 my $self = shift;
378 my $array = shift;
379 my @sorted = sort {$a <=> $b} @$array;
380 my $min = $sorted[0];
381 return $min;
384 sub _get_mode {
385 my $self = shift;
386 my $array = shift;
387 my %count;
388 my @modes;
389 map{ $count{$_}++ } @$array;
390 my @values;
391 my $top=0;
392 for my $k ( sort {$count{$b} <=> $count{$a}} keys %count ) {
393 #first element has highest count
394 if ($count{$k} >= $top) {
395 $top = $count{$k};
396 push @modes, $k;
399 return \@modes;
402 sub _get_median {
403 my $self = shift;
404 my $median = sum( ( sort { $a <=> $b } @_ )[ int( $#_/2 ), ceil( $#_/2 ) ] )/2;
406 return $median;