Răsfoiți Sursa

Added protein BLAST and re-vamped the results page to be a tabular listing generated from XML

Lacey Sanderson 10 ani în urmă
părinte
comite
00b915a82d

+ 6 - 0
blast_ui.install

@@ -37,6 +37,12 @@ function blast_ui_schema(){
          'length' => 1023,
         'not null' => true,
       ),
+      'dbtype' => array(
+        'description' => t('Type of the blast database'),
+        'type' => 'varchar',
+        'length' => 8,
+        'not null' => true,
+       ),
     ),
     'indexes' => array(
       'name' => array('name'),

+ 42 - 16
blast_ui.module

@@ -8,12 +8,37 @@
 require_once 'includes/blast_ui.blastn.inc';
 require_once 'includes/blast_ui.blastp.inc';
 require_once 'includes/blast_ui.node.inc';
+require_once 'theme/blast_ui.theme.inc';
 
+/**
+ *
+ * Implements hook_theme()
+ *
+ */
+
+function blast_ui_theme() {
+  $items = array();
+
+  $path = drupal_get_path('module', 'blast_ui');
+
+  $items['show_blast_report'] = array(
+    'template' => 'blast_report',
+    'path' => "$path/theme",
+  );
+
+  $items['blast_report_alignment_row'] = array(
+    'template' => 'blast_report_alignment_row',
+    'variables' => array('hsps' => NULL),
+    'path' => "$path/theme",
+  );
+
+  return $items;
+}
 
 /**
  *
  * Implements hook_menu()
- * 
+ *
  */
 function blast_ui_menu() {
 
@@ -27,7 +52,7 @@ function blast_ui_menu() {
 );
 
   $items['blast/report/%'] = array(
-    'title' => 'Nucleotide BLAST result:',
+    'title' => 'BLAST result:',
     'page callback' => 'show_blast_output',
     'page arguments' => array(2),
     'access arguments' => array('access content'),
@@ -42,13 +67,13 @@ function blast_ui_menu() {
     'type' => MENU_NORMAL_ITEM
   );
 
-//  $items['blast/blastp'] = array(
-//    'title' => 'Protein BLAST',
-//    'page callback' => 'drupal_get_form',
-//    'page arguments' => array('blast_protein_form'), 
-//    'access arguments' => array('access content'),
-//    'type' => MENU_NORMAL_ITEM
-//  );
+$items['blast/blastp'] = array(
+   'title' => 'Protein BLAST',
+   'page callback' => 'drupal_get_form',
+   'page arguments' => array('blast_protein_form'),
+   'access arguments' => array('access content'),
+   'type' => MENU_NORMAL_ITEM
+);
 
   return $items;
 }
@@ -57,23 +82,24 @@ function blast_ui_menu() {
  * Facilitate presenting the result of the blast search
  *
  * @param $args
- *  A string containing name of the blast output file. 
+ *  A string containing name of the blast output file.
  *
  * @return $result
- *  Return a string containing the blast search output. A link is also provided to let users download the output file.    
+ *  Return a string containing the blast search output. A link is also provided to let users download the output file.
  *
  */
-function show_blast_output($args = 'all') { 
+function show_blast_output($args = 'all') {
 
   if (preg_match('/^[^\/]*/',$args)) {
     // Since the blast results are in the files directory we can use public:// to get around hard-coding the full path
     $full_path_filename = 'public://'.$args;
 
     if (file_exists($full_path_filename)) {
-      $result = t('<br /><h3>BLAST Results: <a href="@url" target="_blank">HTML</a></h3>', array('@url' => url('sites/default/files/' . $args)));
-      $result .= check_markup(file_get_contents($full_path_filename), 'full_html');
+    //  $result = t('<br /><h3>BLAST Results: <a href="@url" target="_blank">HTML</a></h3>', array('@url' => url('sites/default/files/' . $args)));
+    //  $result .= check_markup(file_get_contents($full_path_filename), 'full_html');
+    //  $result = str_replace('<script src="blastResult.js"></script>','',$result);
 
-      $result = str_replace('<script src="blastResult.js"></script>','',$result);
+	$result = theme('show_blast_report');
     }
     else {
       tripal_report_error(
@@ -87,7 +113,7 @@ function show_blast_output($args = 'all') {
   }
   else {
     $result = '<p>An error was encountered while trying to process your blast results</p>';
-  } 
+  }
 
   return $result;
 }

+ 5 - 3
includes/blast_ui.blastn.inc

@@ -331,11 +331,11 @@ function blast_nucleotide_form_submit($form, &$form_state) {
      $blastdb_path = $blastdb_node->db_path;     
      $blastdb_human_name = $form['DB']['SELECT_DB']['#options'][$selected_db];
      $subSeqOut = str_replace(' ','_', $blastdb_human_name) . rand(0, 10000);
-     $blast_db_cmd = "blastn -task blastn -query $query -db $blastdb_path -out sites/default/files/$subSeqOut.blastn.html -evalue $eVal -word_size $wordSize -gapopen $gapOpen -gapextend $gapExtend -penalty $penalty -reward $reward -num_alignments 100 -html";
+     $blast_db_cmd = "blastn -task blastn -query $query -db $blastdb_path -out sites/default/files/$subSeqOut.blastn.xml -evalue $eVal -word_size $wordSize -gapopen $gapOpen -gapextend $gapExtend -penalty $penalty -reward $reward -num_alignments 100 -outfmt=5";
      system($blast_db_cmd,$input);
   }
 
-  $path = "$subSeqOut.blastn.html";
+  $path = "$subSeqOut.blastn.xml";
   drupal_goto("blast/report/$path");
 }
 
@@ -380,8 +380,10 @@ function _DB_options() {
    $options = array();
 
    foreach ($nodes as $node) {
-      if ( isset($node) ) {
+      if ( isset($node) && isset($node->db_dbtype) ) {
+	if ( ($node->db_dbtype=='n') ) {
          $options[$node->nid] = $node->db_name;
+	}
       }     
    }
 

+ 651 - 113
includes/blast_ui.blastp.inc

@@ -1,59 +1,70 @@
 <?php
 
+/**
+ * @file
+ * Contains all functions for the protein blast module 
+ */
+
+
+/**
+ * Form constructor for the protein blast form.
+ *
+ * @see blast_protein_form_validate()
+ * @see blast_protein_form_submit()
+ *
+ */
 function blast_protein_form($form, &$form_state) {
   
+// Protein BLAST
 
-//Protein BLAST
-
-  $form['pBLAST'] = array(
+$form['pBLAST'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Standard Nucleotide BLAST'),
+    '#title' => t('Enter Query Sequence'),
+    '#description' => t('Enter one or more queries in the top text box or use the browse button to upload a file from your local disk. The file may contain a single sequence or a list of sequences. In both cases, the data must be in FASTA format. <a href="http://www.ncbi.nlm.nih.gov/BLAST/blastcgihelp.shtml" target="_blank">More information..</a> '),
     '#collapsible' => TRUE, 
     '#collapsed' => FALSE,  
   );
+
 $form['pBLAST']['FASTA'] = array(
     '#type' => 'textarea',
     '#title' => t('Enter FASTA sequence(s)'),
     '#description'=>t('Enter query sequence(s) in the text area.'),
   );
 
-
 // Upload a file as an alternative to enter a query sequence 
-  $form['#attributes']['enctype'] = 'multipart/form-data';
-  $form['pBLAST']['UPLOAD'] = array(
+$form['#attributes']['enctype'] = 'multipart/form-data';
+$form['pBLAST']['UPLOAD'] = array(
   	'#prefix' => 'Or upload your query files:	',
   	'#type' => 'file',
-  	'#description' => t('Please give a text file, not a MS-Word or other document, you can upload up to 10 Mb.'),
+  	'#description' => t('The file should be a plain-text FASTA file and not a .doc, .docx, etc. It cannot be greater than 10 Mb in size.'),
   );
 
+
 //DATABASE//
 
-	$form['DB'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('BLAST Assembled KnowPulse Genomes'),
-    '#collapsible' => TRUE, 
-    '#collapsed' => FALSE,  
-  );
-  $form['DB']['SELECT_DB'] = array(
-       '#type' => 'select',
-       '#title' => t('KnowPulse Databases:'),
-       '#options' => array(
-          0 => t('Human immunodeficiency virus 1'),
-          1 => t('Human immunodeficiency virus 2'),
-          2 => t('Simian immunodeficiency virus'),
-          3 => t('Human herpesvirus 2'),
-          4 => t('Human herpesvirus 1'),
-       ),
-       '#default_value' => NULL,
-   );
+$form['DB'] = array(
+  '#type' => 'fieldset',
+  '#title' => t('Choose Search Set'),
+  '#description' => t('Choose from one of the protein BLAST databases listed below. You can also use the browse button to upload a file from your local disk. The file may contain a single sequence or a list of sequences. '),
+  '#collapsible' => TRUE, 
+  '#collapsed' => FALSE,  
+);
+  
+$options = DB_options();
+$form['DB']['SELECT_DB'] = array(
+ '#type' => 'select',
+ '#title' => t('Protein BLAST Databases:'),
+ '#options' => $options,
+ '#default_value' => t('Select a database'),
+);
   
 // Upload a file as an alternative to enter a query sequence 
-  $form['#attributes']['enctype'] = 'multipart/form-data';
-  $form['DB']['DBUPLOAD'] = array(
-  	'#prefix' => 'Or upload your own dataset:	',
+$form['#attributes']['enctype'] = 'multipart/form-data';
+$form['DB']['DBUPLOAD'] = array(
+   '#prefix' => 'Or upload your own dataset:	',
   	'#type' => 'file',
-  	'#description' => t('Please give a text file, not a MS-Word or other document, you can upload up to 10 Mb.'),
-  );
+  	'#description' => t('The file should be a plain-text FASTA file and not a .doc, .docx, etc. It cannot be greater than 10 Mb in size.'),
+);
   
 //Algorithm parameters
 
@@ -62,124 +73,637 @@ $form['pBLAST']['FASTA'] = array(
     '#title' => t('Algorithm parameters'),
     '#collapsible' => TRUE, 
     '#collapsed' => TRUE,  
-  );
+);
 
 //General parameters  
 
-  $form['ALG']['GParam'] = array(
+ $form['ALG']['GParam'] = array(
     '#type' => 'fieldset',
     '#title' => t('General parameters'),
     '#collapsible' => FALSE,
-  );
+ );
   
-  $form['ALG']['GParam']['maxTarget'] = array(
-       '#type' => 'select',
-       '#title' => t('Max target sequences:'),
-       '#options' => array(
-          0 => t('10'),
-          1 => t('50'),
-          2 => t('100'),
-          3 => t('250'),
-          4 => t('500'),
-          5 => t('1000'),
-          6 => t('5000'),
-          7 => t('10000'),
-          8 => t('20000'),
-       ),
-       '#default_value' => 2,
-       '#description' => t('Select the maximum number of aligned sequences to display'),
-   );
+$form['ALG']['GParam']['maxTarget'] = array(
+    '#type' => 'select',
+    '#title' => t('Max target sequences:'),
+    '#options' => array(
+       0 => t('10'),
+       1 => t('50'),
+       2 => t('100'),
+       3 => t('250'),
+       4 => t('500'),
+       5 => t('1000'),
+       6 => t('5000'),
+       7 => t('10000'),
+       8 => t('20000'),
+    ),
+    '#default_value' => 2,
+    '#description' => t('Select the maximum number of aligned sequences to display'),
+);
   
-  $form['ALG']['GParam']['shortQueries'] = array(
+$form['ALG']['GParam']['shortQueries'] = array(
    '#type' => 'checkbox', 
    '#title' => t('Automatically adjust parameters for short input sequences'),
    '#default_value' => TRUE,
 );
 	
-   $form['ALG']['GParam']['eVal'] = array(
+$form['ALG']['GParam']['eVal'] = array(
   	'#type' => 'textfield', 
-  	'#title' => t('Expect threshold'), 
+  	'#title' => t('e-value(Expect threshold)'), 
   	'#default_value' => 10, 
   	'#size' => 12, 
   	'#maxlength' => 20, 
   	'#description' => t('Expected number of chance matches in a random model.'),
 );
 	
-   $form['ALG']['GParam']['wordSize'] = array(
-       '#type' => 'select',
-       '#title' => t('Word size:'),
-       '#options' => array(
-          0 => t('2'),
-          1 => t('3'),
-       ),
-       '#default_value' => 1,
-       '#description' => t('The length of the seed that initiates an alignment'),
-   );
+$form['ALG']['GParam']['wordSize'] = array(
+    '#type' => 'select',
+    '#title' => t('Word size:'),
+    '#options' => array(
+       0 => t('2'),
+       1 => t('3'),
+    ),
+    '#default_value' => 1,
+    '#description' => t('The length of the seed that initiates an alignment'),
+);
   
-   $form['ALG']['GParam']['qRange'] = array(
-   	 '#type' => 'textfield', 
-   	 '#title' => t('Max matches in a query range'), 
-   	 '#default_value' => 0, 
-   	 '#size' => 12, 
-   	 '#maxlength' => 20, 
-   	 '#description' => t('Limit the number of matches to a query range. This option is useful if many strong matches to one part of a query may prevent BLAST from presenting weaker matches to another part of the query.'),
+$form['ALG']['GParam']['qRange'] = array(
+   '#type' => 'textfield', 
+   '#title' => t('Max matches in a query range'), 
+   '#default_value' => 0, 
+   '#size' => 12, 
+   '#maxlength' => 20, 
+   '#description' => t('Limit the number of matches to a query range. This option is useful if many strong matches to one part of a query may prevent BLAST from presenting weaker matches to another part of the query.'),
 );
  
 // Scoring parameters
 
-  $form['ALG']['SParam'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Scoring parameters'),
-    '#collapsible' => FALSE, 
-  );
+$form['ALG']['SParam'] = array(
+   '#type' => 'fieldset',
+   '#title' => t('Scoring parameters'),
+   '#collapsible' => FALSE, 
+);
   
-  $options_first = _ajax_example_get_first_dropdown_options();
-  $selected = isset($form_state['values']['MATRIX'] ) ? $form_state['values']['MATRIX'] : key($options_first);
+$options_first = _ajax_example_get_first_dropdown_options();
+$selected = isset($form_state['values']['MATRIX'] ) ? $form_state['values']['MATRIX'] : key($options_first);
 
-  $form['ALG']['SParam']['MATRIX'] = array(
-    '#type' => 'select',
-    '#title' => 'Matrix',
-    '#options' => $options_first,
-    '#default_value' => $selected,
-    '#description' => t('Assigns a score for aligning pairs of residues, and determines overall alignment score..'),
-    '#ajax' => array(
+$form['ALG']['SParam']['MATRIX'] = array(
+   '#type' => 'select',
+   '#title' => 'Matrix',
+   '#options' => $options_first,
+   '#default_value' => $selected,
+   '#description' => t('Assigns a score for aligning pairs of residues, and determines overall alignment score..'),
+   '#ajax' => array(
       'callback' => 'ajax_example_dependent_dropdown_callback',
       'wrapper' => 'dropdown-second-replace',
-    ),
-  );
+   ),
+);
 
-  $form['ALG']['SParam']['gapCost'] = array(
-    '#type' => 'select',
-    '#title' => t('Gap Costs:'),    
-    '#prefix' => '<div id="dropdown-second-replace">',
-    '#suffix' => '</div>',
-    '#options' => _ajax_example_get_second_dropdown_options($selected),
-    '#default_value' => 2,
-    '#description' => t('Cost to create and extend a gap in an alignment.'),
-   );
+$form['ALG']['SParam']['gapCost'] = array(
+   '#type' => 'select',
+   '#title' => t('Gap Costs:'),    
+   '#prefix' => '<div id="dropdown-second-replace">',
+   '#suffix' => '</div>',
+   '#options' => _ajax_example_get_second_dropdown_options($selected),
+   '#default_value' => 2,
+   '#description' => t('Cost to create and extend a gap in an alignment.'),
+);
   
-   $form['ALG']['SParam']['M&MScores'] = array(
-    '#type' => 'select',
-    '#title' => t('Match/Mismatch Scores:'),
-    '#options' => array(
-    	0 => t('No adjustment'),
-      1 => t('Composition-based statistics'),
-      2 => t('Conditional compositional score matrix adjustment'),
-      3 => t('Universal composition score matrix adjustment '),
-    ),
-    '#default_value' => 2,
-    '#description' => t('Matrix adjustment method to compensate for amino acid composition of sequences'),
-   );
+$form['ALG']['SParam']['M&MScores'] = array(
+   '#type' => 'select',
+   '#title' => t('Match/Mismatch Scores:'),
+   '#options' => array(
+     0 => t('No adjustment'),
+     1 => t('Composition-based statistics'),
+     2 => t('Conditional compositional score matrix adjustment'),
+     3 => t('Universal composition score matrix adjustment '),
+   ),
+   '#default_value' => 2,
+   '#description' => t('Matrix adjustment method to compensate for amino acid composition of sequences'),
+);
   
 //Submit 
 
-  $form['next'] = array(
-    '#type' => 'submit',
-    '#value' => ' BLAST ',
-  );
-  return $form;
+$form['submit'] = array(
+   '#type' => 'submit',
+   '#default_value' => ' BLAST ',
+);
+  
+return $form;
+}
+
+/**
+ * Form validation handler for blast_protein_form().
+ *
+ * @see blast_protein_form_validate()
+ */
+function blast_protein_form_validate($form, &$form_state) {
+   $fastaSeq = $form_state['input']['FASTA'];
+   if (isset($fastaSeq)) {
+      if(validateFasta($fastaSeq)){
+          form_set_error('pBLAST', t('Error: Failed to read the Blast query: Wrong format provided for FASTA protein sequence'));
+      } else {
+        $form_state['qFlag'] = 'seqQuery';
+      }  
+   }
+   $upQuery = file_save_upload('UPLOAD', array('file_validate_extensions' => array('txt fasta fa fna')), FILE_EXISTS_RENAME);
+   if ($upQuery) {
+      $upQuery_uri = $upQuery->uri;
+      $form_state['upQuery_path'] = drupal_realpath($upQuery_uri);
+      $upQuery_content = file_get_contents($form_state['upQuery_path']);
+      if(validateFasta($upQuery_content)){
+          form_set_error('pBLAST', t('Error: Failed to upload the Blast query: Wrong format provided for FASTA protein sequence'));
+      } else {
+         $form_state['qFlag'] = 'upQuery';
+      }
+   }
+   
+   $upDB = file_save_upload('DBUPLOAD', array('file_validate_extensions' => array('txt fasta fa fna')), FILE_EXISTS_RENAME);
+   if ($upDB) {  
+      $upDB_uri = $upDB->uri;
+      $form_state['upDB_path'] = drupal_realpath($upDB_uri);
+      $upDB_content = file_get_contents($form_state['upDB_path']); 
+      if(validateFasta($upDB_content)){
+         form_set_error('DB', t('Error: Failed to upload the Blast subject sequence file: Wrong format provided for FASTA protein sequence'));
+      } else {
+         $form_state['dbFlag'] = 'upQuery';
+      }
+   } else {
+      $form_state['dbFlag'] = 'blastdb';
+   }
+      
+}
+
+/**
+ * Form submition handler for blast_protein_form().
+ *
+ * @see blast_protein_form_submit()
+ */
+function blast_protein_form_submit($form, &$form_state) {  
+  $eVal = $form_state['values']['eVal'];
+  
+  $trgtKey = $form_state['values']['maxTarget'];
+  $numAlign = $form['ALG']['GParam']['maxTarget']['#options'][$trgtKey];
+  
+  $wsKey = $form_state['values']['wordSize'];
+  $wordSize = $form['ALG']['GParam']['wordSize']['#options'][$wsKey];
+  
+  $gapKey = $form_state['values']['MATRIX'];
+  switch ($gapKey) {
+   case 0:
+     $matrix ="PAM30"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 7;
+         $gapExtend = 2;
+         break;
+      case 1:
+         $gapOpen = 6;
+         $gapExtend = 2;
+         break;
+      case 2:
+         $gapOpen = 5;
+         $gapExtend = 2;
+         break;
+      case 3:
+         $gapOpen = 10;
+         $gapExtend = 1;
+         break;
+      case 4:
+         $gapOpen = 9;
+         $gapExtend = 1;
+         break;
+      case 5:
+         $gapOpen = 8;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+   case 1:
+     $matrix ="PAM70";
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 8;
+         $gapExtend = 2;
+         break;
+      case 1:
+         $gapOpen = 7;
+         $gapExtend = 2;
+         break;
+      case 2:
+         $gapOpen = 6;
+         $gapExtend = 2;
+         break;
+      case 3:
+         $gapOpen = 11;
+         $gapExtend = 1;
+         break;
+      case 4:
+         $gapOpen = 10;
+         $gapExtend = 1;
+         break;
+      case 5:
+         $gapOpen = 9;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+   case 2:
+     $matrix ="PAM250"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 15;
+         $gapExtend = 3;
+         break;
+      case 1:
+         $gapOpen = 14;
+         $gapExtend = 3;
+         break;
+      case 2:
+         $gapOpen = 13;
+         $gapExtend = 3;
+         break;
+      case 3:
+         $gapOpen = 12;
+         $gapExtend = 3;
+         break;
+      case 4:
+         $gapOpen = 11;
+         $gapExtend = 3;
+         break;
+      case 5:
+         $gapOpen = 17;
+         $gapExtend = 2;
+         break;
+      case 6:
+         $gapOpen = 16;
+         $gapExtend = 2;
+         break;
+      case 7:
+         $gapOpen = 15;
+         $gapExtend = 2;
+         break;
+      case 8:
+         $gapOpen = 14;
+         $gapExtend = 2;
+         break;
+      case 9:
+         $gapOpen = 13;
+         $gapExtend = 2;
+         break;
+      case 10:
+         $gapOpen = 21;
+         $gapExtend = 1;
+         break;
+      case 11:
+         $gapOpen = 20;
+         $gapExtend = 1;
+         break;
+      case 12:
+         $gapOpen = 19;
+         $gapExtend = 1;
+         break;
+      case 13:
+         $gapOpen = 18;
+         $gapExtend = 1;
+         break;
+      case 14:
+         $gapOpen = 17;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+   case 3:
+     $matrix ="BLOSUM80";
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 8;
+         $gapExtend = 2;
+         break;
+      case 1:
+         $gapOpen = 7;
+         $gapExtend = 2;
+         break;
+      case 2:
+         $gapOpen = 6;
+         $gapExtend = 2;
+         break;
+      case 3:
+         $gapOpen = 11;
+         $gapExtend = 1;
+         break;
+      case 4:
+         $gapOpen = 10;
+         $gapExtend = 1;
+         break;
+      case 5:
+         $gapOpen = 9;
+         $gapExtend = 1;
+         break;
+     }
+      break;
+   case 4:
+     $matrix ="BLOSUM62"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 11;
+         $gapExtend = 2;
+         break;
+      case 1:
+         $gapOpen = 10;
+         $gapExtend = 2;
+         break;
+      case 2:
+         $gapOpen = 9;
+         $gapExtend = 2;
+         break;
+      case 3:
+         $gapOpen = 8;
+         $gapExtend = 2;
+         break;
+      case 4:
+         $gapOpen = 7;
+         $gapExtend = 2;
+         break;
+      case 5:
+         $gapOpen = 6;
+         $gapExtend = 2;
+         break;
+      case 6:
+         $gapOpen = 13;
+         $gapExtend = 1;
+         break;
+      case 7:
+         $gapOpen = 12;
+         $gapExtend = 1;
+         break;
+      case 8:
+         $gapOpen = 11;
+         $gapExtend = 1;
+         break;
+      case 9:
+         $gapOpen = 10;
+         $gapExtend = 1;
+         break;
+      case 10:
+         $gapOpen = 9;
+         $gapExtend = 1;
+         break;
+     }
+      break;
+   case 5:
+     $matrix ="BLOSUM45"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 13;
+         $gapExtend = 3;
+         break;
+      case 1:
+         $gapOpen = 12;
+         $gapExtend = 3;
+         break;
+      case 2:
+         $gapOpen = 11;
+         $gapExtend = 3;
+         break;
+      case 3:
+         $gapOpen = 10;
+         $gapExtend = 3;
+         break;
+      case 4:
+         $gapOpen = 15;
+         $gapExtend = 2;
+         break;
+      case 5:
+         $gapOpen = 14;
+         $gapExtend = 2;
+         break;
+      case 6:
+         $gapOpen = 13;
+         $gapExtend = 2;
+         break;
+      case 7:
+         $gapOpen = 12;
+         $gapExtend = 2;
+         break;
+      case 8:
+         $gapOpen = 19;
+         $gapExtend = 1;
+         break;
+      case 9:
+         $gapOpen = 18;
+         $gapExtend = 1;
+         break;
+      case 10:
+         $gapOpen = 17;
+         $gapExtend = 1;
+         break;
+      case 11:
+         $gapOpen = 16;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+   case 6:
+     $matrix ="BLOSUM50"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 13;
+         $gapExtend = 3;
+         break;
+      case 1:
+         $gapOpen = 12;
+         $gapExtend = 3;
+         break;
+      case 2:
+         $gapOpen = 11;
+         $gapExtend = 3;
+         break;
+      case 3:
+         $gapOpen = 10;
+         $gapExtend = 3;
+         break;
+      case 4:
+         $gapOpen = 9;
+         $gapExtend = 3;
+         break;
+      case 5:
+         $gapOpen = 16;
+         $gapExtend = 2;
+         break;
+      case 6:
+         $gapOpen = 15;
+         $gapExtend = 2;
+         break;
+      case 7:
+         $gapOpen = 14;
+         $gapExtend = 2;
+         break;
+      case 8:
+         $gapOpen = 13;
+         $gapExtend = 2;
+         break;
+      case 9:
+         $gapOpen = 12;
+         $gapExtend = 2;
+         break;
+      case 10:
+         $gapOpen = 19;
+         $gapExtend = 1;
+         break;
+      case 11:
+         $gapOpen = 18;
+         $gapExtend = 1;
+         break;
+      case 12:
+         $gapOpen = 17;
+         $gapExtend = 1;
+         break;
+      case 13:
+         $gapOpen = 16;
+         $gapExtend = 1;
+         break;
+      case 14:
+         $gapOpen = 15;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+   case 7:
+     $matrix ="BLOSUM90"; 
+     $gapKey = $form_state['values']['gapCost'];
+     switch ($gapKey) {
+      case 0:
+         $gapOpen = 9;
+         $gapExtend = 2;
+         break;
+      case 1:
+         $gapOpen = 8;
+         $gapExtend = 2;
+         break;
+      case 2:
+         $gapOpen = 7;
+         $gapExtend = 2;
+         break;
+      case 3:
+         $gapOpen = 6;
+         $gapExtend = 2;
+         break;
+      case 4:
+         $gapOpen = 11;
+         $gapExtend = 1;
+         break;
+      case 5:
+         $gapOpen = 10;
+         $gapExtend = 1;
+         break;
+      case 6:
+         $gapOpen = 9;
+         $gapExtend = 1;
+         break;
+     }
+     break;
+  }
+  
+  if ( isset($form_state['qFlag']) ) {
+     if ( $form_state['qFlag'] == 'seqQuery' ) {
+        $seq_content = $form_state['values']['FASTA'];
+	$query = "/tmp/user__query_file.fasta";
+        file_put_contents ( $query , $seq_content);
+     } elseif ( $form_state['qFlag'] == 'upQuery' ) {
+        $query = $form_state['upQuery_path'];
+     }
+  }
+  
+  if ($form_state['dbFlag'] == 'upQuery') {
+     $subjectSeq = $form_state['upDB_path'];
+     $subSeqOut = drupal_basename($form_state['upDB_path']) . rand(0, 10000);
+     $blast_subj_cmd = "blastp -task blastp -query $query -subject $subjectSeq -out sites/default/files/$subSeqOut.blastp.html";
+// -evalue $eVal -word_size $wordSize -gapopen $gapOpen -gapextend $gapExtend -matrix $matrix -num_alignments 100 -html";
+     system($blast_subj_cmd);
+  } elseif ($form_state['dbFlag'] == 'blastdb') {
+     $selected_db = $form_state['values']['SELECT_DB'];
+     $blastdb_node = node_load($selected_db);
+     $blastdb_path = $blastdb_node->db_path;     
+     $blastdb_human_name = $form['DB']['SELECT_DB']['#options'][$selected_db];
+     $subSeqOut = str_replace(' ','_', $blastdb_human_name) . rand(0, 10000);
+     $blast_db_cmd = "blastp -task blastp -query $query -db $blastdb_path -out sites/default/files/$subSeqOut.blastp.html -evalue $eVal -word_size $wordSize -gapopen $gapOpen -gapextend $gapExtend -matrix $matrix -num_alignments 100 -html";
+     system($blast_db_cmd,$input);
+  }
+
+  $path = "$subSeqOut.blastp.html";
+  drupal_goto("blast/report/$path");
+}
+
+
+/**
+ * FASTA validating parser
+ *
+ * @param $sequence 
+ *  A string of characters to be validated. A sequence in FASTA format begins with a single-line description, followed by lines of sequence data. 
+ *  The description line is distinguished from the sequence data by a greater-than (">") symbol in the first column. 
+ *  The word following the ">" symbol is the identifier of the sequence, and the rest of the line is the description (both are optional). 
+ *  There should be no space between the ">" and the first letter of the identifier. The sequence ends if another line starting with a ">" appears; 
+ *  this indicates the start of another sequence.
+ *
+ * @return
+ *  Return a boolean. 1 if the sequence does not pass the format valifation stage and 0 otherwise.   
+ *
+ */
+function validateFasta($sequence) {
+	$fastaIdRegEx = '/^>.*(\\n|\\r)/';
+	$fastaSeqRegEx = '/[^acgturykmswbdhvnxACGTURYKMSWBDHVNX\*\-\n\r]/';
+	if ( preg_match($fastaSeqRegEx,$sequence) && !(preg_match($fastaIdRegEx,$sequence)) ) {
+      $flag = 1;
+   } else {
+      $flag = 0;
+   }
+   
+  return $flag;
+}
+
+
+/**
+ * Load the preexisting blast databases 
+ *
+ * @return
+ *  Return human readble names of the preexisting blast databases   
+ *
+ */
+function DB_options() {
+   $type = 'blastdb';
+   $nodes  = node_load_multiple(array(), array('type'=> $type));
+	
+   $options = array();
+
+   foreach ($nodes as $node) {
+      if ( isset($node) && isset($node->db_dbtype) ) {
+        if ( ($node->db_dbtype=='p') ) {                         
+         $options[$node->nid] = $node->db_name;
+        }
+      }
+   }
+
+   asort($options);
+   $options[0] = 'Select a Dataset';
+
+   return $options;
 }
 
+/**
+ * Fill the first dropdown list with appropriate options  
+ *
+ * @return
+ * An array consisting of matrices name for the first dropdown list   
+ *
+ */
 function _ajax_example_get_first_dropdown_options() {
   return drupal_map_assoc(array(
   t('PAM30'),	
@@ -193,6 +717,13 @@ function _ajax_example_get_first_dropdown_options() {
   ));
 }
 
+/**
+ * Fill the second dropdown list with appropriate options  
+ *
+ * @return
+ * An array containing open and extension gap values for the chosen matrix (to fill the second dropdown list)   
+ *
+ */
 function _ajax_example_get_second_dropdown_options($key = '') {
   $options = array(
     t('PAM30') => drupal_map_assoc(array(
@@ -297,6 +828,13 @@ function _ajax_example_get_second_dropdown_options($key = '') {
     }
 }
 
+/**
+ * Respond to Ajax dropdown call 
+ *
+ * @return
+ *     
+ *
+ */
 function ajax_example_dependent_dropdown_callback($form, $form_state) {
   return $form['ALG']['SParam']['gapCost'];
 }

+ 14 - 2
includes/blast_ui.node.inc

@@ -79,7 +79,16 @@ function blastdb_form($node, &$form_state) {
     '#required' => TRUE,
     '#default_value' => isset($node->db_path) ? $node->db_path : '',
   );
-
+  $form['db_dbtype'] = array(
+	'#type' => 'radios',
+	'#title' => t('Type of the blast database'),
+	'#options' => array(
+		'n' => t('Nucleotide'),
+		'p' => t('Protein'),
+	),
+	'#required' => TRUE,
+	'#default_value' => isset($node->db_dbtype) ? $node->db_dbtype : 'n',
+  );
   return $form;
 }
 
@@ -94,6 +103,7 @@ function blastdb_insert($node) {
     'nid' => $node->nid,
     'name' => $node->db_name,
     'path' => $node->db_path,
+    'dbtype' => $node->db_dbtype,
   ))->execute();
 
 }
@@ -117,6 +127,7 @@ function blastdb_update($node) {
     db_update('blastdb')->fields(array(
     'name' => $node->db_name,
     'path' => $node->db_path,
+    'dbtype' => $node->db_dbtype,
   ))->condition('nid', $node->nid)->execute();
 }
 
@@ -146,12 +157,13 @@ function blastdb_delete($node) {
 */
 function blastdb_load($nodes) {
     
-  $result = db_query('SELECT nid, name, path FROM {blastdb} WHERE nid IN (:nids)', array(':nids' => array_keys($nodes)));
+  $result = db_query('SELECT nid, name, path, dbtype FROM {blastdb} WHERE nid IN (:nids)', array(':nids' => array_keys($nodes)));
   
   foreach ($result as $record) {
     $nodes[$record->nid]->db_name = $record->name;
     $nodes[$record->nid]->db_path = $record->path;
     $nodes[$record->nid]->title = $record->name;
+    $nodes[$record->nid]->db_dbtype = $record->dbtype;
   }
 
 }

BIN
theme/.blast_report.tpl.php.swp


BIN
theme/arrows.png


+ 78 - 0
theme/blast_report.css

@@ -0,0 +1,78 @@
+#blast_report h4 {
+  margin: 0px;
+  padding: 0px;
+}
+#blast_report img {
+  float:right;
+}
+#blast_report ul {
+  margin:10px 0 10px 10px;
+  padding: 0px;
+}
+#blast_report th {
+/**
+  background: #7CB8E2 url(header_bkg.png) repeat-x scroll center left;
+  color: #fff;
+  padding: 7px 50px; */
+  text-align: left;
+}
+#blast_report td {
+/**
+  background:#C7DDEE none repeat-x scroll center left;
+  color:#000;
+  padding:7px 50px;
+*/
+}
+#blast_report tr.odd td {
+/**
+  background:#fff url(row_bkg.png) repeat-x scroll center left; */
+  cursor:pointer;
+}
+#blast_report .arrow {
+  background:transparent url(arrows.png) no-repeat scroll 0px -16px;
+  width:16px;
+  height:16px;
+  display:block;
+}
+#blast_report div.up {
+  background-position:0px 0px;
+}
+#blast_report td.number, #blast_report th.number {
+  width: 10px;
+}
+#blast_report td.evalue, #blast_report th.evalue {
+  width: 100px;
+  border-right: none;
+}
+#blast_report td.arrow-col, #blast_report th.arrow-col {
+  width: 10px;
+  border-left: none;
+}
+
+/**
+ * Alignment
+ */
+#blast_report tr.alignment-row .title{
+  font-weight: bold;
+}
+#blast_report tr.alignment-row .hsp-title{
+  padding-top: 15px;
+  font-weight: bold;
+}
+#blast_report tr.alignment-row{
+  width: 100%;
+}
+#blast_report .alignment {
+  width: 625px;
+}
+#blast_report .alignment-title {
+  font-weight: bold;
+}
+#blast_report div.alignment-row{
+  padding: 10px 30px;
+  height: 60px;
+  border: 1px solid #DDDDDD;
+  font-family: monospace;
+  overflow-x: scroll;
+  white-space: nowrap;
+}

