Browse Source

Added CViTj support

E.Cannon 7 years ago
parent
commit
9a2e308f10

+ 145 - 2
includes/blast_ui.admin.inc

@@ -31,7 +31,7 @@ function blast_ui_admin_form($form, $form_state) {
 
 
    $form['general']['eVal']= array(
    $form['general']['eVal']= array(
     '#type' => 'textfield',
     '#type' => 'textfield',
-    '#title' => t('Default e-Value (Expected Threshold)'),
+    '#title' => t('Default e-value (Expected Threshold)'),
     '#description' => t('Expected number of chance matches in a random model. This number should be give in a decimal format.'),
     '#description' => t('Expected number of chance matches in a random model. This number should be give in a decimal format.'),
      '#default_value' => variable_get('eVal', 0.001),
      '#default_value' => variable_get('eVal', 0.001),
     //'#default_value' => variable_get('blast_threads', 1),
     //'#default_value' => variable_get('blast_threads', 1),
@@ -151,6 +151,62 @@ KRSLEEGLKTTGEGLDWGVLFGFGPGLTIETVVLRSVAI';
     '#default_value' => variable_get('blast_ui_max_results_displayed', 500)
     '#default_value' => variable_get('blast_ui_max_results_displayed', 500)
   );
   );
 
 
+  // CVITJS
+  $description = 'The JavaScript program CViTjs enables users to see BLAST hits on an '
+               . 'entire genome assembly. See the help tab for information on how to '
+               . 'download and set up CViTjs.';
+  $form['cvitjs'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => true,
+    '#collapsed' => true,
+    '#title' => 'Enable and configure genome visualization',
+    '#description' => $description,
+  );
+
+  $description = 'CViTjs is only applicable for genome BLAST targets. After it is '
+               . 'enabled here, CViTjs will need to be enabled for each applicable BLAST '
+              . 'target node.';
+  $form['cvitjs']['explanation'] = array(
+    '#markup' => t($description),
+  );
+
+  $form['cvitjs']['cvitjs_enable'] = array(
+    '#type' => 'checkbox',
+    '#title' => 'Enable CViTjs',
+    '#description' => 'When checked, CViTjs will be enabled.',
+    '#default_value' => variable_get('blast_ui_cvitjs_enabled', FALSE)
+  );
+
+  $form['cvitjs']['cvitjs_location'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Path to CViTjs code',
+    '#description' => 'Path is relative to the location of this module. Example: js/cvitjs',
+    '#default_value' => variable_get('blast_ui_cvitjs_location', '')
+  );
+
+  // Get CViTjs confuration text, if possible.
+  if (!$default_value = blast_ui_get_cvit_conf_text()) {
+    $default_value = 'Unable to get CViTjs configuration information. '
+                   . 'You will need to enable whole genome views and set and save the '
+                   . 'path to CViTjs before you can edit the CViTjs configuration text.';
+    $disabled = true;
+  }
+  else {
+    $disabled = false;
+  }
+  
+  $description = 'This is the file that defines data directories and backbone GFF files '
+               . 'for each genome assembly target. It is named cvit.conf and is in the '
+               . 'root directory for the CViTjs javascript code.';
+  $form['cvitjs']['cvitjs_config'] = array(
+    '#type' => 'textarea',
+    '#title' => 'CViTjs configuration (empty until CViTjs path is saved)',
+    '#description' => $description,
+    '#default_value' => $default_value,
+    '#rows' => 10,
+    '#disabled' => $disabled,
+  );
+
   // SUBMIT
   // SUBMIT
   $form['submit'] = array(
   $form['submit'] = array(
     '#type' => 'submit',
     '#type' => 'submit',
@@ -176,8 +232,79 @@ function blast_ui_admin_form_validate($form, &$form_state) {
     }
     }
   }
   }
 
 
