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(
     '#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.'),
      '#default_value' => variable_get('eVal', 0.001),
     //'#default_value' => variable_get('blast_threads', 1),
@@ -151,6 +151,62 @@ KRSLEEGLKTTGEGLDWGVLFGFGPGLTIETVVLRSVAI';
     '#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
   $form['submit'] = array(
     '#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.
  */
@@ -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_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']);
+
+  // 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;
 }
 
@@ -303,6 +335,7 @@ function blastdb_insert($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->execute();
 }
 
@@ -349,6 +382,7 @@ function blastdb_update($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->condition('nid', $node->nid)->execute();
 }
 
@@ -376,7 +410,7 @@ function blastdb_load($nodes) {
 
   $sql = "
     SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id, 
-           dbxref_linkout_type
+           dbxref_linkout_type, cvitjs_enabled
     FROM {blastdb} 
     WHERE nid IN (:nids)";
   $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]->db_dbtype = $record->dbtype;
 
+    // CViTjs status
+    $nodes[$record->nid]->cvitjs_enabled  = $record->cvitjs_enabled;
+
     // Determine the type of link-out chosen.
     $types = module_invoke_all('blast_linkout_info');
     $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) {
       $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) {
   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>
-  <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>
 
 <a name="setup"></a>
@@ -89,6 +90,8 @@
   </li>
 </ul>
 
+<a name="protection"</a></a>
+&mdash;
 <h3><b>Protection Against Large Jobs</b></h3>
 Depending on the size and nature of your target databases, you may wish to constrain use 
 of this module.
@@ -105,3 +108,55 @@ of this module.
   </li>
 </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>
 
-    <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>
   <br />

+ 17 - 0
theme/css/blast_report.css

@@ -68,3 +68,20 @@ table#blast_report div.alignment-row{
 table#blast_report div.alignment-subrow{
   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;
+}