+ 70 - 0
theme/blast_report.css~

@@ -0,0 +1,70 @@
+#report h4 { 
+  margin: 0px; 
+  padding: 0px;
+}
+#report img { 
+  float:right;
+}
+#report ul { 
+  margin:10px 0 10px 10px; 
+  padding: 0px; 
+}
+#report th { 
+/**
+  background: #7CB8E2 url(header_bkg.png) repeat-x scroll center left; 
+  color: #fff;
+  padding: 7px 50px; */
+  text-align: left;
+}
+#report td { 
+/**
+  background:#C7DDEE none repeat-x scroll center left; 
+  color:#000;
+  padding:7px 50px; 
+*/
+}
+#report tr.odd td { 
+/** 
+  background:#fff url(row_bkg.png) repeat-x scroll center left; */
+  cursor:pointer; 
+}
+#report div.arrow { 
+  background:transparent url(arrows.png) no-repeat scroll 0px -16px; 
+  width:16px; 
+  height:16px; 
+  display:block;
+}
+#report div.up { 
+  background-position:0px 0px;
+}
+#alignmentContent{
+/**
+  width: 600px; 
+  height:130px; 
+*/
+/**
+  border-style: solid; 
+  border-width: 0.5px; 
+  border-color:#C7DDEE; 
+*/
+  box-sizing:border-box; 
+  overflow-x:scroll; 
+  overflow-y: hidden; 
+  white-space: nowrap;
+}
+#report td.number, #report th.number {
+  width: 10px;
+}
+#report td.arrow-col, #report th.arrow-col {
+  width: 10px;
+}
+
+/**
+ * Alignment
+ */
+#report .alignment {
+  font-family: monospace;
+}
+#report .alignment-title {
+  font-weight: bold;
+}