+  // Check path to CViTjs executable and make sure cvit.conf is writable
+  if ($form_state['values']['cvitjs_enable']) {
+    $cvit_path = blast_ui_get_cvit_conf($form_state['values']['cvitjs_location']);
+    if (!$cvit_path || !file_exists($cvit_path)) {
+      $msg = "The CViTjs configuration file, cvit.conf, does not exist at the path given (" 
+           . $form_state['values']['cvitjs_location']
+           . "). Please check your path. "
+           . "If you have not yet downloaded CViTjs, see the help tab for more information.";
+      form_set_error('cvitjs_location', t($msg));
+    }
+    
+    if (!is_writable($cvit_path)) {
+      $msg = "The file $cvit_path is not writable by this page. "
+           . "Please enable write access for apache then try saving these settings again.";
+      form_set_error('cvitjs_location', t($msg));
+    }
+  }
+  
+  // Empty contents of cvitjs_config textarea if it is disabled
+  if ($form['cvitjs']['cvitjs_config']['#disabled']) {
+    $form_state['values']['cvitjs_config'] = '';
+  }
+
+  // Check CViTjs configuration text
+  if ($form_state['values']['cvitjs_config']
+        && !preg_match('/\[general\]\s*\ndata_default =.*/m',
+                       $form_state['values']['cvitjs_config'])) {
+    $msg = "The CViTjs configuration text looks incorrect. "
+         . "It should contain a [general] section. "
+         . "See the help tab for more information.";
+    form_set_error('cvitjs_config', t($msg));
+  }
+  if ($form_state['values']['cvitjs_config']
+        && !preg_match('/\[.*\]\s*\nconf = .*\ndefaultData =.*/m', 
+                       $form_state['values']['cvitjs_config'])) {
+    $msg = "The CViTjs configuration text looks incorrect. "
+         . "It should contain one section for each genome target. "
+         . "See the help tab for more information.";
+    form_set_error('cvitjs_config', t($msg));
+  }    
+}
+
+
+/**
+ * Get text from cvitjs conf file, if possible.
+ */
+function blast_ui_get_cvit_conf_text() {
+  if ($cvit_conf=blast_ui_get_cvit_conf(variable_get('blast_ui_cvitjs_location', false))) {
+    if ($contents=file_get_contents($cvit_conf)) {
+      return $contents;
+    }
+  }
+  
+  return false;
 }
 }
 
 
+
+/**
+ * Get path to cvitjs conf file.
+ */
+function blast_ui_get_cvit_conf($cvitjs_location) {
+  if (!$cvitjs_location) {
+    return false;
+  }
+  
+  $cvit_conf_path = drupal_get_path('module','blast_ui') 
+                  . DIRECTORY_SEPARATOR . $cvitjs_location
+                  . DIRECTORY_SEPARATOR . 'cvit.conf';
+             
+  return $cvit_conf_path;
+}
+
+
 /**
 /**
  * Submit the Admin/settings form.
  * Submit the Admin/settings form.
  */
  */
@@ -197,6 +324,22 @@ function blast_ui_admin_form_submit($form, $form_state) {
   variable_set('blast_ui_nucleotide_example_sequence', $form_state['values']['nucleotide_example']);
   variable_set('blast_ui_nucleotide_example_sequence', $form_state['values']['nucleotide_example']);
   variable_set('blast_ui_protein_example_sequence', $form_state['values']['protein_example']);
   variable_set('blast_ui_protein_example_sequence', $form_state['values']['protein_example']);
   
   
-/**: added by safetybrake*/
+  // Protect against large result sets
   variable_set('blast_ui_max_results_displayed', $form_state['values']['max_results_displayed']);
   variable_set('blast_ui_max_results_displayed', $form_state['values']['max_results_displayed']);
+
+  // Whole genome visualization - CViTjs
+  variable_set('blast_ui_cvitjs_enabled', $form_state['values']['cvitjs_enable']);
+  variable_set('blast_ui_cvitjs_location', $form_state['values']['cvitjs_location']);
+  if ($form_state['values']['cvitjs_enable'] && $form_state['values']['cvitjs_config']) {
+    // Need absolute path to conf file to write
+    $cvit_conf_path = getcwd() . DIRECTORY_SEPARATOR
+                    . blast_ui_get_cvit_conf($form_state['values']['cvitjs_location']);
+    if ($fh = fopen($cvit_conf_path, 'w')) {
+      fwrite($fh, $form_state['values']['cvitjs_config']);
+      fclose($fh);
+    }
+    else {
+      drupal_set_message("Unable to open CViTjs conf file for writing: <pre>" . print_r(error_get_last(),true) . "</pre>");
+    }
+  }
 }
 }

+ 50 - 2
includes/blast_ui.node.inc

@@ -233,6 +233,38 @@ function blastdb_form($node, &$form_state) {
     );
     );
   }
   }
     
     
+  // CViTjs settings, if enabled
+  if (variable_get('blast_ui_cvitjs_enabled', false)) {
+    $form['cvitjs'] = array(
+      '#type' => 'fieldset',
+      '#title' => 'Whole Genome Visualization',
+      '#description' => 'Settings for the display of BLAST hits on an entire genome assembly using CViTjs.',
+      '#prefix' => '<div id="cvitjs-settings">',
+      '#suffix' => '</div>',
+    );
+    
+    $form['cvitjs']['cvitjs_enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show BLAST hits on the genome in the results page.'),
+      '#description' => t('Uses CViTjs to display BLAST hits on the entire genome'),
+      '#default_value' => (isset($node->cvitjs_enabled)) ? $node->cvitjs_enabled : false,
+      '#ajax' => array(
+        'callback' => 'ajax_blast_ui_node_cvitjs_custom_callback',
+        'wrapper' => 'cvitjs-settings',
+      )
+    );
+
+    if (isset($form_state['values'])) {
+      $cvitjs_enabled = $form_state['values']['cvitjs_enabled'];
+    }
+    else if (isset($node->cvitjs_enabled))  {
+      $cvitjs_enabled = $node->cvitjs_enabled;
+    }
+    else {
+      $cvitjs_enabled = false;
+    }
+  }
+  
   return $form;
   return $form;
 }
 }
 
 
