blast_report.tpl.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <?php
  2. /**
  3. * Display the results of a BLAST job execution
  4. *
  5. * Variables Available in this template:
  6. * $xml_filename: The full path & filename of XML file containing the BLAST results
  7. * @deepaksomanadh: $job_data = meta data related to the current job
  8. */
  9. // uncomment this to see the contents of the $blastdb object
  10. //echo "blastdb:<pre>";var_dump($blastdb);echo "</pre>";
  11. // Set ourselves up to do link-out if our blast database is configured to do so.
  12. $linkout = FALSE;
  13. if ($blastdb->linkout->none === FALSE) {
  14. $linkout_type = $blastdb->linkout->type;
  15. $linkout_regex = $blastdb->linkout->regex;
  16. // Note that URL prefix is not required if linkout type is 'custom'
  17. if (isset($blastdb->linkout->db_id->urlprefix) && !empty($blastdb->linkout->db_id->urlprefix)) {
  18. $linkout_urlprefix = $blastdb->linkout->db_id->urlprefix;
  19. }
  20. // Check that we can determine the linkout URL.
  21. // (ie: that the function specified to do so, exists).
  22. if (function_exists($blastdb->linkout->url_function)) {
  23. $url_function = $blastdb->linkout->url_function;
  24. $linkout = TRUE;
  25. }
  26. }
  27. // Handle no hits. This following array will hold the names of all query
  28. // sequences which didn't have any hits.
  29. $query_with_no_hits = array();
  30. // Furthermore, if no query sequences have hits we don't want to bother listing
  31. // them all but just want to give a single, all-include "No Results" message.
  32. $no_hits = TRUE;
  33. ?>
  34. <script type="text/javascript">
  35. window.onload = function() {
  36. if (!window.location.hash) {
  37. window.location = window.location + '#loaded';
  38. window.location.reload();
  39. }
  40. }
  41. // JQuery controlling display of the alignment information (hidden by default)
  42. $(document).ready(function(){
  43. // Hide the alignment rows in the table
  44. // (ie: all rows not labelled with the class "result-summary" which contains the tabular
  45. // summary of the hit)
  46. $("#blast_report tr:not(.result-summary)").hide();
  47. $("#blast_report tr:first-child").show();
  48. // When a results summary row is clicked then show the next row in the table
  49. // which should be corresponding the alignment information
  50. $("#blast_report tr.result-summary").click(function(){
  51. $(this).next("tr").toggle();
  52. $(this).find(".arrow").toggleClass("up");
  53. });
  54. });
  55. </script>
  56. <style>
  57. .no-hits-message {
  58. color: red;
  59. font-style: italic;
  60. }
  61. </style>
  62. <div class="blast-report">
  63. <!-- Provide Information to the user about their blast job -->
  64. <div class="blast-job-info">
  65. <?php if($xml): ?>
  66. <div class="blast-download-info"><strong>Download</strong>:
  67. <a href="<?php print '../../' . $html_filename; ?>">Alignment</a>,
  68. <a href="<?php print '../../' . $tsv_filename; ?>">Tab-Delimited</a>,
  69. <a href="<?php print '../../' . $xml_filename; ?>">XML</a>
  70. </div>
  71. <?php endif; ?>
  72. <br />
  73. <div class="blast-query-info"><strong>Query Information</strong>:
  74. <?php print $blast_job->display['query_info'];?></div>
  75. <div class="blast-target-info"><strong>Search Target</strong>:
  76. <?php print $blast_job->display['target'];?></div>
  77. <div class="blast-date-info"><strong>Submission Date</strong>:
  78. <?php print $blast_job->display['date'];?></div>
  79. <div class="blast-cmd-info"><strong>BLAST Command executed</strong>:
  80. <?php print $blast_job->display['blast_cmd'];?></div>
  81. </div>
  82. <br />
  83. <?php
  84. /**
  85. * We are using the drupal table theme functionality to create this listing
  86. * @see theme_table() for additional documentation
  87. */
  88. if ($xml) {
  89. ?>
  90. <p>The following table summarizes the results of your BLAST.
  91. Click on a <em>triangle </em> on the left to see the alignment and a visualization of the hit,
  92. and click the <em>target name </em> to get more information about the target hit.</p>
  93. <?php
  94. // Specify the header of the table
  95. $header = array(
  96. 'arrow-col' => array('data' => '', 'class' => array('arrow-col')),
  97. 'number' => array('data' => '#', 'class' => array('number')),
  98. 'query' => array('data' => 'Query Name (Click for alignment & visualization)', 'class' => array('query')),
  99. 'hit' => array('data' => 'Target Name', 'class' => array('hit')),
  100. 'evalue' => array('data' => 'E-Value', 'class' => array('evalue')),
  101. );
  102. $rows = array();
  103. $count = 0;
  104. // Parse the BLAST XML to generate the rows of the table
  105. // where each hit results in two rows in the table: 1) A summary of the query/hit and
  106. // significance and 2) additional information including the alignment
  107. foreach ($xml->{'BlastOutput_iterations'}->children() as $iteration) {
  108. $children_count = $iteration->{'Iteration_hits'}->children()->count();
  109. //@deepaksomanadh: Code added for BLAST visualization
  110. // parameters that need to be passed for BLAST image generation
  111. $target_name = '';
  112. $q_name = $xml->{'BlastOutput_query-def'};
  113. $query_size = $xml->{'BlastOutput_query-len'};
  114. $target_size = $iteration->{'Iteration_stat'}->{'Statistics'}->{'Statistics_db-len'};
  115. if ($children_count != 0) {
  116. foreach ($iteration->{'Iteration_hits'}->children() as $hit) {
  117. if (is_object($hit)) {
  118. $count +=1;
  119. $zebra_class = ($count % 2 == 0) ? 'even' : 'odd';
  120. $no_hits = FALSE;
  121. // RETRIEVE INFO
  122. $hit_name = (preg_match('/BL_ORD_ID/', $hit->{'Hit_id'})) ? $hit->{'Hit_def'} : $hit->{'Hit_id'};
  123. $score = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_score'};
  124. $evalue = $hit->{'Hit_hsps'}->{'Hsp'}->{'Hsp_evalue'};
  125. $query_name = $iteration->{'Iteration_query-def'};
  126. // Round e-val to two decimal values
  127. $rounded_evalue = '';
  128. if (strpos($evalue,'e') != false) {
  129. $evalue_split = explode('e', $evalue);
  130. $rounded_evalue = round($evalue_split[0], 2, PHP_ROUND_HALF_EVEN);
  131. $rounded_evalue .= 'e' . $evalue_split[1];
  132. }
  133. else {
  134. $rounded_evalue = $evalue;
  135. }
  136. // ALIGNMENT ROW (collapsed by default)
  137. // Process HSPs
  138. // @deepaksomanadh: Code added for BLAST visualization
  139. // hit array and corresponding bit scores
  140. // hits=4263001_4262263_1_742;4260037_4259524_895_1411;&scores=722;473;
  141. $HSPs = array();
  142. $track_start = INF;
  143. $track_end = -1;
  144. $hsps_range = '';
  145. $hit_hsps = '';
  146. $hit_hsp_score = '';
  147. $target_size = $hit->{'Hit_len'};
  148. foreach ($hit->{'Hit_hsps'}->children() as $hsp_xml) {
  149. $HSPs[] = (array) $hsp_xml;
  150. if ($track_start > $hsp_xml->{'Hsp_hit-from'}) {
  151. $track_start = $hsp_xml->{'Hsp_hit-from'} . "";
  152. }
  153. if ($track_end < $hsp_xml->{'Hsp_hit-to'}) {
  154. $track_end = $hsp_xml->{'Hsp_hit-to'} . "";
  155. }
  156. }
  157. $range_start = (int) $track_start - 50000;
  158. $range_end = (int) $track_end + 50000;
  159. if ($range_start < 1)
  160. $range_start = 1;
  161. // For BLAST visualization
  162. $target_size = $hit->{'Hit_len'};
  163. $Hsp_bit_score = '';
  164. foreach ($hit->{'Hit_hsps'}->children() as $hsp_xml) {
  165. $hit_hsps .= $hsp_xml->{'Hsp_hit-from'} . '_' .
  166. $hsp_xml->{'Hsp_hit-to'} . '_' .
  167. $hsp_xml->{'Hsp_query-from'} . '_' . $hsp_xml->{'Hsp_query-to'} .
  168. ';';
  169. $Hsp_bit_score .= $hsp_xml->{'Hsp_bit-score'} .';';
  170. }
  171. // SUMMARY ROW
  172. // If the id is of the form gnl|BL_ORD_ID|### then the parseids flag
  173. // to makeblastdb did a really poor job. In this case we want to use
  174. // the def to provide the original FASTA header.
  175. // If our BLAST DB is configured to handle link-outs then use the
  176. // regex & URL prefix provided to create one.
  177. $hit_name = $hit->{'Hit_def'};
  178. $hit_name_short = (preg_match('/^([^\s]+)/', $hit_name, $matches)) ? $matches[1] : $hit_name;
  179. $query_name = $iteration->{'Iteration_query-def'};
  180. if ($linkout) {
  181. //echo "link out regex: $linkout_regex executed on [$hit_name]<br>";
  182. //preg_match($linkout_regex, $hit_name, $linkout_match);
  183. //echo "<br>matches:<pre>" . var_dump($linkout_match);echo "</pre>";
  184. if (preg_match($linkout_regex, $hit_name, $linkout_match)) {
  185. $linkout_id = $linkout_match[1];
  186. $hit->{'linkout_id'} = $linkout_id;
  187. $hit->{'hit_name'} = $hit_name;
  188. }
  189. $hit_url = call_user_func(
  190. $url_function,
  191. $linkout_urlprefix,
  192. $hit,
  193. array(
  194. 'query_name' => $query_name,
  195. 'score' => $score,
  196. 'e-value' => $evalue,
  197. 'HSPs' => $HSPs,
  198. 'Target' => $blastdb->title,
  199. )
  200. );
  201. // The linkout id might have been set/changed by the custom linkout code.
  202. if ($linkout_type == 'custom' && $hit->{'linkout_id'}) {
  203. $linkout_id = $hit->{'linkout_id'};
  204. }
  205. if ($hit_url) {
  206. /* eksc- l() URL-encodes the URL path too, which is often not what we want.
  207. $hit_name = l(
  208. $linkout_id,
  209. $hit_url,
  210. array('attributes' => array('target' => '_blank'))
  211. );
  212. */
  213. $hit_name = "
  214. <a href=\"$hit_url\" target=\"_blank\">
  215. $linkout_id
  216. </a>";
  217. }
  218. }//handle linkout
  219. //@deepaksomanadh: Code added for BLAST visualization
  220. // get the image and display
  221. $hit_img = generate_blast_hit_image($target_name, $Hsp_bit_score, $hit_hsps,
  222. $target_size, $query_size, $q_name, $hit_name_short);
  223. $row = array(
  224. 'data' => array(
  225. 'arrow-col' => array('data' => '<div class="arrow"></div>', 'class' => array('arrow-col')),
  226. 'number' => array('data' => $count, 'class' => array('number')),
  227. 'query' => array('data' => $query_name, 'class' => array('query')),
  228. 'hit' => array('data' => $hit_name, 'class' => array('hit')),
  229. 'evalue' => array('data' => $rounded_evalue, 'class' => array('evalue')),
  230. 'arrow-col' => array('data' => '<div class="arrow"></div>', 'class' => array('arrow-col'))
  231. ),
  232. 'class' => array('result-summary')
  233. );
  234. $rows[] = $row;
  235. // ALIGNMENT ROW (collapsed by default)
  236. // Process HSPs
  237. $row = array(
  238. 'data' => array(
  239. 'arrow' => array(
  240. 'data' => theme('blast_report_alignment_row', array('HSPs' => $HSPs, 'hit_visualization' => $hit_img)),
  241. 'colspan' => 5,
  242. ),
  243. ),
  244. 'class' => array('alignment-row', $zebra_class),
  245. 'no_striping' => TRUE
  246. );
  247. $rows[] = $row;
  248. }//end of if - checks $hit
  249. }//end of foreach - iteration_hits
  250. }//end of if - check for iteration_hits
  251. else {
  252. // Currently where the "no results" is added.
  253. $query_name = $iteration->{'Iteration_query-def'};
  254. $query_with_no_hits[] = $query_name;
  255. }//no results
  256. }//end of foreach - BlastOutput_iterations
  257. if ($no_hits) {
  258. print '<p class="no-hits-message">No results found.</p>';
  259. }
  260. else {
  261. // We want to warn the user if some of their query sequences had no hits.
  262. if (!empty($query_with_no_hits)) {
  263. print '<p class="no-hits-message">Some of your query sequences did not '
  264. . 'match to the database/template. They are: '
  265. . implode(', ', $query_with_no_hits) . '.</p>';
  266. }
  267. // Actually print the table.
  268. if (!empty($rows)) {
  269. print theme('table', array(
  270. 'header' => $header,
  271. 'rows' => $rows,
  272. 'attributes' => array('id' => 'blast_report'),
  273. 'sticky' => FALSE
  274. ));
  275. }
  276. }//handle no hits
  277. }//XML exists
  278. else {
  279. drupal_set_title('BLAST: Error Encountered');
  280. print '<p class="blast-no-results">We encountered an error and are unable to load your BLAST results.</p>';
  281. }
  282. ?>
  283. <p><?php print l(
  284. 'Edit this query and re-submit',
  285. $blast_job->form_options['job_url'],
  286. array('query' => array('jid' => base64_encode($job_id))));
  287. ?></p>
  288. </div>
  289. <!-- Recent Jobs -->
  290. <?php
  291. // Gets the list of recent jobs filtered to the current blast program (ie: blastn).
  292. if ($recent_jobs) {
  293. print '<h2>Recent Jobs</h2>';
  294. $table = array(
  295. 'header' => array('Query Information', 'Search Target', 'Date Requested', ''),
  296. 'rows' => array(),
  297. 'attributes' => array('class' => array('tripal-blast', 'recent-jobs')),
  298. 'sticky' => FALSE
  299. );
  300. foreach ($recent_jobs as $job) {
  301. // Define a row for the current job.
  302. $table['rows'][] = array(
  303. $job['query_info'],
  304. $job['target'],
  305. $job['date'],
  306. l('See Results', $job['job_output_url'])
  307. );
  308. }
  309. print theme('table', $table);
  310. }
  311. ?>