Просмотр исходного кода

Merge pull request #1 from deepakbitragunta/7.x-1.x

Code changes done for BLAST visualization and minor bugs & enhancements
ekcannon 9 лет назад
Родитель
Сommit
ed851bc355

+ 3 - 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);
 
   }
@@ -124,6 +124,8 @@ function run_BLAST_tripal_job($program, $query, $database, $output_filestub, $op
   // Allow administrators to use an absolute path for these commands.
   // Defaults to using $PATH.
 	$blast_path = variable_get('blast_path', '');
+	$blast_threads = variable_get('blast_threads', '');
+	
 	$program = 	$blast_path . $program;
 	$blast_formatter_command = $blast_path .  'blast_formatter';
 

+ 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) {

+ 8 - 2
includes/blast_ui.admin.inc

@@ -38,6 +38,12 @@ function blast_ui_admin_form($form, $form_state) {
         FALSE
       )
   );
+	$form['general']['blast_threads']= array(
+    '#type' => 'textfield',
+    '#title' => t('Enter the number of CPU threads to use in blast search.'),
+    '#description' => t('You can increase the number to reduce the search time. Before you increase, please check your hardware configurations . A value of one(1) can result in a slower search for some programs eg. tblastn.'),
+    '#default_value' => variable_get('blast_threads', 1),
+  );
 
   $form['example_sequence'] = array(
     '#type' => 'fieldset',
@@ -112,7 +118,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)) {
@@ -132,7 +138,7 @@ function blast_ui_validate($form, &$form_state) {
 function blast_ui_admin_form_submit($form, $form_state) {
 
   variable_set('blast_ui_allow_target_upload', $form_state['values']['target_upload']);
-
+	variable_set('blast_threads', $form_state['values']['blast_threads']);
   variable_set('blast_ui_nucleotide_example_sequence', $form_state['values']['nucleotide_example']);
   variable_set('blast_ui_protein_example_sequence', $form_state['values']['protein_example']);
 }

+ 56 - 4
includes/blast_ui.form_per_program.inc

@@ -19,7 +19,16 @@ function blast_ui_per_blast_program_form($form, $form_state) {
 	$form['#attached']['css'] = array(
 		drupal_get_path('module', 'blast_ui') . '/theme/css/form.css',
 	);
-
+	
+  // @deepaksomanadh - Code added for edit and resubmit funcitonality
+	// 	Approach: persist the form data and read it back using JobID
+	$job_data = variable_get('job_data', '');
+	if(isset($_GET['jid']) && isset($job_data)) {		
+			$jid = base64_decode($_GET['jid']);
+	}	else {
+			$job_data = array();
+			$jid = 0;
+	}
   // Determine the BLAST program.
   $query_type = $form_state['build_info']['args'][0];
   $db_type = $form_state['build_info']['args'][1];
@@ -102,6 +111,7 @@ function blast_ui_per_blast_program_form($form, $form_state) {
     '#type' => 'textarea',
     '#title' => t('Enter FASTA sequence(s)'),
     '#description'=>t('Enter query sequence(s) in the text area.'),
+		'#default_value' => isset($job_data[$jid]['fasta']) ? $job_data[$jid]['fasta'] : '',
     '#prefix' => '<div id="fasta-textarea">',
     '#suffix' => '</div>',
   );
@@ -147,7 +157,7 @@ attempting to submit your BLAST.</strong>',
     '#type' => 'select',
     '#title' => t('%type BLAST Databases:', array('%type' => ucfirst($db_type))),
     '#options' => $options,
-    '#default_value' => 0,
+    '#default_value' => isset($job_data[$jid]['db_option']) ? $job_data[$jid]['db_option'] : 0,
   );
 
   if (variable_get('blast_ui_allow_target_upload', FALSE)) {
@@ -393,9 +403,51 @@ your sequence headers include pipes (i.e.: | ) they adhere to '
       $job_args,
       $user->uid
     );
-
+		//@deepaksomanadh Persist the important data for edit and resubmit
+		$job_data = variable_get('job_data', '');
+		$seq_rows = explode(PHP_EOL, $seq_content);
+		foreach($seq_rows as $row) {
+			if(strpos($row, ">") !== FALSE) {
+				$query_def[] = ltrim($row, ">");
+			}
+		}
+	
+		$job_data[$job_id] = 
+			array(
+				'program' => $blast_program,
+				'job_url' => current_path(),
+				'fasta' => $seq_content,
+				'query_def' => $query_def,
+				'db_name' => $blastdb_node->db_name,
+				'db_option' => $selected_db,
+				'options' => $advanced_options,
+			);
+		
+		variable_set('job_data', $job_data);
+		//@deepaksomanadh create session and save the recent jobs in respective session
+		if (session_status() === PHP_SESSION_NONE){
+					session_start();
+			}
+		$sid = session_id();
+		$job_encode_id = base64_encode($job_id);
+		$job_url = "blast/report/$job_encode_id";
+
+		$all_jobs = $_SESSION['all_jobs'];
+		
+		$session_jobs = $all_jobs[$sid];
+		$session_jobs[$job_id] = array(
+															'job_output_url'=> $job_url, 
+															'query_defs' => $query_def,
+															'program' => $blast_program,
+														 );
+		$all_jobs[$sid] = $session_jobs;
+		$_SESSION['all_jobs'] = $all_jobs;
+	
+		tripal_jobs_launch(1, $job_id);
+		//Encode the 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, $hit_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 = '"'. $hit_name . '"';
+   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, $black);
+   imagestring($img, 3, $q_xstart, $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 ."HSP" . ($ii + 1)), $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, "Bit 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);
+}
+?>