@@ -303,6 +335,7 @@ function blastdb_insert($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->execute();
   ))->execute();
 }
 }
 
 
@@ -349,6 +382,7 @@ function blastdb_update($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->condition('nid', $node->nid)->execute();
   ))->condition('nid', $node->nid)->execute();
 }
 }
 
 
@@ -376,7 +410,7 @@ function blastdb_load($nodes) {
 
 
   $sql = "
   $sql = "
     SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id, 
     SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id, 
-           dbxref_linkout_type
+           dbxref_linkout_type, cvitjs_enabled
     FROM {blastdb} 
     FROM {blastdb} 
     WHERE nid IN (:nids)";
     WHERE nid IN (:nids)";
   $result = db_query($sql, array(':nids' => array_keys($nodes)));
   $result = db_query($sql, array(':nids' => array_keys($nodes)));
@@ -389,6 +423,9 @@ function blastdb_load($nodes) {
     $nodes[$record->nid]->title = $record->name;
     $nodes[$record->nid]->title = $record->name;
     $nodes[$record->nid]->db_dbtype = $record->dbtype;
     $nodes[$record->nid]->db_dbtype = $record->dbtype;
 
 
+    // CViTjs status
+    $nodes[$record->nid]->cvitjs_enabled  = $record->cvitjs_enabled;
+
     // Determine the type of link-out chosen.
     // Determine the type of link-out chosen.
     $types = module_invoke_all('blast_linkout_info');
     $types = module_invoke_all('blast_linkout_info');
     $type = NULL;
     $type = NULL;
@@ -419,7 +456,7 @@ function blastdb_load($nodes) {
       }
       }
     }
     }
 
 
