Sfoglia il codice sorgente

Code changes done for BLAST visualization and minor bugs & enhancements

Deepak Bitragunta 10 anni fa
parent
commit
2d90f992af

+ 1 - 1
api/blast_ui.api.inc

@@ -28,7 +28,7 @@ function get_blast_database($identifiers) {
 
   } elseif (isset($identifiers['path'])) {
 
-    $nid = db_query('SELECT nid FROM {blastdb} WHERE path=:path', array(':path' => $identifiers['path']))->fetchField();
+    $nid = db_query('SELECT nid FROM {blastdb} WHERE path LIKE :path', array(':path' => db_like($identifiers['path']) . '%'))->fetchField();
     $node = node_load($nid);
 
   }

+ 3 - 1
blast_ui.module

@@ -217,7 +217,9 @@ function show_blast_output($job_id) {
 
   // BLASTs are run as a Tripal job. As such we need to determine whether the current
   // BLAST is in the queue, running or complete in order to determine what to show the user
-  $job = tripal_get_job($job_id);
+  //decode the job_id
+  $job_id = base64_decode($job_id);
+	$job = tripal_get_job($job_id);
 
   // 1) Job is in the Queue
   if ($job->start_time === NULL AND $job->end_time == NULL) {

+ 1 - 1
includes/blast_ui.admin.inc

@@ -112,7 +112,7 @@ KRSLEEGLKTTGEGLDWGVLFGFGPGLTIETVVLRSVAI';
 /**
  * Form validator for the blastdb node
  */
-function blast_ui_validate($form, &$form_state) {
+function blast_ui_admin_form_validate($form, &$form_state) {
 	$blast_path = $form_state['values']['blast_path'];
 	$blast_path .= 'blastn';
 	if(!empty($blast_path)) {

+ 3 - 2
includes/blast_ui.form_per_program.inc

@@ -393,9 +393,10 @@ your sequence headers include pipes (i.e.: | ) they adhere to '
       $job_args,
       $user->uid
     );
-
+		// Encode job ID
+		$job_encode_id = base64_encode($job_id);
     // Redirect to the BLAST results page
-    drupal_goto("blast/report/$job_id");
+    drupal_goto("blast/report/$job_encode_id");
   }
   // We check if $error is set to TRUE because if so then the error has already
   // been reported.

+ 223 - 0
theme/blast_align_image.php

@@ -0,0 +1,223 @@
+<?PHP
+/* file: blast_align_image.php
+ * 
+ * purpose: generate an image of HSPs for a given target
+ *          
+ *          URL paramters:
+ *            acc   - target name
+ *            name  - query name, false if none
+ *            tsize - target size
+ *            qsize - query size
+ *            hits  - each hit represented in URL as: 
+ *                  targetstart_targetend_hspstart_hspend;
+ *            score - score for each hit
+ *                  
+ * Example: <url>blast_align_image.php?acc=chr2&name=query1&tsize=237068873&qsize=1411&hits=4263001_4262263_1_742;4260037_4259524_895_1411;4260405_4260248_740_897;192158716_192158843_612_742;&scores=722;473;155;51;
+ * 
+ * history:
+ *    09/23/10  Carson  created
+ *    04/16/12  eksc    adapted into POPcorn code
+ *		03/12/15	deepak	Adapted code into Tripal BLAST
+ */
+ 
+  /* include_once('../../inc/lib.php');
+   session_start();
+   $pc_system = getSystemInfoPC('sequence_search');
+  
+   $acc    = getCGIParamPC('acc',    'GP', '');
+   $scores = getCGIParamPC('scores', 'GP', '');
+   $links  = getCGIParamPC('links',  'GP', '');
+   $hits   = getCGIParamPC('hits',   'GP', '');
+   $tsize  = intval(getCGIParamPC('tsize', 'GP', ''));
+   $qsize  = intval(getCGIParamPC('qsize', 'GP', ''));
+   $name  = getCGIParamPC('name',    'GP', '');
+  */
+   // extract hit information from hit param
+function generateImage($acc = '', $scores, $hits, $tsize, $qsize, $name) {
+   $tok = strtok($hits, ";");
+   $b_hits = Array();
+   while ($tok !== false) {
+      $b_hits[] = $tok;
+      $tok = strtok(";");
+   }
+
+   // extract score information from score param
+   $tokscr = strtok($scores, ";");
+   $b_scores = Array();
+   while ($tokscr !== false) {
+     $b_scores[] = $tokscr;
+     $tokscr = strtok(";");
+   }
+
+   // image measurements
+   $height = 200 + (count($b_hits) * 16);
+   $width  = 520;
+
+   $img = imagecreatetruecolor($width, $height);
+   
+   $white      = imagecolorallocate($img, 255, 255, 255);
+   $black      = imagecolorallocate($img, 0, 0, 0);
+   $darkgray   = imagecolorallocate($img, 100, 100, 100);
+   $strong     = imagecolorallocatealpha($img, 202, 0, 0, 15);
+   $moderate   = imagecolorallocatealpha($img, 204, 102, 0, 20);
+   $present    = imagecolorallocatealpha($img, 204, 204, 0, 35);
+   $weak       = imagecolorallocatealpha($img, 102, 204, 0, 50);
+   $gray       = imagecolorallocate($img, 190, 190, 190);
+   $lightgray  = imagecolorallocate($img, 230, 230, 230);
+   
+   imagefill($img, 0, 0, $lightgray);
+   
+   // Target coordinates
+   $maxlength = 300;
+   $t_length = ($tsize > $qsize) 
+                  ? $maxlength : $maxlength - 50;
+   $q_length = ($qsize > $tsize) 
+                  ? $maxlength : $maxlength - 50;
+                  
+   $tnormal = $t_length / $tsize;
+   $qnormal = $q_length / $qsize; 
+  
+   $t_ystart = 30;
+   $t_yend   = $t_ystart + 20;
+  
+   $t_xstart = 50;
+   $t_xend   = $t_xstart + $t_length;
+   $t_center = $t_xstart + ($t_length / 2);
+   
+   // Target labels
+   $warn = " (not to scale)";
+   imagestring($img, 5, $t_xstart, $t_ystart-20, $acc.$warn, $black);
+   imagestring($img, 3, 5, $t_ystart+2, "Target", $black);
+   
+   // Draw bar representing target
+   imagefilledrectangle($img, $t_xstart, $t_ystart, $t_xend, $t_yend, $gray);
+   imagerectangle($img, $t_xstart, $t_ystart, $t_xend, $t_yend, $darkgray);
+   
+   // query coordinates
+   $q_maxheight = 250;
+   $q_ystart = $t_yend + 100;
+   $q_yend = $q_ystart + 20;
+  
+   $q_xstart = $t_center - $q_length / 2;
+   $q_xend = $q_xstart + $q_length;
+
+   $q_center = ($q_xend + $q_xstart) / 2;
+   $q_xwidth = $q_xend - $q_xstart;
+
+   // Query labels
+   imagestring($img, 5, $q_xstart, $q_yend+2, $name.$warn, $black);
+   imagestring($img, 3, 5, $q_ystart+2, 'Query', $black);
+   
+   // Draw bar representing query
+   imagefilledrectangle($img, $q_xstart, $q_ystart, $q_xend, $q_yend, $gray);
+   imagerectangle($img ,$q_xstart, $q_ystart, $q_xend, $q_yend, $darkgray);
+   
+   // HSP bars will start here
+   $hsp_bary = $q_yend + 20;
+   
+   // Draw solids for HSP alignments
+   for ($ii=count($b_hits)-1; $ii>=0; $ii--) {
+      // alignment 
+	
+   	$cur_hit = $b_hits[$ii];
+   	$cur_score = intval($b_scores[$ii]);
+   	
+   	// set color according to score
+   	$cur_color = $darkgray;
+   	if ($cur_score > 200) { 
+   		$cur_color = $strong;
+   	} 
+   	else if ($cur_score > 80 && $cur_score <= 200) { 
+   		$cur_color = $moderate;
+   	} 
+   	else if ($cur_score > 50 && $cur_score <= 80) { 
+   		$cur_color = $present;
+   	} 
+   	else if ($cur_score > 40 && $cur_score <= 50) { 
+   		$cur_color = $weak;
+   	} 
+	
+	   $t_start = $tnormal *  intval(strtok($cur_hit, "_")) + $t_xstart;
+      $t_end = $tnormal *  intval(strtok("_")) + $t_xstart;
+      $q_start = $qnormal * intval(strtok("_")) + $q_xstart;
+      $q_end = $qnormal *  intval(strtok("_")) + $q_xstart;
+		
+      $hit1_array = array($t_start, $t_yend, $t_end, $t_yend, $q_end, 
+                          $q_ystart, $q_start, $q_ystart);
+
+	   // HSP coords
+      imagefilledpolygon($img, $hit1_array, 4, $cur_color);
+	
+   }//each hit
+
+   // Draw lines over fills for HSP alignments
+   for ($ii=0; $ii<count($b_hits); $ii++) {
+   	// alignment 
+   	
+   	$cur_hit = $b_hits[$ii];
+   	$t_start = $tnormal *  intval(strtok($cur_hit, "_")) + $t_xstart;
+      $t_end = $tnormal *  intval(strtok("_")) + $t_xstart;
+      $q_start = $qnormal * intval(strtok("_")) + $q_xstart;
+      $q_end = $qnormal *  intval(strtok("_")) + $q_xstart;
+   		
+   	$hit1_array = array($t_start, $t_yend, $t_end, $t_yend, $q_end, $q_ystart,
+   	                    $q_start, $q_ystart,);
+   
+   	imagerectangle($img, $t_start, $t_ystart, $t_end, $t_yend, $black);
+   	imagerectangle($img, $q_start, $q_ystart, $q_end, $q_yend, $black);
+   	imagepolygon ($img, $hit1_array, 4, $black);
+
+      // show HSP
+      
+ 		imagestring($img, 3, 2, $hsp_bary, ($acc ."Hit" . $ii), $black);
+
+   	$cur_score = intval($b_scores[$ii]);
+   	
+   	// set color according to score
+   	$cur_color = $darkgray;
+   	if ($cur_score > 200) { 
+   		$cur_color = $strong;
+   	} 
+   	else if ($cur_score > 80 && $cur_score <= 200) { 
+   		$cur_color = $moderate;
+   	} 
+   	else if ($cur_score > 50 && $cur_score <= 80) { 
+   		$cur_color = $present;
+   	} 
+   	else if ($cur_score > 40 && $cur_score <= 50) { 
+   		$cur_color = $weak;
+   	}
+   	
+   	imagefilledrectangle($img, $q_start, $hsp_bary, $q_end, $hsp_bary+10, $cur_color);
+      $hsp_bary += 15;
+   }//each hit
+
+   // Draw the key
+   
+   $xchart = 390;
+   $ychart = 10;
+   $fontsize = 4;
+   $yinc = 20;
+   $ywidth = 7;
+   $xinc = 10;
+   
+   imagestring($img, 5, $xchart, $ychart - 5, "Scores", $black);
+   
+   imagestring($img, $fontsize, $xchart + $yinc + $xinc,$ychart + ($yinc * 1) + $ywidth, ">= 200" , $black);
+   imagestring($img, $fontsize, $xchart + $yinc + $xinc,$ychart + ($yinc * 2) + $ywidth, "80 - 200" , $black);
+   imagestring($img, $fontsize, $xchart + $yinc + $xinc,$ychart + ($yinc * 3) + $ywidth, "50 - 80" , $black);
+   imagestring($img, $fontsize, $xchart + $yinc + $xinc,$ychart + ($yinc * 4) + $ywidth, "40 - 50" , $black);
+   imagestring($img, $fontsize, $xchart + $yinc + $xinc,$ychart + ($yinc * 5) + $ywidth, "< 40" , $black);
+   
+   imagefilledRectangle($img, $xchart, $ychart + ($yinc * 1) + $xinc, $xchart + $yinc, $ychart + ($yinc * 2), $strong);
+   imagefilledRectangle($img, $xchart, $ychart + ($yinc * 2) + $xinc, $xchart + $yinc, $ychart + ($yinc * 3), $moderate);
+   imagefilledRectangle($img, $xchart, $ychart + ($yinc * 3) + $xinc, $xchart + $yinc, $ychart + ($yinc * 4), $present);
+   imagefilledRectangle($img, $xchart, $ychart + ($yinc * 4) + $xinc, $xchart + $yinc, $ychart + ($yinc * 5), $weak);
+   imagefilledRectangle($img, $xchart, $ychart + ($yinc * 5) + $xinc, $xchart + $yinc, $ychart + ($yinc * 6), $darkgray);
+   
+	 return $img;
+  // write out images
+//    header("Content-type: image/png");
+//    imagepng($img);
+}
+?>

+ 67 - 22
theme/blast_report.tpl.php

@@ -75,7 +75,7 @@ $no_hits = TRUE;
 about each hit including the alignment, click on that row in the table to expand it.</p>
 
 <?php
-
+include_once("blast_align_image.php");
 // Load the XML file
 $xml = simplexml_load_file($xml_filename);
 
@@ -88,7 +88,7 @@ if ($xml) {
   // Specify the header of the table
   $header = array(
     'number' =>  array('data' => '#', 'class' => array('number')),
-    'query' =>  array('data' => 'Query Name', 'class' => array('query')),
+    'query' =>  array('data' => 'Query Name  (Click for alignment & visualization)', 'class' => array('query')),
     'hit' =>  array('data' => 'Hit Name', 'class' => array('hit')),
     'evalue' =>  array('data' => 'E-Value', 'class' => array('evalue')),
     'arrow-col' =>  array('data' => '', 'class' => array('arrow-col'))
@@ -102,6 +102,13 @@ if ($xml) {
   // significance and 2) additional information including the alignment
   foreach($xml->{'BlastOutput_iterations'}->children() as $iteration) {
     $children_count = $iteration->{'Iteration_hits'}->children()->count();
+		//@deepaksomanadh: Code added for BLAST visualization
+		// parameters that need to be passed for BLAST image generation
+		$target_name = '';
+		$q_name = $xml->{'BlastOutput_query-def'};
+		$query_size = $xml->{'BlastOutput_query-len'};
+		$target_size = $iteration->{'Iteration_stat'}->{'Statistics'}->{'Statistics_db-len'};
+		
     if($children_count != 0) {
       foreach($iteration->{'Iteration_hits'}->children() as $hit) {
         if (is_object($hit)) {
@@ -109,23 +116,45 @@ if ($xml) {
           $zebra_class = ($count % 2 == 0) ? 'even' : 'odd';
           $no_hits = FALSE;
 
-          // RETRIEVE INFO
-          $hit_name = (preg_match('/BL_ORD_ID/', $hit->{'Hit_id'})) ? $hit->{'Hit_def'} : $hit->{'Hit_id'};
-          $score = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_score'};
-          $evalue = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_evalue'};
-          $query_name = $iteration->{'Iteration_query-def'};
-
-          $HSPs = array();
-          foreach ($hit->{'Hit_hsps'}->children() as $hsp_xml) {
-            $HSPs[] = (array) $hsp_xml;
-          }
-
-          // SUMMARY ROW
-          // If the id is of the form gnl|BL_ORD_ID|### then the parseids flag
-          // to makeblastdb did a really poor job. In thhis case we want to use
-          // the def to provide the original FASTA header.
-
-
+					// RETRIEVE INFO
+          $hit_name = (preg_match('/BL_ORD_ID/', $hit->{'Hit_id'})) ? $hit->{'Hit_def'} : $hit->{'Hit_id'};	
+					$score = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_score'};
+					$evalue = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_evalue'};
+				  $query_name = $iteration->{'Iteration_query-def'};
+
+					// Round e-val to two decimal values
+					$rounded_evalue = '';
+					if (strpos($evalue,'e') != false) {
+					 $evalue_split = explode('e', $evalue);
+					 $rounded_evalue = round($evalue_split[0], 2, PHP_ROUND_HALF_EVEN);				    
+						 $rounded_evalue .= 'e' . $evalue_split[1];
+					}
+					else { 
+							$rounded_evalue = $evalue;
+					}				
+				
+				  // ALIGNMENT ROW (collapsed by default)
+					// Process HSPs
+					// @deepaksomanadh: Code added for BLAST visualization
+					// hit array and corresponding bit scores 
+					// hits=4263001_4262263_1_742;4260037_4259524_895_1411;&scores=722;473;
+					$HSPs = array();
+					$hit_hsps = '';
+					$hit_hsp_score = '';		
+					foreach ($hit->{'Hit_hsps'}->children() as $hsp_xml) {
+						$HSPs[] = (array) $hsp_xml;
+		
+						$hit_hsps .=  $hsp_xml->{'Hsp_hit-from'} . '_' . $hsp_xml->{'Hsp_hit-to'}  
+														. '_' . $hsp_xml->{'Hsp_query-from'} . '_'
+														. $hsp_xml->{'Hsp_query-to'} . ';';	
+						$Hsp_bit_score .= 	$hsp_xml->{'Hsp_bit-score'} .';';							
+
+					}	 
+					// SUMMARY ROW
+					// If the id is of the form gnl|BL_ORD_ID|### then the parseids flag
+					// to makeblastdb did a really poor job. In this case we want to use
+					// the def to provide the original FASTA header.
+					
           // If our BLAST DB is configured to handle link-outs then use the
           // regex & URL prefix provided to create one.
           if ($linkout) {
@@ -157,12 +186,25 @@ if ($xml) {
             }
           }
 
+					//@deepaksomanadh: Code added for BLAST visualization
+					// get the image and display
+					$hit_img = generateImage($target_name, $Hsp_bit_score, $hit_hsps, $target_size, $query_size, $q_name);
+				
+					ob_start(); // Start buffering the output
+					imagepng($hit_img, null, 0, PNG_NO_FILTER);
+					$b64 = base64_encode(ob_get_contents()); // Get what we've just outputted and base64 it
+					imagedestroy($hit_img);
+					ob_end_clean();
+
+					// Print the HTML tag with the image embedded
+					$hit_img = '<h3> Hit Visualization </h3> <br><img src="data:image/png;base64,'.$b64.'"/>';
+					
           $row = array(
             'data' => array(
               'number' => array('data' => $count, 'class' => array('number')),
               'query' => array('data' => $query_name, 'class' => array('query')),
               'hit' => array('data' => $hit_name, 'class' => array('hit')),
-              'evalue' => array('data' => $evalue, 'class' => array('evalue')),
+              'evalue' => array('data' => $rounded_evalue, 'class' => array('evalue')),
               'arrow-col' => array('data' => '<div class="arrow"></div>', 'class' => array('arrow-col'))
             ),
             'class' => array('result-summary')
@@ -177,8 +219,11 @@ if ($xml) {
               'number' => '',
               'query' => array(
                 'data' => theme('blast_report_alignment_row', array('HSPs' => $HSPs)),
-                'colspan' => 4,
-              )
+              ),
+							'hit' => array(
+                'data' => $hit_img,
+                'colspan' => 3,
+              ),
             ),
             'class' => array('alignment-row', $zebra_class),
             'no_striping' => TRUE

+ 29 - 19
theme/blast_report_alignment_row.tpl.php

@@ -19,11 +19,11 @@
   <div class="alignment-metrics">
     <span class="identity">
       Identity=&nbsp;
-      <?php print $hsp['Hsp_identity']; ?>/<?php print $hsp['Hsp_align-len']; ?> (<?php print $hsp['Hsp_identity']/$hsp['Hsp_align-len']*100;?>%)
+      <?php print $hsp['Hsp_identity']; ?>/<?php print $hsp['Hsp_align-len']; ?> (<?php print round($hsp['Hsp_identity']/$hsp['Hsp_align-len']*100, 2, PHP_ROUND_HALF_EVEN);?>%)
     </span>,&nbsp;
     <span class="positive">
       Positive=&nbsp;
-      <?php print $hsp['Hsp_positive']; ?>/<?php print $hsp['Hsp_align-len']; ?> (<?php print $hsp['Hsp_positive']/$hsp['Hsp_align-len']*100;?>%)
+      <?php print $hsp['Hsp_positive']; ?>/<?php print $hsp['Hsp_align-len']; ?> (<?php print round($hsp['Hsp_positive']/$hsp['Hsp_align-len']*100, 2, PHP_ROUND_HALF_EVEN);?>%)
     </span>
     <span class="coord-summary">
       Query Matches <?php print $hsp['Hsp_query-from'] . ' to ' . $hsp['Hsp_query-to']; ?>
@@ -46,23 +46,33 @@
       foreach (array_keys($query) as $k) {
         // Determine the current coordinates.
         $coord['qstart'] = $hsp['Hsp_query-from'] + ($k * 60);
-        $coord['qstart'] = ($k == 0) ? $coord['qstart'] : $coord['qstart'] + 1;
-
-        $coord['hstart'] = $hsp['Hsp_hit-from'] + ($k * 60);
-        $coord['hstart'] = ($k == 0) ? $coord['hstart'] : $coord['hstart'] + 1;
-
-        $coord['qstop'] = $hsp['Hsp_query-from'] + (($k + 1) * 60);
-        $coord['qstop'] = ($coord['qstop'] > $hsp['Hsp_query-to']) ? $hsp['Hsp_query-to'] : $coord['qstop'];
-
-	$coord['hstop'] = $hsp['Hsp_hit-from'] + (($k + 1) * 60);
-        $coord['hstop'] = ($coord['hstop'] > $hsp['Hsp_hit-to']) ? $hsp['Hsp_hit-to'] : $hsp['Hsp_hit-from'];
-
-        // Pad these coordinates to ensure columned display.
-        foreach ($coord as $ck => $val) {
-          $pad_type = (preg_match('/start/', $ck)) ? STR_PAD_LEFT : STR_PAD_RIGHT;
-          $coord[$ck] = str_pad($val, $coord_length, '#', $pad_type);
-          $coord[$ck] =	str_replace('#', '&nbsp', $coord[$ck]);
-        }
+        $coord['qstart'] = ($k == 0) ? $coord['qstart'] : $coord['qstart'];
+				// code added to fix the range issue
+				// Cordinates can increase or decrease
+				if($hsp['Hsp_hit-from'] < $hsp['Hsp_hit-to']) {
+							$coord['hstart'] = $hsp['Hsp_hit-from'] + ($k * 60);		
+					}
+					else {
+									$coord['hstart'] = $hsp['Hsp_hit-from'] - ($k * 60);
+						}
+					$coord['qstop'] = $hsp['Hsp_query-from'] + (($k + 1) * 60) - 1;
+					$coord['qstop'] = ($coord['qstop'] > $hsp['Hsp_query-to']) ? $hsp['Hsp_query-to'] : $coord['qstop'];
+			
+					if($hsp['Hsp_hit-from'] < $hsp['Hsp_hit-to']) {
+							$coord['hstop'] = $hsp['Hsp_hit-from'] + (($k + 1) * 60) - 1;
+							$coord['hstop'] = ($coord['hstop'] > $hsp['Hsp_hit-to']) ? $hsp['Hsp_hit-to'] : $coord['hstop'];
+					
+					}
+					else {
+								$coord['hstop'] = $hsp['Hsp_hit-from'] - (($k + 1) * 60) + 1;
+								$coord['hstop'] = ($coord['hstop'] < $hsp['Hsp_hit-to']) ? $hsp['Hsp_hit-to'] : $coord['hstop'];
+					}
+					// Pad these coordinates to ensure columned display.
+					foreach ($coord as $ck => $val) {
+						$pad_type = (preg_match('/start/', $ck)) ? STR_PAD_LEFT : STR_PAD_RIGHT;
+						$coord[$ck] = str_pad($val, $coord_length, '#', $pad_type);
+						$coord[$ck] =	str_replace('#', '&nbsp', $coord[$ck]);
+	        }
       ?>
         <div class="alignment-subrow">
           <div class="query">

+ 1 - 0
theme/css/blast_report.css

@@ -20,6 +20,7 @@
 }
 #blast_report tr.odd td {
   cursor:pointer;
+	vertical-align : top;
 }
 #blast_report .arrow {
   background:transparent url('../images/arrows.png') no-repeat scroll 0px -16px;