+ 131 - 26
theme/blast_report.tpl.php

@@ -5,6 +5,7 @@
  *
  * Variables Available in this template:
  *   $xml_filename: The full path & filename of XML file containing the BLAST results
+ *		@deepaksomanadh: $job_data = meta data related to the current job
  */
 
 // Set ourselves up to do link-out if our blast database is configured to do so.
@@ -70,12 +71,48 @@ $no_hits = TRUE;
   <a href="<?php print '../../' . $tsv_filename; ?>">Tab-Delimited</a>,
   <a href="<?php print '../../' . $xml_filename; ?>">XML</a>
 </p>
+<!--	@deepaksomanadh: For displaying BLAST command details -->
+<table>
+<tr>
+	<th>Input query sequence(s) </th>
+	<th>Target Database selected </th>
+	<th>BLAST command executed </th>
+<tr>
+<tr>
+<?php 
+	// get input sequences from job_data variable
+
+	$query_def = $job_id_data['query_def'];
+	echo "<td>";
+	echo "<ol>";
+	foreach($query_def as $row) {
+		echo "<li>";		
+		echo  $row . "</li>";
+	}
+	echo "</ol></td>";
+	echo "<td>" . 	$job_id_data['db_name'] . "</td>"
+ ?> 
 
-<p>The following table summarizes the results of your BLAST. To see additional information
-about each hit including the alignment, click on that row in the table to expand it.</p>
 
 <?php
+	include_once("blast_align_image.php");
+ 
+	//display the BLAST command without revealing the internal path
+	$blast_cmd = $job_id_data['program'];
+	
+	foreach($job_id_data['options'] as $key => $value) {
+			$blast_cmd .= ' -' . $key. ' ' . $value ;
+	}
+	print "<td>" . $blast_cmd . "</td>";	
+ ?>
+</table>
+
+<p>The following table summarizes the results of your BLAST. 
+Click on a <strong>triangle </strong> on the left to see the alignment and a visualization of the hit, 
+and click the <strong>target name </strong> to open a new window with a genome browser around this hit.</p>
 
+<?php
+include_once("blast_align_image.php");
 // Load the XML file
 $xml = simplexml_load_file($xml_filename);
 