-    // finally add information related to link-outs to the node.
+    // Add information related to link-outs to the node.
     if ($add_linkout) {
     if ($add_linkout) {
       $nodes[$record->nid]->linkout = new stdClass();
       $nodes[$record->nid]->linkout = new stdClass();
 
 
@@ -475,3 +512,14 @@ function blastdb_load($nodes) {
 function ajax_blast_ui_node_linkout_custom_callback($form, $form_state) {
 function ajax_blast_ui_node_linkout_custom_callback($form, $form_state) {
   return $form['dbxref'];
   return $form['dbxref'];
 }
 }
+
+/**
+ * AJAX Callback: Update Node CViTjs fields.
+ *
+ * On BlastDB node form, if CViTjs is enabled, a number of additional settings are 
+ * required. This callback refreshes the CViTjs settings fields so the additional 
+ * fields are displayed if CViTjs is enable, hidden otherwise.
+ */
+function ajax_blast_ui_node_cvitjs_custom_callback($form, $form_state) {
+  return $form['cvitjs'];
+}

+ 56 - 1
theme/blast_help.tpl.php

@@ -16,7 +16,8 @@
 <p>This module provides a basic interface to allow your users to utilize your server's NCBI BLAST+.</p>
 <p>This module provides a basic interface to allow your users to utilize your server's NCBI BLAST+.</p>
 
 
 <p>
 <p>
-  <a href="#setup">Setup</a> | <a href="#function">Functionality</a>
+  <a href="#setup">Setup</a> | <a href="#function">Functionality</a> 
+  | <a href="#protection">Large jobs | <a href="#genomeview">Genome visualization</a>
 </p>
 </p>
 
 
 <a name="setup"></a>
 <a name="setup"></a>
@@ -89,6 +90,8 @@
   </li>
   </li>
 </ul>
 </ul>
 
 
+<a name="protection"</a></a>
+&mdash;
 <h3><b>Protection Against Large Jobs</b></h3>
 <h3><b>Protection Against Large Jobs</b></h3>
 Depending on the size and nature of your target databases, you may wish to constrain use 
 Depending on the size and nature of your target databases, you may wish to constrain use 
 of this module.
 of this module.
@@ -105,3 +108,55 @@ of this module.
   </li>
   </li>
 </ol>
 </ol>
 
 
+<a name="genomeview"></a>
+&mdash;
+<h3><b>Whole Genome Visualization</b></h3>
+This module can be configured to use 
+<a href="https://github.com/LegumeFederation/cvitjs">CViTjs</a> to display BLAST hits on 
+a genome image. To configure this module to use CViTjs:
+<ol>
+  <li>
+    <a href="https://github.com/LegumeFederation/cvitjs">Download CViTjs</a> and copy
+    the code to your webserver. It might make the most sense to put the code directly into
+    this module's directory, in a subdirectory named <b>js</b>.
+  </li>
+  <li>
+    Enable CViTjs from the BLAST module administration page and provide the path to the
+    root directory for the CViTjs code relative to this module. For example, <b>js/cvitjs</b>.
+  </li>
+  <li>
+    CViTjs will have a config file in its root directory named cvit.conf. This file 
+    provides information for whole genome visualization for each genome BLAST target.
+    <b>Make sure the config file can be edited by your web server.</b>
+  </li>
+  <li>
+    Edit the configuration file to define each genome target. These will look like:
+    <pre>
+[data.Cajanus cajan - genome]
+conf = data/cajca/cajca.conf
+defaultData = data/cajca/cajca.gff</pre>
+    Where:<br>
+    &mdash;the section name, "data.Cajanus cajan - genome", consists of "data." followed
+    by the name of the BLAST target node,<br>
+    &mdash;the file "cajca.conf" is a cvit configuration file which describes how to draw the 
+    chromosomes and BLAST hits on the <i>Cajanus cajan</i> genome,<br>
+    &mdash;and the file "cajca.gff" is a GFF3 file that describes the <i>Cajanus cajan</i> 
+    chromosomes.<br>
+    You will have to put the target-specific conf and gff files (e.g. cajca.conf and 
+    cjca.gff) on your web server, in the directory, <b>js/cvitjs/data</b>. You may choose
+    to group files for each genome into subdirectories, for example, 
+    <b>js/cvitjs/data/cajca</b>.
+    <br><br>
+    At the top of the configuration file there must be a [general] section that defines
+    the default data set. For example:
+    <pre>
+[general]
+data_default = data.Cajanus cajan - genome</pre>
+  </li>
+  <li>
+    Edit the nodes for each genome target (nodes of type "Blast Database") and enable whole 
+    genome visualization. Remember that the names listed in the CViTjs config file must 
+    match the BLAST node name. In the example above, the BLAST database node for the
+    <i>Cajanus cajan</i> genome assembly is named "Cajanus cajan - genome"
+  </li>
+</ol>

+ 35 - 4
theme/blast_report.tpl.php

@@ -86,10 +86,41 @@ $no_hits = TRUE;
       </div>
       </div>
     </div>
     </div>
 
 
-    <br />
-    <div class="num-results">
-      <strong>Number of Results</strong>: <?php print $num_results; ?>
-    </div>
+    <?php
+      if (isset($blast_job->blastdb->cvitjs_enabled)
+            && $blast_job->blastdb->cvitjs_enabled == '1') {
+        $cvitjs_location = variable_get('blast_ui_cvitjs_location', '');
+    ?>
+      <!-- CViTjs image of BLAST hits, if enabled -->
+      <div class="cvitjs">
+        <div id="title-div"></div>
+        <div id="cvit-div"></div>
+      </div>
+      <?php
+        drupal_add_js(array(
+          'blast_ui'=> array(
+            'dataset' => $blast_job->blastdb->db_name)
+          ),
+          'setting'
+        );
+        drupal_add_js(array(
+          'blast_ui'=> array(
+            'gff' => '../../' . $blast_job->files->result->gff)),'setting'
+        );    
+        $base = drupal_get_path('module','blast_ui') 
+                . DIRECTORY_SEPARATOR . $cvitjs_location
+                . DIRECTORY_SEPARATOR . 'js'
+                . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR;
+echo "Base path for CViTjs is [$base]<br>";
+        drupal_add_css($base.'bootstrap/css/bootstrap.min.css',array('preprocess'=>FALSE));
+        drupal_add_css($base.'hopscotch/css/hopscotch.min.css',array('preprocess'=>FALSE));
+        drupal_add_css($base.'../../css/cvit.css',array('preprocess'=> FALSE));
+        drupal_add_js($base.'require/require.js',array('group'=>'JS_LIBRARY','type'=>'file'));
+        drupal_add_js($base.'require/blast_ui-config.js',array('group'=>'JS_THEME'));
+      ?>
+    <?php  
+      }
+    ?>
 
 
   </div>
   </div>
   <br />
   <br />

+ 17 - 0
theme/css/blast_report.css

@@ -68,3 +68,20 @@ table#blast_report div.alignment-row{
 table#blast_report div.alignment-subrow{
 table#blast_report div.alignment-subrow{
   padding-bottom: 15px;
   padding-bottom: 15px;
 }
 }
+
+/* CViTjs support */
+.blast-top:after {
+   clear: both;
+   display: table;
+   content: "";
+}
+.blast-job-info {
+  float: left;
+}
+.cvitjs {
+  float: left;
+}
+.report-table {
+  clear: both;
+  position: static;
+}