+ 93 - 0
theme/blast_report.tpl.php

@@ -0,0 +1,93 @@
+<?php
+
+?>
+
+<script type="text/javascript">
+  $(document).ready(function(){
+    $("#blast_report tr:not(.result-summary)").hide();
+    $("#blast_report tr:first-child").show();
+
+    $("#blast_report tr.result-summary").click(function(){
+      $(this).next("tr").toggle();
+      $(this).find(".arrow").toggleClass("up");
+    });
+  });
+</script>
+
+<?php
+//Load the XML file
+$path = current_path();
+if (preg_match('%blast/report/([\w\.]+)%',$path,$matches)) {
+  $filename = 'sites/default/files/' . $matches[1];
+  $xml=simplexml_load_file($filename);
+}
+
+$header = array(
+  'number' =>  array('data' => '#', 'class' => array('number')),
+  'query' =>  array('data' => 'Query Name', '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'))
+);
+
+$rows = array();
+$count = 0;
+
+foreach($xml->{'BlastOutput_iterations'}->children() as $iteration) {
+  foreach($iteration->{'Iteration_hits'}->children() as $hit) {
+    if (is_object($hit)) {
+      $count +=1;
+
+      $zebra_class = ($count % 2 == 0) ? 'even' : 'odd';
+
+      // SIMPLY SUMMARY ROW
+      $hit_name = $hit->Hit_def;
+      if (preg_match('/(\w+)/', $hit_name, $matches)) {
+        $hit_name = $matches[1];
+      }
+      $score = $hit->Hit_hsps->Hsp->Hsp_score;
+      $evalue = $hit->Hit_hsps->Hsp->Hsp_evalue;
+      $query_name = $iteration->{'Iteration_query-def'};
+
+      $row = array(
+        'data' => array(
+          'number' => array('data' => $count, 'class' => array('number')),
+          'query' => array('data' => $query_name, 'class' => array('query')),
+          'hit' => array('data' => l($hit_name,''), 'class' => array('hit')),
+          'evalue' => array('data' => $evalue, 'class' => array('evalue')),
+          'arrow-col' => array('data' => '<div class="arrow"></div>', 'class' => array('arrow-col'))
+        ),
+        'class' => array('result-summary')
+      );
+      $rows[] = $row;
+
+      // ALIGNMENT ROW (collapsed by default)
+      // Process HSPs
+      $HSPs = array();
+      foreach ($hit->{'Hit_hsps'}->children() as $hsp_xml) {
+        $HSPs[] = (array) $hsp_xml;
+      }
+
+      $row = array(
+        'data' => array(
+          'number' => '',
+          'query' => array(
+            'data' => theme('blast_report_alignment_row', array('HSPs' => $HSPs)),
+            'colspan' => 4,
+          )
+        ),
+        'class' => array('alignment-row', $zebra_class),
+        'no_striping' => TRUE
+      );
+      $rows[] = $row;
+
+    }
+  }
+}
+
+print theme('table', array(
+    'header' => $header,
+    'rows' => $rows,
+    'attributes' => array('id' => 'blast_report'),
+  ));
+?>