@@ -87,11 +124,11 @@ $xml = simplexml_load_file($xml_filename);
 if ($xml) {
   // Specify the header of the table
   $header = array(
+		'arrow-col' =>  array('data' => '', 'class' => array('arrow-col')),
     'number' =>  array('data' => '#', 'class' => array('number')),
-    'query' =>  array('data' => 'Query Name', 'class' => array('query')),
-    'hit' =>  array('data' => 'Hit Name', 'class' => array('hit')),
+    'query' =>  array('data' => 'Query Name  (Click for alignment & visualization)', 'class' => array('query')),
+    'hit' =>  array('data' => 'Target Name', 'class' => array('hit')),
     'evalue' =>  array('data' => 'E-Value', 'class' => array('evalue')),
-    'arrow-col' =>  array('data' => '', 'class' => array('arrow-col'))
   );
 
   $rows = array();
@@ -102,6 +139,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 +153,47 @@ 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 = '';
+					$target_size = $hit->{'Hit_len'};
+		
+					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 +225,26 @@ 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, $hit_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 = '<h4><strong> Hit Visualization </strong></h4> <br><img src="data:image/png;base64,'.$b64.'"/>';
+					
           $row = array(
             'data' => array(
+							'arrow-col' => array('data' => '<div class="arrow"></div>', 'class' => array('arrow-col')),
               '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')
@@ -174,11 +256,16 @@ if ($xml) {
 
           $row = array(
             'data' => array(
+							'arrow' => '',
               'number' => '',
               'query' => array(
                 'data' => theme('blast_report_alignment_row', array('HSPs' => $HSPs)),
-                'colspan' => 4,
-              )
+              //  'colspan' => 4,
+              ),
+							'hit' => array(
+                'data' => $hit_img,
+                'colspan' => 3,
+              ),
             ),
             'class' => array('alignment-row', $zebra_class),
             'no_striping' => TRUE
@@ -195,7 +282,7 @@ if ($xml) {
       $query_with_no_hits[] = $query_name;
 
 		} // end of else
-  }
+  }	//end of foreach - BlastOutput_iterations
 
   if ($no_hits) {
     print '<p class="no-hits-message">No results found.</p>';
@@ -223,3 +310,21 @@ else {
   print '<p>We encountered an error and are unable to load your BLAST results.</p>';
 }
 ?>
+<p> <!--	@deepaksomanadh: Building the edit and resubmit URL --> 
+	 <a style ="align:center" href="<?php print '../../'. $job_id_data['job_url'] . '?jid=' . base64_encode($job_id) ?>">Edit this query and re-submit</a>	
+</p>
+<strong> Recent Jobs </strong>
+	<ol>
+	<?php
+			$sid = session_id();	
+			$jobs = $_SESSION['all_jobs'][$sid];
+	
+			foreach ( $jobs as $job) {
+				echo "<li>";
+				$q_def = !isset($job['query_defs'][0]) ? "Query" : $job['query_defs'][0];
+				echo "<a href='" . "../../" . $job['job_output_url'] ."' >"  
+								. $q_def ."->". $job['program'] . "</a>";
+				echo "</li>";
+			}
+	?>
+	</ol>

+ 30 - 20
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">
@@ -77,7 +87,7 @@
             <span class="alignment-residues"><?php print str_replace(' ', '&nbsp', $matches[$k]); ?></span>
           </div>
           <div class="hit">
-            <span class="alignment-title">Hit:</span>&nbsp;&nbsp;&nbsp;&nbsp;
+            <span class="alignment-title">Sbjct:</span>&nbsp;&nbsp;&nbsp;&nbsp;
             <span class="alignment-start-coord"><?php print $coord['hstart']; ?></span>
             <span class="alignment-residues"><?php print $hit[$k]; ?></span>
             <span class="alignment-stop-coord"><?php print $coord['hstop']; ?></span>

+ 4 - 0
theme/blast_ui.theme.inc

@@ -31,6 +31,10 @@ function blast_ui_preprocess_show_blast_report(&$vars) {
   // Add the blast database node.
   // This is needed for link-out functionality.
   $vars['blastdb'] = get_blast_database(array('path' => $job_args['database']));
+	//@deepaksomanadh: code added to use the persisted data in the template file.
+	$job_id = $vars['job_id'];
+	$job_data = variable_get('job_data', '');
+	$vars['job_id_data'] = $job_data[$job_id];
 }
 
 /**

+ 4 - 0
theme/css/blast_report.css

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