+ 44 - 0
theme/blast_report_alignment_row.tpl.php

@@ -0,0 +1,44 @@
+<?php
+/**
+ * This Template generates the HTML for a single Alignment row in a BLAST report
+ */
+dpm($HSPs, 'HPSPs');
+?>
+
+<div class="title">Alignment</div>
+
+<?php
+  foreach($HSPs as $hsp) {
+?>
+
+  <div class="hsp-title">HSP <?php print $hsp['Hsp_num']?></div>
+  <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;?>%)
+    </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;?>%)
+    </span>
+  </div>
+  <div class="alignment">
+    <div class="alignment-row">
+      <div class="query">
+        <span class="alignment-title">Query:</span>&nbsp;&nbsp;&nbsp;
+        <span class="alignment-residues"><?php print $hsp['Hsp_qseq']; ?></span>
+      </div>
+      <div class="matches">
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+        <span class="alignment-residues"><?php print $hsp['Hsp_midline']; ?></span>
+      </div>
+      <div class="subject">
+        <span class="alignment-title">Subject:</span>&nbsp;
+        <span class="alignment-residues"><?php print $hsp['Hsp_hseq']; ?></span>
+      </div>
+    </div>
+  </div>
+
+<?php
+  }
+?>

+ 13 - 0
theme/blast_ui.theme.inc

@@ -0,0 +1,13 @@
+<?php
+
+function blast_ui_preprocess_show_blast_report(&$vars) {
+
+   $path = drupal_get_path('module', 'blast_ui');
+ 
+   drupal_add_css($path . '/theme/blast_report.css');
+   drupal_add_js('http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js');
+
+}
+
+
+?>

+ 14 - 0
theme/blast_ui.theme.inc~

@@ -0,0 +1,14 @@
+<?php
+
+function blast_ui_preprocess_blast_show_report(&$vars) {
+
+dpm('in preprocess');
+   $path = drupal_get_path('module', 'blast_ui');
+ 
+   drupal_add_css($path . '/theme/blast_report.css');
+   drupal_add_js('http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js');
+
+}
+
+
+?>

+ 14 - 0
theme/jExpand.js

@@ -0,0 +1,14 @@
+(function($){
+    $.fn.jExpand = function(){
+        var element = this;
+
+        $(element).find("tr:odd").addClass("odd");
+        $(element).find("tr:not(.odd)").hide();
+        $(element).find("tr:first-child").show();
+
+        $(element).find("tr.odd").click(function() {
+            $(this).next("tr").toggle();
+        });
+        
+    }    
+})(jQuery);