Browse Source

Nightly checkin .... fixed some issues that caused log entries. working on adding CDS sequences to sequence page

Stephen Ficklin 11 năm trước cách đây
mục cha
commit
3b15f3b503

+ 1 - 3
tripal_bulk_loader/tripal_bulk_loader.module

@@ -36,9 +36,7 @@ require_once 'api/tripal_bulk_loader.DEPRECATED.inc';
  * @ingroup tripal_bulk_loader
  */
 function tripal_bulk_loader_init() {
-  // Add javascript and style sheet
-  drupal_add_css(drupal_get_path('theme', 'tripal') . '/css/tripal_bulk_loader.css');
-  drupal_add_js(drupal_get_path('theme', 'tripal') . '/js/tripal_bulk_loader.js');
+
 }
 
 /**

+ 1 - 1
tripal_core/theme/templates/node--chado-generic.tpl.php

@@ -3,7 +3,7 @@
 if($teaser) {
   print render($content);
 }
-else { 
+else {
   $node_type = $node->type; ?>
   
   <script type="text/javascript">

+ 1 - 1
tripal_cv/api/tripal_cv.api.inc

@@ -548,7 +548,7 @@ function tripal_insert_cvterm($term, $options = array()) {
 
   // add the database. The function will just return the DB object if the
   // database already exists.
-  $db = tripal_db_get_db_by_name($dbname);
+  $db = tripal_get_db(array('name' => $dbname));
   if (!$db) {
     $db = tripal_db_add_db($dbname);
   }

+ 0 - 11
tripal_cv/tripal_cv.module

@@ -34,17 +34,6 @@ require_once 'includes/tripal_cv.cvtermpath_form.inc';
  */
 function tripal_cv_init() {
 
-  // add the tripal_cv JS and CSS
-  drupal_add_css(drupal_get_path('module', 'tripal_cv') . '/theme/css/tripal_cv.css');
-  drupal_add_js(drupal_get_path('module', 'tripal_cv') . '/theme/js/tripal_cv.js');
-
-  // add the jgCharts.js
-  drupal_add_js(drupal_get_path('module', 'tripal_cv') . '/theme/js/jgcharts/jgcharts.js');
-
-  // add the jsTree JS and CSS
-  drupal_add_css(drupal_get_path('module', 'tripal_cv') . '/theme/js/jsTree/source/tree_component.css');
-  drupal_add_js(drupal_get_path('module', 'tripal_cv') . '/theme/js/jsTree/source/_lib.js');
-  drupal_add_js(drupal_get_path('module', 'tripal_cv') . '/theme/js/jsTree/source/tree_component.js');
 }
 
 /**

+ 2 - 2
tripal_db/api/tripal_db.api.inc

@@ -37,8 +37,8 @@
  * @param $identifier
  *   An array with the key stating what the identifier is. Supported keys (only on of the
  *   following unique keys is required):
- *    - db_id: the chado cv.cv_id primary key
- *    - name: the chado cv.name field (assume unique)
+ *    - db_id: the chado db.db_id primary key
+ *    - name: the chado db.name field (assume unique)
  * @param $options
  *   An array of options. Supported keys include:
  *     - Any keys supported by chado_generate_var(). See that function definition for

+ 2 - 2
tripal_example/tripal_example.info

@@ -32,13 +32,13 @@ version = 7.x-2.0.1-alpha
 ; Stylesheets containing CSS that should always be available for the
 ; module should be specified here.  
 ;
-stylesheets[all][] = theme/css/tripal_feature.css
+stylesheets[all][] = theme/css/tripal_example.css
 
 ;
 ; Javascript files that should always be available for the
 ; module should be specified here.  
 ;
-scripts[]          = theme/js/tripal_feature.js
+scripts[]          = theme/js/tripal_example.js
 
 ; 
 ; Add additional dependencies for other modules using the module project name.

+ 8 - 8
tripal_feature/api/tripal_feature.DEPRECATED.inc

@@ -376,9 +376,9 @@ function tripal_feature_reverse_complement($sequence) {
 /**
  * @deprecated Restructured API to make naming more readable and consistent.
  * Function was deprecated in Tripal 2.0 and will be removed 2 releases from now.
- * This function has been replaced by tripal_format_sequence().
+ * This function has been replaced by tripal_get_sequence().
  *
- * @see tripal_format_sequence().
+ * @see tripal_get_sequence().
  */
 function tripal_feature_get_formatted_sequence($feature_id, $feature_name, $num_bases_per_line, $derive_from_parent, $aggregate, $output_format, $upstream, $downstream, $sub_features = array(), $relationship = '', $rel_part = '') {
 
@@ -388,11 +388,11 @@ function tripal_feature_get_formatted_sequence($feature_id, $feature_name, $num_
     "DEPRECATED: %old_function has been replaced with %new_function. Please update your code.",
     array(
       '%old_function'=>'tripal_feature_get_formatted_sequence',
-      '%new_function' => 'tripal_format_sequence'
+      '%new_function' => 'tripal_get_sequence'
     )
   );
 
-  return tripal_format_sequence(
+  return tripal_get_sequence(
     // Feature
     array(
       'feature_id' => $feature_id,
@@ -474,9 +474,9 @@ function tripal_feature_add_cvterm($feature_id, $cvname, $cvterm) {
 /**
  * @deprecated Restructured API to make naming more readable and consistent.
  * Function was deprecated in Tripal 2.0 and will be removed 2 releases from now.
- * This function has been replaced by tripal_get_fasta_sequence().
+ * This function has been replaced by tripal_format_fasta_sequence().
  *
- * @see tripal_get_fasta_sequence().
+ * @see tripal_format_fasta_sequence().
  */
 function tripal_feature_return_fasta($feature, $desc) {
 
@@ -486,9 +486,9 @@ function tripal_feature_return_fasta($feature, $desc) {
     "DEPRECATED: %old_function has been replaced with %new_function. Please update your code.",
     array(
       '%old_function'=>'tripal_feature_return_fasta',
-      '%new_function' => 'tripal_get_fasta_sequence'
+      '%new_function' => 'tripal_format_fasta_sequence'
     )
   );
 
-  return tripal_get_fasta_sequence($feature, $desc);
+  return tripal_format_fasta_sequence($feature, $desc);
 }

+ 159 - 187
tripal_feature/api/tripal_feature.api.inc

@@ -54,64 +54,62 @@ function tripal_reverse_compliment_sequence($sequence) {
  * @param $options
  *   An associative array of options. Valid keys include:
  *    - width: Indicate the number of bases to use per line.  A new line will be added
- *      after the specified number of bases on each line.
+ *        after the specified number of bases on each line.
  *    - derive_from_parent: Set to '1' if the sequence should be obtained from the parent
- *      to which this feature is aligned.
+ *        to which this feature is aligned.
  *    - aggregate: Set to '1' if the sequence should only contain sub features, excluding
- *      intro sub feature sequence.  For example, set this option to obtain just
- *      the coding sequence of an mRNA.
+ *        intro sub feature sequence.  For example, set this option to obtain just
+ *        the coding sequence of an mRNA.
  *    - output_format: The type of format.  Valid formats include 'fasta_html', 'fasta_txt' and
- *      'raw'.  The format 'fasta_txt' outputs line breaks as <br> tags and the entire
- *      return value is in a <span> tag with a fixed-width font definition.  'fasta_txt'
- *      outputs line breaks with windows format carriage returns (e.g. \r\n) with no other
- *      formatting. The raw format is simply the sequence with now FASTA formatting and no
- *      line breaks.
+ *        'raw'.  The format 'fasta_txt' outputs line breaks as <br> tags and the entire
+ *        return value is in a <span> tag with a fixed-width font definition.  'fasta_txt'
+ *        outputs line breaks with windows format carriage returns (e.g. \r\n) with no other
+ *        formatting. The raw format is simply the sequence with no FASTA formatting and no
+ *        line breaks.
  *    - num_upstream: An integer specifing the number of upstream bases to include in the output
  *    - num_downstream: An integer specifying the number of downstream bases to include in the
- *      output.
+ *        output.
  *    - sub_feature_types: Only include sub features (or child features) of the types
- *      provided in the array
+ *        provided in the array
  *    - relationship_type: If a relationship name is provided (e.g. sequence_of) then any
- *      sequences that are in relationships of this type with matched sequences are also included
+ *        sequences that are in relationships of this type with matched sequences are also included
  *    - relationship_part: If a relationship is provided in the preceeding argument then
- *      the rel_part must be either 'object' or 'subject' to indicate which side of the
- *      relationship the matched features belong
+ *        the rel_part must be either 'object' or 'subject' to indicate which side of the
+ *        relationship the matched features belong
  *
  * @return
  *   The DNA/protein sequence formated as requested.
  *
  * @ingroup tripal_feature_api
  */
-function tripal_format_sequence($feature, $options) {
-
-  // Default Values
-  $feature_id = $feature['feature_id'];
-  $feature_name = $feature['name'];
-
-  $num_bases_per_line = $options['width'];
-  $derive_from_parent = $options['derive_from_parent'];
-  $aggregate = $options['aggregate'];
-  $output_format = $options['output_format'];
-  $upstream = $options['num_upstream'];
-  $downstream = $options['num_downstream'];
-  $sub_features = $options['sub_feature_types'];
-  $relationship = $options['relationship_type'];
-  $rel_part = $options['relationship_part'];
-
-  // to speed things up we need to make sure we have a persistent connection
-  $connection = tripal_db_persistent_chado();
-
-  if (!$upstream) {
-     $upstream = 0;
-  }
-  if (!$downstream) {
-     $downstream = 0;
+function tripal_get_sequence($feature, $options) {
+
+  // default values for finding the feature
+  $feature_id   = array_key_exists('feature_id', $feature) ? $feature['feature_id'] : 0;
+  $feature_name = array_key_exists('name', $feature)       ? $feature['name']       : '';
+
+  // default values for building the sequence
+  $num_bases_per_line = array_key_exists('width', $options)              ? $options['width']              : 50;
+  $derive_from_parent = array_key_exists('derive_from_parent', $options) ? $options['derive_from_parent'] : 0;
+  $aggregate          = array_key_exists('aggregate', $options)          ? $options['aggregate']          : 0;
+  $output_format      = array_key_exists('output_format', $options)      ? $options['output_format']      : 'fasta_txt';
+  $upstream           = array_key_exists('num_upstream', $options)       ? $options['num_upstream']       : 0;
+  $downstream         = array_key_exists('num_downstream', $options)     ? $options['num_downstream']     : 0;
+  $sub_features       = array_key_exists('sub_feature_types', $options)  ? $options['sub_feature_types']  : array();
+  $relationship       = array_key_exists('relationship_type', $options)  ? $options['relationship_type']  : '';
+  $rel_part           = array_key_exists('relationship_part', $options)  ? $options['relationship_part']  : '';
+  
+  if (!is_array($sub_features)) {
+    tripal_report_error('tripal_deprecated', TRIPAL_ERROR,
+      "'sub_features' option must be an array for function tripal_get_sequence().",
+      array()
+    );
+    return;
   }
 
   if ($rel_part == "object" or $rel_part == "subject") {
     if ($rel_part == "subject") {
-      $psql = '
-        PREPARE feature_rel_get_object (int, text) AS
+      $sql = '
         SELECT FO.feature_id, FO.name, FO.uniquename, CVTO.name as feature_type, O.genus, O.species
         FROM feature FS
           INNER JOIN feature_relationship FR ON FR.subject_id   = FS.feature_id
@@ -120,20 +118,13 @@ function tripal_format_sequence($feature, $options) {
           INNER JOIN cvterm CVTO             ON CVTO.cvterm_id  = FO.type_id
           INNER JOIN organism O              ON O.organism_id   = FO.organism_id
         WHERE
-          FS.feature_id = $1 AND
-          CVTFR.name    = $2
+          FS.feature_id = :feature_id AND
+          CVTFR.name    = :relationship
       ';
-      $status = tripal_core_chado_prepare('feature_rel_get_object', $psql, array('int', 'text'));
-      if (!$status) {
-        tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
-          array('%name' => 'feature_by_subject'));
-      }
-      $sql = "EXECUTE feature_rel_get_object(:feature_id, :relationship)";
       $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
     }
     if ($rel_part == "object") {
-      $psql = '
-        PREPARE feature_rel_get_subject (int, text) AS
+      $sql = '
         SELECT FS.feature_id, FS.name, FS.uniquename, CVTO.name as feature_type, O.genus, O.species
         FROM feature FO
           INNER JOIN feature_relationship FR ON FR.object_id    = FO.feature_id
@@ -142,15 +133,9 @@ function tripal_format_sequence($feature, $options) {
           INNER JOIN cvterm CVTO             ON CVTO.cvterm_id  = FS.type_id
           INNER JOIN organism O              ON O.organism_id   = FS.organism_id
         WHERE
-          FO.feature_id = $1 AND
-          CVTFR.name    = $2
+          FO.feature_id = :feature_id AND
+          CVTFR.name    = :relationship
       ';
-      $status = tripal_core_chado_prepare('feature_rel_get_subject', $psql, array('int', 'text'));
-      if (!$status) {
-        tripal_report_error('tripal_feature', TRIPAL_ERROR, "init: not able to prepare SQL statement '%name'",
-          array('%name' => 'feature_by_object'));
-      }
-      $sql = "EXECUTE feature_rel_get_subject(:feature_id, :relationship)";
       $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
     }
     $sequences = '';
@@ -163,135 +148,128 @@ function tripal_format_sequence($feature, $options) {
       if ($rel_part == "object") {
         $defline = "$feature->uniquename $feature->feature_type ($feature->genus $feature->species), $relationship, $feature_name";
       }
-      $sequences .= tripal_feature_get_formatted_sequence($feature->feature_id, $defline,
-        $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
-        $upstream, $downstream, $sub_features, '', '');
+      $sequences .= tripal_get_sequence(
+        array(
+          'feature_id' => $feature->feature_id, 
+          'name' => $defline
+        ),
+        array(
+          'width' => $num_bases_per_line, 
+          'derive_from_pareht' => $derive_from_parent, 
+          'aggregate' => $aggregate, 
+          'output_format' => $output_format,
+          'upstream' => $upstream, 
+          'downstream' => $downstream, 
+          'sub_features' => $sub_features, 
+        )
+      );
     }
     return $sequences;
   }
 
-  // prepare statements we'll need to use later
-  if (!tripal_core_is_sql_prepared('sequence_by_parent')) {
-    // prepare the queries we're going to use later during the render phase
-    // This SQL statement uses conditionals in the select clause to handle
-    // cases cases where the alignment is in the reverse direction and when
-    // the upstream and downstream extensions go beyond the lenght of the
-    // parent sequence.
-    $psql ='
-      PREPARE sequence_by_parent (int, int, int) AS
-      SELECT srcname, srcfeature_id, strand, srctypename, typename,
-        fmin, fmax, upstream, downstream, adjfmin, adjfmax,
-        substring(residues from (adjfmin + 1) for (upstream + (fmax - fmin) + downstream))  as residues,
-        genus, species
-      FROM (
-        SELECT
-          OF.name srcname, FL.srcfeature_id, FL.strand,
-          OCVT.name as srctypename, SCVT.name as typename,
-          FL.fmin, FL.fmax, OO.genus, OO.species,
-          CASE
-            WHEN FL.strand >= 0 THEN
-              CASE
-                 WHEN FL.fmin - $1 <= 0 THEN 0
-                 ELSE FL.fmin - $1
-              END
-            WHEN FL.strand < 0 THEN
-              CASE
-                 WHEN FL.fmin - $2 <= 0 THEN 0
-                 ELSE FL.fmin - $2
-              END
-          END as adjfmin,
-          CASE
-            WHEN FL.strand >= 0 THEN
-              CASE
-                WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen
-                ELSE FL.fmax + $2
-              END
-            WHEN FL.strand < 0 THEN
-              CASE
-                WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen
-                ELSE FL.fmax + $1
-              END
-          END as adjfmax,
-          CASE
-            WHEN FL.strand >= 0 THEN
-              CASE
-                 WHEN FL.fmin - $1 <= 0 THEN FL.fmin
-                 ELSE $1
-              END
-            ELSE
-              CASE
-                 WHEN FL.fmax + $1 > OF.seqlen THEN OF.seqlen - FL.fmax
-                 ELSE $1
-              END
-          END as upstream,
-          CASE
-            WHEN FL.strand >= 0 THEN
-              CASE
-                 WHEN FL.fmax + $2 > OF.seqlen THEN OF.seqlen - FL.fmax
-                 ELSE $2
-              END
-            ELSE
-              CASE
-                 WHEN FL.fmin - $2 <= 0 THEN FL.fmin
-                 ELSE $2
-              END
-          END as downstream,
-          OF.residues
-        FROM {featureloc} FL
-          INNER JOIN {feature} SF   on FL.feature_id    = SF.feature_id
-          INNER JOIN {cvterm}  SCVT on SF.type_id       = SCVT.cvterm_id
-          INNER JOIN {feature} OF   on FL.srcfeature_id = OF.feature_id
-          INNER JOIN {cvterm}  OCVT on OF.type_id       = OCVT.cvterm_id
-          INNER JOIN {organism} OO  on OF.organism_id   = OO.organism_id
-        WHERE SF.feature_id = $3 and NOT (OF.residues = \'\' or OF.residues IS NULL)) as tbl1
-    ';
-    $status = tripal_core_chado_prepare('sequence_by_parent', $psql, array('int', 'int', 'int'));
-    if (!$status) {
-      tripal_report_error('tripal_feature', TRIPAL_ERROR,
-        "init: not able to prepare SQL statement '%name'",
-        array('%name' => 'sequence_by_parent'));
-    }
-
-    // this query is meant to get all of the sub features of any given
-    // feature (arg #1) and order them as they appear on the reference
-    // feature (arg #2).
-    $psql ='PREPARE sub_features (int, int) AS
-            SELECT SF.feature_id, CVT.name as type_name, SF.type_id
-            FROM {feature_relationship} FR
-              INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
-              INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
-              INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
-              INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
-            WHERE FR.object_id = $1 and PF.feature_id = $2
-            ORDER BY FL.fmin ASC';
-    $status = tripal_core_chado_prepare('sub_features', $psql, array('int', 'int'));
-    if (!$status) {
-      tripal_report_error('tripal_feature', TRIPAL_ERROR,
-        "init: not able to prepare SQL statement '%name'",
-        array('%name' => 'ssub_features'));
-    }
-    $psql ='PREPARE count_sub_features (int, int) AS
-            SELECT count(*) as num_children
-            FROM {feature_relationship} FR
-              INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
-              INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
-              INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
-              INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
-            WHERE FR.object_id = $1 and PF.feature_id = $2';
-    $status = tripal_core_chado_prepare('count_sub_features', $psql, array('int', 'int'));
-    if (!$status) {
-      tripal_report_error('tripal_feature', TRIPAL_ERROR,
-        "init: not able to prepare SQL statement '%name'",
-        array('%name' => 'count_sub_features'));
-    }
-  }
+  // prepare the queries we're going to use later during the render phase
+  // This SQL statement uses conditionals in the select clause to handle
+  // cases cases where the alignment is in the reverse direction and when
+  // the upstream and downstream extensions go beyond the lenght of the
+  // parent sequence.
+  $sql ='
+    SELECT srcname, srcfeature_id, strand, srctypename, typename,
+      fmin, fmax, upstream, downstream, adjfmin, adjfmax,
+      substring(residues from (adjfmin + 1) for (upstream + (fmax - fmin) + downstream))  as residues,
+      genus, species
+    FROM (
+      SELECT
+        OF.name srcname, FL.srcfeature_id, FL.strand,
+        OCVT.name as srctypename, SCVT.name as typename,
+        FL.fmin, FL.fmax, OO.genus, OO.species,
+        CASE
+          WHEN FL.strand >= 0 THEN
+            CASE
+               WHEN FL.fmin - :upstream <= 0 THEN 0
+               ELSE FL.fmin - :upstream
+            END
+          WHEN FL.strand < 0 THEN
+            CASE
+               WHEN FL.fmin - :downstream <= 0 THEN 0
+               ELSE FL.fmin - :downstream
+            END
+        END as adjfmin,
+        CASE
+          WHEN FL.strand >= 0 THEN
+            CASE
+              WHEN FL.fmax + :downstream > OF.seqlen THEN OF.seqlen
+              ELSE FL.fmax + :downstream
+            END
+          WHEN FL.strand < 0 THEN
+            CASE
+              WHEN FL.fmax + :upstream > OF.seqlen THEN OF.seqlen
+              ELSE FL.fmax + :upstream
+            END
+        END as adjfmax,
+        CASE
+          WHEN FL.strand >= 0 THEN
+            CASE
+               WHEN FL.fmin - :upstream <= 0 THEN FL.fmin
+               ELSE :upstream
+            END
+          ELSE
+            CASE
+               WHEN FL.fmax + :upstream > OF.seqlen THEN OF.seqlen - FL.fmax
+               ELSE :upstream
+            END
+        END as upstream,
+        CASE
+          WHEN FL.strand >= 0 THEN
+            CASE
+               WHEN FL.fmax + :downstream > OF.seqlen THEN OF.seqlen - FL.fmax
+               ELSE :downstream
+            END
+          ELSE
+            CASE
+               WHEN FL.fmin - :downstream <= 0 THEN FL.fmin
+               ELSE :downstream
+            END
+        END as downstream,
+        OF.residues
+      FROM {featureloc} FL
+        INNER JOIN {feature} SF   on FL.feature_id    = SF.feature_id
+        INNER JOIN {cvterm}  SCVT on SF.type_id       = SCVT.cvterm_id
+        INNER JOIN {feature} OF   on FL.srcfeature_id = OF.feature_id
+        INNER JOIN {cvterm}  OCVT on OF.type_id       = OCVT.cvterm_id
+        INNER JOIN {organism} OO  on OF.organism_id   = OO.organism_id
+      WHERE SF.feature_id = :feature_id and NOT (OF.residues = \'\' or OF.residues IS NULL)) as tbl1
+  ';
+  // this query is meant to get all of the sub features of any given
+  // feature (arg #1) and order them as they appear on the reference
+  // feature (arg #2).
+  $sfsql = '
+    SELECT SF.feature_id, CVT.name as type_name, SF.type_id
+    FROM {feature_relationship} FR
+      INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
+      INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
+      INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
+      INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
+    WHERE FR.object_id = :feature_id and PF.feature_id = :srcfeature_id
+    ORDER BY FL.fmin ASC
+  ';
+  // for counting the number of children
+  $fsql ='
+    SELECT count(*) as num_children
+    FROM {feature_relationship} FR
+      INNER JOIN {feature} SF on SF.feature_id = FR.subject_id
+      INNER JOIN {cvterm} CVT on CVT.cvterm_id = SF.type_id
+      INNER JOIN {featureloc} FL on FL.feature_id = FR.subject_id
+      INNER JOIN {feature} PF on PF.feature_id = FL.srcfeature_id
+    WHERE FR.object_id = :feature_id and PF.feature_id = :srcfeature_id
+  ';
 
   // if we need to get the sequence from the parent then do so now.
   if ($derive_from_parent) {
+    
+    $residues = '';
 
     // execute the query to get the sequence from the parent
-    $sql = "EXECUTE sequence_by_parent (:upstream, :downstream, :feature_id)";
-    $parents = chado_query($sql, array(':uptream' => $upstream, ':downstream' => $downstream, ':feature_id' => $feature_id));
+    $parents = chado_query($sql, array(':upstream' => $upstream, ':downstream' => $downstream, ':feature_id' => $feature_id));
 
     while ($parent = $parents->fetchObject()) {
       $seq = '';  // initialize the sequence for each parent
@@ -301,11 +279,8 @@ function tripal_format_sequence($feature, $options) {
       if ($aggregate) {
 
         // now get the sub features that are located on the parent.
-        $sql = "EXECUTE sub_features (:feature_id, :srcfeature_id)";
-        $children = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
-        $sql = "EXECUTE count_sub_features (:feature_id, :srcfeature_id)";
-        $sub_features = chado_query($sql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
-        $num_children = $sub_features->fetchObject();
+        $children = chado_query($sfsql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
+        $num_children = chado_query($fsql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id))->fetchObject();
 
         // iterate through the sub features and concat their sequences. They
         // should already be in order.
@@ -324,8 +299,6 @@ function tripal_format_sequence($feature, $options) {
             $types[] = $child->type_name;
           }
 
-          $sql = "EXECUTE sequence_by_parent (:upstream, %d, :feature_id)";
-
           // if the first sub feature we need to include the upstream bases. first check if
           // the feature is in the foward direction or the reverse.
           if ($i == 0 and $parent->strand >= 0) {  // forward direction
@@ -358,7 +331,6 @@ function tripal_format_sequence($feature, $options) {
 
           // for internal sub features we don't want upstream or downstream bases
           else {
-            $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
             $q = chado_query($sql, array(':upstream' => 0, ':downstream' => 0, ':feature_id' => $child->feature_id));
           }
 
@@ -458,7 +430,7 @@ function tripal_format_sequence($feature, $options) {
  *
  * @ingroup tripal_feature_api
  */
-function tripal_get_fasta_sequence($feature, $desc) {
+function tripal_format_fasta_sequence($feature, $desc) {
 
   $fasta  = ">" . variable_get('chado_feature_accession_prefix', 'FID') . "$feature->feature_id|$feature->name";
   $fasta .= " $desc\n";

+ 2 - 0
tripal_feature/theme/css/tripal_feature.css

@@ -13,6 +13,8 @@ pre.tripal_feature-sequence {
   height: 300px;
   overflow: scroll; 
   border: 1px solid #DDDDDD;
+  max-width: 500px;
+  white-space: normal;
 }
 
 div#tripal_feature-featureloc_sequence-legend {

+ 1 - 1
tripal_feature/theme/templates/tripal_feature_properties.tpl.php

@@ -6,7 +6,7 @@ $feature = chado_expand_var($feature, 'table', 'featureprop', $options);
 $properties = $feature->featureprop;
 
 if(count($properties) > 0){ 
-    
+  
   // the $headers array is an array of fields to use as the colum headers.
   // additional documentation can be found here
   // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7

+ 76 - 31
tripal_feature/theme/templates/tripal_feature_sequence.tpl.php

@@ -1,22 +1,11 @@
 <?php
 /*
- * There are two ways that sequences can be displayed.  They can come from the 
- * feature.residues column or they can come from an alignment with another feature.  
- * This template will show both or one or the other depending on the data available.
- * 
- * For retreiving the sequence from an alignment we would typically make a call to
- * chado_expand_var function.  For example, to retrieve all
- * of the featurelocs in order to get the sequences needed for this template, the
- * following function call would be made:
- *
- *   $feature = chado_expand_var($feature,'table','featureloc');
- *
- * Then all of the sequences would need to be retreived from the alignments and
- * formatted for display below.  However, to simplify this template, this has already
- * been done by the tripal_feature module and the sequences are made available in
- * the variable:
- *
- *   $feature->featureloc_sequences
+ * There are several ways that sequences can be displayed.  They can come from the 
+ * feature.residues column,  they can come from an alignment with another feature,
+ * they can come from a protein sequence that has relationship with this sequence,
+ * or they can come from sub children (e.g. CDS coding sequences).
+ *   
+ * This template will show all types depending on the data available.
  *
  */
 
@@ -69,31 +58,58 @@ if ($residues or count($featureloc_sequences) > 0) {
   // variable that we use to get the proteins.
   $all_relationships = $feature->all_relationships;
   $object_rels = $all_relationships['object'];
+  $has_coding_seq = 0;
   foreach ($object_rels as $rel_type => $rels){
     foreach ($rels as $subject_type => $subjects){
       foreach ($subjects as $subject){
+        
+        // add in protein sequence if it has residues
         if ($rel_type == 'derives from' and $subject_type == 'polypeptide') {
           $protein = $subject->record->subject_id;
           $protein = chado_expand_var($protein, 'field', 'feature.residues');
           
-          $list_items[] = '<a href="#residues">Protein sequence of ' . $protein->name . '</a>';
-          $sequences_html .= '<a name="protein-' . $protein->feature_id . '"></a>';
-          $sequences_html .= '<div id="protein-' . $protein->feature_id . '" class="tripal_feature-sequence-item">';
-          $sequences_html .= '<p><b>Protein sequence of ' . $protein->name . '</b></p>';
-          $sequences_html .= '<pre class="tripal_feature-sequence">';
-          $sequences_html .= '>' . tripal_get_fasta_defline($protein) . "\n";
-          $sequences_html .= preg_replace("/(.{50})/","\\1<br>", $protein->residues);
-          $sequences_html .= '</pre>';
-          $sequences_html .= '<a href="#sequences-top">back to top</a>';
-          $sequences_html .= '</div>';
+          if ($protein->residues) {
+            $list_items[] = '<a href="#residues">Protein sequence of ' . $protein->name . '</a>';
+            $sequences_html .= '<a name="protein-' . $protein->feature_id . '"></a>';
+            $sequences_html .= '<div id="protein-' . $protein->feature_id . '" class="tripal_feature-sequence-item">';
+            $sequences_html .= '<p><b>Protein sequence of ' . $protein->name . '</b></p>';
+            $sequences_html .= '<pre class="tripal_feature-sequence">';
+            $sequences_html .= '>' . tripal_get_fasta_defline($protein) . "\n";
+            $sequences_html .= preg_replace("/(.{50})/","\\1<br>", $protein->residues);
+            $sequences_html .= '</pre>';
+            $sequences_html .= '<a href="#sequences-top">back to top</a>';
+            $sequences_html .= '</div>';
+          }
         }
-        // add any other sequences by by relationship in a similar way
+        
+        // we want to know if there are any coding sequences associated with this feature
+        // if so we will use some code a bit later on to get those sequences
+        if ($rel_type == 'part of' and $subject_type == 'CDS') {
+          $has_coding_seq = 1;
+        }
+        
+        // add any other sequences that are related through a relationship
+        // and that have values in the 'residues' column
       }
     }
   }
   
-  // ADD IN ALIGNMENT SEQUENCES FOR THIS FEATURE
-  // show the alignment sequences first as they are colored with child features
+  
+  /* ADD IN ALIGNMENT SEQUENCES FOR THIS FEATURE
+   * For retreiving the sequence from an alignment we would typically make a call to
+   * chado_expand_var function.  For example, to retrieve all
+   * of the featurelocs in order to get the sequences needed for this template, the
+   * following function call would be made:
+   *
+   *   $feature = chado_expand_var($feature,'table','featureloc');
+   *
+   * Then all of the sequences would need to be retreived from the alignments and
+   * formatted for display below.  However, to simplify this template, this has already
+   * been done by the tripal_feature module and the sequences are made available in
+   * the variable: 
+   *
+   *   $feature->featureloc_sequences
+   */
   if(count($featureloc_sequences) > 0){
     foreach($featureloc_sequences as $src => $attrs){
       // the $attrs array has the following keys
@@ -102,7 +118,7 @@ if ($residues or count($featureloc_sequences) > 0) {
       //   * location:  the alignment location
       //   * defline: the definition line
       //   * formatted_seq: the formatted sequences
-      $list_items[] = '<a href="#' . $attrs['src'] . '">Alignment at  ' . $attrs['location'];
+      $list_items[] = '<a href="#' . $attrs['src'] . '">Alignment at  ' . $attrs['location'] . "</a>";
       $sequences_html .= '<a name="' . $attrs['src'] . '"></a>';
       $sequences_html .= '<div id="' . $attrs['src'] . '" class="tripal_feature-sequence-item">';
       $sequences_html .= '<p><b>Alignment at  ' . $attrs['location'] .'</b></p>';
@@ -112,6 +128,35 @@ if ($residues or count($featureloc_sequences) > 0) {
     }
   }
   
+  // CODING SEQUENCES
+  // add in any CDS sequences. 
+  if ($has_coding_seq) {
+    // use the tripal_get_sequence() API function to retreive the CDS sequences
+    $cds_sequence = tripal_get_sequence(
+      array(
+        'feature_id' => $feature->feature_id,
+        'name' => $feature->name, 
+      ),
+      array(
+        'width' => 50,  // FASTA sequence should have 50 chars per line
+        'derive_from_parent' => 1, // CDS are in parent-child relationships so we want to use the sequence from the parent
+        'aggregate' => 1, // we want to combine all CDS for this feature into a single sequence
+        'output_format' => 'fasta_txt', // we just want plain text, we'll format it here.
+        'sub_feature_types' => array('CDS'), // we're looking for CDS features
+        ''
+      )
+    );
+    $list_items[] = '<a href="#coding_sequence">Coding sequence </a>';
+    $sequences_html .= '<a name="coding_sequence"></a>';
+    $sequences_html .= '<div id="coding_sequence" class="tripal_feature-sequence-item">';
+    $sequences_html .= '<p><b>Coding sequence</b></p>';
+    $sequences_html .= '<pre class="tripal_feature-sequence">';
+    $sequences_html .= $cds_sequence;
+    $sequences_html .= '</pre>';
+    $sequences_html .= '<a href="#sequences-top">back to top</a>';
+    $sequences_html .= '</div>';
+  }
+  
   // first add a list at the top of the page that can be formatted as the
   // user desires.  We use the theme_item_list function of Drupal to create 
   // the list rather than hard-code the HTML here.  Instructions for how

+ 575 - 0
tripal_feature/theme/tripal_feature.theme.inc

@@ -35,6 +35,428 @@ function tripal_feature_preprocess_tripal_feature_sequence(&$variables) {
     $feature->all_relationships = tripal_feature_get_feature_relationships($feature);
   }
 }
+
+/**
+ * Get the sequence this feature is located on
+ *
+ * @param $feature_id
+ * @param $featurelocs
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
+
+  // if we don't have any featurelocs then no point in continuing
+  if (!$featurelocs) {
+    return array();
+  }
+
+  // get the list of relationships (including any aggregators) and iterate
+  // through each one to find information needed to color-code the reference sequence
+  $relationships = tripal_feature_get_aggregate_relationships($feature_id);
+  if (!$relationships) {
+    return array();
+  }
+
+
+  // iterate through each of the realtionships features and get their
+  // locations
+  foreach ($relationships as $rindex => $rel) {
+    // get the featurelocs for each of the relationship features
+    $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
+    foreach ($rel_featurelocs as $rfindex => $rel_featureloc) {
+      // keep track of this unique source feature
+      $src = $rel_featureloc->src_feature_id . "-" . $rel_featureloc->src_cvterm_id;
+
+      // copy over the results to the relationship object.  Since there can
+      // be more than one feature location for each relationship feature we
+      // use the '$src' variable to keep track of these.
+      $rel->featurelocs = new stdClass();
+      $rel->featurelocs->$src = new stdClass();
+      $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
+      $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
+      $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
+      $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
+      $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
+      $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
+
+      // keep track of the individual parts for each relationship
+      $start = $rel->featurelocs->$src->fmin;
+      $end   = $rel->featurelocs->$src->fmax;
+      $type  = $rel->subject_type;
+      $rel_locs[$src]['parts'][$start][$type]['start'] = $start;
+      $rel_locs[$src]['parts'][$start][$type]['end']   = $end;
+      $rel_locs[$src]['parts'][$start][$type]['type']  = $type;
+    }
+  }
+
+  // the featurelocs array provided to the function contains the locations
+  // where this feature is found.   We want to get the sequence for each
+  // location and then annotate it with the parts found from the relationships
+  // locations determiend above.
+  $floc_sequences = array();
+  foreach ($featurelocs as $featureloc) {
+
+    // build the src name so we can keep track of the different parts for each feature
+    $src = $featureloc->srcfeature_id->feature_id . "-" . $featureloc->srcfeature_id->type_id->cvterm_id;
+
+    // orient the parts to the beginning of the feature sequence
+    if (!empty($rel_locs[$src]['parts'])) {
+      $parts = $rel_locs[$src]['parts'];
+      $rparts = array();  // we will fill this up if we're on the reverse strand
+
+      foreach ($parts as $start => $types) {
+        foreach ($types as $type_name => $type) {
+          if ($featureloc->strand >= 0) {
+            // this is on the forward strand.  We need to convert the start on the src feature to the
+            // start on this feature's sequence
+            $parts[$start][$type_name]['start'] = $parts[$start][$type_name]['start'] - $featureloc->fmin;
+            $parts[$start][$type_name]['end']   = $parts[$start][$type_name]['end'] - $featureloc->fmin;
+            $parts[$start][$type_name]['type']  = $type_name;
+          }
+          else {
+            // this is on the reverse strand.  We need to swap the start and stop and calculate from the
+            // begining of the reverse sequence
+            $size = ($featureloc->fmax - $featureloc->fmin);
+            $start_orig = $parts[$start][$type_name]['start'];
+            $end_orig = $parts[$start][$type_name]['end'];
+            $new_start = $size - ($end_orig - $featureloc->fmin);
+            $new_end = $size - ($start_orig - $featureloc->fmin);
+
+            $rparts[$new_start][$type_name]['start'] = $new_start;
+            $rparts[$new_start][$type_name]['end']   = $new_end;
+            $rparts[$new_start][$type_name]['type']  = $type_name;
+          }
+        }
+      }
+
+      // now sort the parts
+      // if we're on the reverse strand we need to resort
+      if ($featureloc->strand >= 0) {
+        usort($parts, 'tripal_feature_sort_rel_parts_by_start');
+      }
+      else {
+        usort($rparts, 'tripal_feature_sort_rel_parts_by_start');
+        $parts = $rparts;
+      }
+
+      $floc_sequences[$src]['src'] = $src;
+      $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
+      $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
+      $start = $featureloc->fmin + 1;
+      $size = $featureloc->fmax - $featureloc->fmin;
+      
+      // TODO: fix the hard coded $start and $size
+      // the $start and $size variables are hard-coded in the SQL statement
+      // because the db_query function places quotes around all placeholders
+      // (e.g. :start & :size) and screws up the substring function
+      $sql = "
+        SELECT substring(residues from $start for $size) as residues
+        FROM {feature}
+        WHERE feature_id = :feature_id
+      ";
+      $sequence = chado_query($sql, $args)->fetchObject();
+      $residues = $sequence->residues;
+      if ($featureloc->strand < 0) {
+        $residues = tripal_feature_reverse_complement($residues);
+      }
+      $strand = '.';
+      if ($featureloc->strand == 1) {
+        $strand = '+';
+      }
+      elseif ($featureloc->strand == -1) {
+        $strand = '-';
+      }
+      $floc_sequences[$src]['location'] = tripal_get_location_string($featureloc);
+      $floc_sequences[$src]['defline'] = tripal_get_fasta_defline($featureloc->feature_id, $featureloc);
+      $floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence($residues, $parts, $floc_sequences[$src]['defline']);
+    }
+  }
+  return $floc_sequences;
+}
+/**
+ * Used to sort the list of relationship parts by start position
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_sort_rel_parts_by_start($a, $b) {
+  foreach ($a as $type_name => $details) {
+    $astart = $a[$type_name]['start'];
+    break;
+  }
+  foreach ($b as $type_name => $details) {
+    $bstart = $b[$type_name]['start'];
+    break;
+  }
+  return strnatcmp($astart, $bstart);
+}
+/**
+ * Load the locations for a given feature
+ *
+ * @param $feature_id
+ *   The feature to look up locations for
+ * @param $side
+ *   Whether the feature is the scrfeature, 'as_parent', or feature, 'as_child'
+ * @param $aggregate
+ *   Whether or not to get the locations for related features
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_load_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1) {
+
+  $sql = "
+    SELECT
+       F.name, F.feature_id, F.uniquename,
+       FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename,
+       CVT.name as cvname, CVT.cvterm_id,
+       CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
+       FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase
+     FROM {featureloc} FL
+       INNER JOIN {feature} F   ON FL.feature_id = F.feature_id
+       INNER JOIN {feature} FS  ON FS.feature_id = FL.srcfeature_id
+       INNER JOIN {cvterm} CVT  ON F.type_id     = CVT.cvterm_id
+       INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
+   ";
+  if (strcmp($side, 'as_parent')==0) {
+    $sql .= "WHERE FL.srcfeature_id = :feature_id ";
+  }
+  if (strcmp($side, 'as_child')==0) {
+    $sql .= "WHERE FL.feature_id = :feature_id ";
+  }
+
+  $flresults = chado_query($sql, array(':feature_id' => $feature_id));
+
+  // copy the results into an array
+  $i=0;
+  $featurelocs = array();
+  while ($loc = $flresults->fetchObject()) {
+    // if a drupal node exists for this feature then add the nid to the
+    // results object
+    $loc->fnid = chado_get_nid_from_id('feature', $loc->feature_id);
+    $loc->snid = chado_get_nid_from_id('feature', $loc->src_feature_id);
+    // add the result to the array
+    $featurelocs[$i++] = $loc;
+  }
+
+  // Add the relationship feature locs if aggregate is turned on
+  if ($aggregate and strcmp($side, 'as_parent')==0) {
+    // get the relationships for this feature without substituting any children
+    // for the parent. We want all relationships
+    $relationships = tripal_feature_get_aggregate_relationships($feature_id, 0);
+    foreach ($relationships as $rindex => $rel) {
+      // get the featurelocs for each of the relationship features
+      $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
+      foreach ($rel_featurelocs as $findex => $rfloc) {
+        $featurelocs[$i++] = $rfloc;
+      }
+    }
+  }
+
+  usort($featurelocs, 'tripal_feature_sort_locations');
+  return $featurelocs;
+}
+
+/**
+ * Used to sort the feature locs by start position
+ *
+ * @param $a
+ *   One featureloc record (as an object)
+ * @param $b
+ *   The other featureloc record (as an object)
+ *
+ * @return
+ *   Which feature location comes first
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_sort_locations($a, $b) {
+  return strnatcmp($a->fmin, $b->fmin);
+}
+
+
+/**
+ * Get features related to the current feature to a given depth. Recursive function.
+ *
+ * @param $feature_id
+ * @param $substitute
+ * @param $levels
+ * @param $base_type_id
+ * @param $depth
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_get_aggregate_relationships($feature_id, $substitute=1,
+    $levels=0, $base_type_id=NULL, $depth=0) {
+
+  // we only want to recurse to as many levels deep as indicated by the
+  // $levels variable, but only if this variable is > 0. If 0 then we
+  // recurse until we reach the end of the relationships tree.
+  if ($levels > 0 and $levels == $depth) {
+    return NULL;
+  }
+
+  // first get the relationships for this feature
+  return tripal_feature_load_relationships($feature_id, 'as_object');
+
+}
+/**
+ * Get the relationships for a feature.
+ *
+ * @param $feature_id
+ *   The feature to get relationships for
+ * @param $side
+ *   The side of the relationship this feature is (ie: 'as_subject' or 'as_object')
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_load_relationships($feature_id, $side = 'as_subject') {
+  // get the relationships for this feature.  The query below is used for both
+  // querying the object and subject relationships
+  $sql = "
+    SELECT
+      FS.name as subject_name, FS.uniquename as subject_uniquename,
+      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
+      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
+      CVT.name as rel_type,
+      FO.name as object_name, FO.uniquename as object_uniquename,
+      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
+    FROM {feature_relationship} FR
+     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
+     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
+     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
+     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
+     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
+  ";
+  if (strcmp($side, 'as_object')==0) {
+    $sql .= " WHERE FR.object_id = :feature_id";
+  }
+  if (strcmp($side, 'as_subject')==0) {
+    $sql .= " WHERE FR.subject_id = :feature_id";
+  }
+  $sql .= " ORDER BY FR.rank";
+
+  // get the relationships
+  $results = chado_query($sql, array(':feature_id' => $feature_id));
+
+
+  // iterate through the relationships, put these in an array and add
+  // in the Drupal node id if one exists
+  $i=0;
+  $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
+  $relationships = array();
+  while ($rel = $results->fetchObject()) {
+    $node = db_query($nodesql, array(':feature_id' => $rel->subject_id))->fetchObject();
+    if ($node) {
+      $rel->subject_nid = $node->nid;
+    }
+    $node = db_query($nodesql, array(':feature_id' => $rel->object_id))->fetchObject();
+    if ($node) {
+      $rel->object_nid = $node->nid;
+    }
+    $relationships[$i++] = $rel;
+  }
+  return $relationships;
+}
+
+/**
+ * Returns the marked up fasta sequence for the described feature
+ *
+ * @param $sequence
+ * @param $parts
+ * @param $defline
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_color_sequence($sequence, $parts, $defline) {
+
+
+  $types = array();
+  // first get the list of types so we can create a color legend
+  foreach ($parts as $index => $t) {
+    foreach ($t as $type_name => $details) {
+      $types[$type_name] = 1;
+    }
+  }
+
+  $newseq = "<div id=\"tripal_feature-featureloc_sequence-legend\">Legend: ";
+  foreach ($types as $type_name => $present) {
+    $newseq .= "<span id=\"tripal_feature-legend-$type_name\" class=\"tripal_feature-legend-item tripal_feature-featureloc_sequence-$type_name\" script=\"\">$type_name</span>";
+  }
+  $newseq .= "</div>Hold the cursor over a type above to highlight its positions in the sequence below.";
+
+
+  // set the background color of the rows based on the type
+  $pos = 0;
+  $newseq .= "<pre class=\"tripal_feature-sequence\">";
+  $newseq .= ">$defline\n";
+
+  // iterate through the parts. They should be in order.
+  $starts   = array(); // an array holding all of the children starting locations
+  $ends     = array(); // an array holding all of the children's ending locations
+  $seqcount = 0;
+  foreach ($parts as $index => $types) {
+
+    // get the start for this part.  All types in this part start at the
+    // same position so we only need the first record
+    foreach ($types as $type => $child) {
+      $start = $child['start'];
+      $starts[$start][] = $type;
+    }
+
+    // next, sort the parts by their end. We want the span tag to
+    // to be added in the order the parts end.
+    usort($types, 'tripal_feature_sort_rel_parts_by_end');
+
+    // iterate through the types in order that then end and create a
+    // span for it.
+    foreach ($types as $type) {
+      $end = $type['end'];
+      $ends[$end][] = $type;
+    }
+  }
+
+  // iterate through each nucleotide in the sequence, add a new line very
+  // 50 characters and add the spans as we encounter them
+  for ($i = 0; $i < strlen($sequence); $i++) {
+
+    // if we are at and end of a span then close it
+    if (array_key_exists($i, $ends)) {
+      foreach ($ends[$i] as $index => $type) {
+        $newseq .= "</span>";
+      }
+    }
+
+    // if we are at and end of a span then close it
+    if (array_key_exists($i, $starts)) {
+      foreach ($starts[$i] as $index => $type) {
+        $class = "tripal_feature-featureloc_sequence-" . $type;
+        $newseq .= "<span class=\"$class\">";
+      }
+    }
+
+    $newseq .= $sequence{$i};
+    $seqcount++;
+    if ($seqcount % 50 == 0) {
+      $newseq .= "\n";
+    }
+  }
+
+  $newseq .= "</pre>";
+  return $newseq;
+}
+
+/**
+ * Used to sort the list of relationship parts by start position
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_sort_rel_parts_by_end($a, $b) {
+  $val = strnatcmp($b['end'], $a['end']);
+  if ($val == 0) {
+    return strcmp($a['type'], $b['type']);
+  }
+  return $val;
+}
 /**
  *
  *
@@ -171,6 +593,77 @@ function tripal_feature_preprocess_tripal_feature_alignments(&$variables) {
   }
   $feature->all_featurelocs = $alignments;
 }
+/**
+ * This function is for features that align through an intermediate such
+ * as 'EST_match' or 'match'.  This occurs in the case where two sequences
+ * align but where one does not align perfectly.  Some ESTs may be in a contig
+ * but not all of the EST.  Portions may overhang and not be included in the
+ * consensus if quality is bad.
+ * For example:
+ *    Feature 1: Contig --------------------
+ *    Feature 2: EST_match           -------
+ *    Feature 3: EST                 ---------
+ *
+ * The feature provided to the function will always be the feature 1.  The
+ * featureloc columns prefixed with 'right' (e.g. right_fmin) belong to the
+ * alignment of feature 3 with feature 2
+ *
+ * Features may align to more than one feature and are not matches. We do
+   * not want to include these, so we have to filter on the SO terms:
+ * match, or %_match
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_get_matched_alignments($feature) {
+
+  $sql = "
+     SELECT
+       FL1.featureloc_id    as left_featureloc_id,
+       FL1.srcfeature_id    as left_srcfeature_id,
+       FL1.feature_id       as left_feature_id,
+       FL1.fmin             as left_fmin,
+       FL1.is_fmin_partial  as left_is_fmin_partial,
+       FL1.fmax             as left_fmax,
+       FL1.is_fmax_partial  as left_is_fmax_partial,
+       FL1.strand           as left_strand,
+       FL1.phase            as left_phase,
+       FL1.locgroup         as left_locgroup,
+       FL1.rank             as left_rank,
+       FL2.featureloc_id    as right_featureloc_id,
+       FL2.srcfeature_id    as right_srcfeature_id,
+       FL2.feature_id       as right_feature_id,
+       FL2.fmin             as right_fmin,
+       FL2.is_fmin_partial  as right_is_fmin_partial,
+       FL2.fmax             as right_fmax,
+       FL2.is_fmax_partial  as right_is_fmax_partial,
+       FL2.strand           as right_strand,
+       FL2.phase            as right_phase,
+       FL2.locgroup         as right_locgroup,
+       FL2.rank             as right_rank
+     FROM {feature} F1
+       INNER JOIN {featureloc} FL1 on FL1.srcfeature_id = F1.feature_id
+       INNER JOIN {feature} F2 on FL1.feature_id = F2.feature_id
+       INNER JOIN {featureloc} FL2 on FL2.feature_id = F2.feature_id
+       INNER JOIN {cvterm} CVT2 on F2.type_id = CVT2.cvterm_id
+     WHERE
+       F1.feature_id = :feature_id  AND
+       (CVT2.name = 'match' or CVT2.name like '%_match')
+     ORDER BY FL1.fmin
+   ";
+
+  $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
+
+  // iterate through the results and add them to our featurelocs array
+  $featurelocs = array();
+  while ($fl = $results->fetchObject()) {
+    // ignore featurelocs where the left and right srcfeature is the same
+    if (strcmp($fl->left_srcfeature_id, $fl->right_srcfeature_id) == 0) {
+      continue;
+    }
+    $featurelocs[] = $fl ;
+  }
+  return $featurelocs;
+}
 /**
  *
  *
@@ -180,6 +673,88 @@ function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables, $
   $organism = $variables['node']->organism;
   $organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
 }
+/**
+ * Load the arguments for the organism feature counts browser
+ *
+ * @param $organism
+ *  The organism of interest
+ *
+ * @ingroup tripal_feature
+ */
+function tripal_feature_load_organism_feature_counts($organism) {
+
+  $args = array();
+  $order = array();
+  $names = array();
+
+  // build the where clause for the SQL statement if we have a custom term list
+  // we'll also keep track of the names the admin provided (if any) and the
+  // order that the terms should appear.
+  $is_custom = 0;
+  $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
+  $where = '';
+  if ($temp) {
+    $is_custom = 1;
+    $temp = explode("\n", $temp);
+    $i = 0;
+    foreach ($temp as $value) {
+      // separate the key value pairs
+      $temp2 = explode("=", $value);
+      $feature_type = rtrim($temp2[0]);
+      $order[] = $feature_type;  // save the order of the these terms
+      $where .= " OFC.feature_type = :name$i OR ";
+      $args[":name$i"] = rtrim($temp2[0]);
+
+      // if the admin specified a new name then store that otherwise use the
+      // the default sequence ontology term name
+      if(count($temp2) == 2) {
+        $names[] = rtrim($temp2[1]);
+      }
+      else {
+        $names[] = $feature_type;
+      }
+      $i++;
+    }
+    if ($where) {
+      $where = drupal_substr($where, 0, -4);  # remove OR from the end
+      $where = "($where) AND";
+    }
+  }
+
+  // get the feature counts.  This is dependent on a materialized view
+  // installed with the organism module
+  $sql = "
+  SELECT OFC.num_features,OFC.feature_type,CVT.definition
+  FROM {organism_feature_count} OFC
+  INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
+  WHERE $where organism_id = :organism_id
+  ORDER BY num_features desc
+  ";
+  $args[':organism_id'] = $organism->organism_id;
+  $org_features = chado_query($sql, $args);
+
+  // iterate through the types
+  $types = array();
+  while ($type = $org_features->fetchObject()) {
+  $types[$type->feature_type] = $type;
+  // if we don't have an order this means we didn't go through the loop
+  // above to set the names, so do that now
+  if (!$is_custom) {
+  $names[] = $type->feature_type;
+  $order[] = $type->feature_type;
+  }
+  }
+
+  // now reorder the types
+  $ordered_types = array();
+  foreach ($order as $type) {
+  $ordered_types[] = $types[$type];
+  }
+  return array(
+  'types' => $ordered_types,
+      'names' => $names
+  );
+}
 
 /**
  * Using the chado_expand_var function to retrieve a set

+ 0 - 576
tripal_feature/tripal_feature.module

@@ -336,583 +336,7 @@ function tripal_feature_theme($existing, $type, $theme, $path) {
   return $items;
 }
 
-/**
- * Load the locations for a given feature
- *
- * @param $feature_id
- *   The feature to look up locations for
- * @param $side
- *   Whether the feature is the scrfeature, 'as_parent', or feature, 'as_child'
- * @param $aggregate
- *   Whether or not to get the locations for related features
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_load_featurelocs($feature_id, $side = 'as_parent', $aggregate = 1) {
-
-  $sql = "
-    SELECT
-       F.name, F.feature_id, F.uniquename,
-       FS.name as src_name, FS.feature_id as src_feature_id, FS.uniquename as src_uniquename,
-       CVT.name as cvname, CVT.cvterm_id,
-       CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
-       FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, FL.phase
-     FROM {featureloc} FL
-       INNER JOIN {feature} F   ON FL.feature_id = F.feature_id
-       INNER JOIN {feature} FS  ON FS.feature_id = FL.srcfeature_id
-       INNER JOIN {cvterm} CVT  ON F.type_id     = CVT.cvterm_id
-       INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-   ";
-  if (strcmp($side, 'as_parent')==0) {
-    $sql .= "WHERE FL.srcfeature_id = :feature_id ";
-  }
-  if (strcmp($side, 'as_child')==0) {
-    $sql .= "WHERE FL.feature_id = :feature_id ";
-  }
-
-  $flresults = chado_query($sql, array(':feature_id' => $feature_id));
-
-  // copy the results into an array
-  $i=0;
-  $featurelocs = array();
-  while ($loc = $flresults->fetchObject()) {
-    // if a drupal node exists for this feature then add the nid to the
-    // results object
-    $loc->fnid = chado_get_nid_from_id('feature', $loc->feature_id);
-    $loc->snid = chado_get_nid_from_id('feature', $loc->src_feature_id);
-    // add the result to the array
-    $featurelocs[$i++] = $loc;
-  }
-
-  // Add the relationship feature locs if aggregate is turned on
-  if ($aggregate and strcmp($side, 'as_parent')==0) {
-    // get the relationships for this feature without substituting any children
-    // for the parent. We want all relationships
-    $relationships = tripal_feature_get_aggregate_relationships($feature_id, 0);
-    foreach ($relationships as $rindex => $rel) {
-      // get the featurelocs for each of the relationship features
-      $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
-      foreach ($rel_featurelocs as $findex => $rfloc) {
-        $featurelocs[$i++] = $rfloc;
-      }
-    }
-  }
-
-  usort($featurelocs, 'tripal_feature_sort_locations');
-  return $featurelocs;
-}
-
-/**
- * Used to sort the feature locs by start position
- *
- * @param $a
- *   One featureloc record (as an object)
- * @param $b
- *   The other featureloc record (as an object)
- *
- * @return
- *   Which feature location comes first
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_sort_locations($a, $b) {
-  return strnatcmp($a->fmin, $b->fmin);
-}
-
-/**
- * Get the relationships for a feature.
- *
- * @param $feature_id
- *   The feature to get relationships for
- * @param $side
- *   The side of the relationship this feature is (ie: 'as_subject' or 'as_object')
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_load_relationships($feature_id, $side = 'as_subject') {
-  // get the relationships for this feature.  The query below is used for both
-  // querying the object and subject relationships
-  $sql = "
-    SELECT
-      FS.name as subject_name, FS.uniquename as subject_uniquename,
-      CVTS.name as subject_type, CVTS.cvterm_id as subject_type_id,
-      FR.subject_id, FR.type_id as relationship_type_id, FR.object_id, FR.rank,
-      CVT.name as rel_type,
-      FO.name as object_name, FO.uniquename as object_uniquename,
-      CVTO.name as object_type, CVTO.cvterm_id as object_type_id
-    FROM {feature_relationship} FR
-     INNER JOIN {cvterm} CVT  ON FR.type_id    = CVT.cvterm_id
-     INNER JOIN {feature} FS  ON FS.feature_id = FR.subject_id
-     INNER JOIN {feature} FO  ON FO.feature_id = FR.object_id
-     INNER JOIN {cvterm} CVTO ON FO.type_id    = CVTO.cvterm_id
-     INNER JOIN {cvterm} CVTS ON FS.type_id    = CVTS.cvterm_id
-  ";
-  if (strcmp($side, 'as_object')==0) {
-    $sql .= " WHERE FR.object_id = :feature_id";
-  }
-  if (strcmp($side, 'as_subject')==0) {
-    $sql .= " WHERE FR.subject_id = :feature_id";
-  }
-  $sql .= " ORDER BY FR.rank";
-
-  // get the relationships
-  $results = chado_query($sql, array(':feature_id' => $feature_id));
-
-
-  // iterate through the relationships, put these in an array and add
-  // in the Drupal node id if one exists
-  $i=0;
-  $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = :feature_id";
-  $relationships = array();
-  while ($rel = $results->fetchObject()) {
-    $node = db_query($nodesql, array(':feature_id' => $rel->subject_id))->fetchObject();
-    if ($node) {
-      $rel->subject_nid = $node->nid;
-    }
-    $node = db_query($nodesql, array(':feature_id' => $rel->object_id))->fetchObject();
-    if ($node) {
-      $rel->object_nid = $node->nid;
-    }
-    $relationships[$i++] = $rel;
-  }
-  return $relationships;
-}
-
-/**
- * Get features related to the current feature to a given depth. Recursive function.
- *
- * @param $feature_id
- * @param $substitute
- * @param $levels
- * @param $base_type_id
- * @param $depth
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_get_aggregate_relationships($feature_id, $substitute=1,
-  $levels=0, $base_type_id=NULL, $depth=0) {
-
-  // we only want to recurse to as many levels deep as indicated by the
-  // $levels variable, but only if this variable is > 0. If 0 then we
-  // recurse until we reach the end of the relationships tree.
-  if ($levels > 0 and $levels == $depth) {
-    return NULL;
-  }
-
-  // first get the relationships for this feature
-  return tripal_feature_load_relationships($feature_id, 'as_object');
-
-}
-
-/**
- * Get the sequence this feature is located on
- *
- * @param $feature_id
- * @param $featurelocs
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_load_featureloc_sequences($feature_id, $featurelocs) {
-
-  // if we don't have any featurelocs then no point in continuing
-  if (!$featurelocs) {
-    return array();
-  }
-
-  // get the list of relationships (including any aggregators) and iterate
-  // through each one to find information needed to color-code the reference sequence
-  $relationships = tripal_feature_get_aggregate_relationships($feature_id);
-  if (!$relationships) {
-    return array();
-  }
-
-
-  // iterate through each of the realtionships features and get their
-  // locations
-  foreach ($relationships as $rindex => $rel) {
-    // get the featurelocs for each of the relationship features
-    $rel_featurelocs = tripal_feature_load_featurelocs($rel->subject_id, 'as_child', 0);
-    foreach ($rel_featurelocs as $rfindex => $rel_featureloc) {
-      // keep track of this unique source feature
-      $src = $rel_featureloc->src_feature_id . "-" . $rel_featureloc->src_cvterm_id;
-
-      // copy over the results to the relationship object.  Since there can
-      // be more than one feature location for each relationship feature we
-      // use the '$src' variable to keep track of these.
-      $rel->featurelocs = new stdClass();
-      $rel->featurelocs->$src = new stdClass();
-      $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
-      $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
-      $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
-      $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
-      $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
-      $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
-
-      // keep track of the individual parts for each relationship
-      $start = $rel->featurelocs->$src->fmin;
-      $end   = $rel->featurelocs->$src->fmax;
-      $type  = $rel->subject_type;
-      $rel_locs[$src]['parts'][$start][$type]['start'] = $start;
-      $rel_locs[$src]['parts'][$start][$type]['end']   = $end;
-      $rel_locs[$src]['parts'][$start][$type]['type']  = $type;
-    }
-  }
-
-  // the featurelocs array provided to the function contains the locations
-  // where this feature is found.   We want to get the sequence for each
-  // location and then annotate it with the parts found from the relationships
-  // locations determiend above.
-  $floc_sequences = array();
-  foreach ($featurelocs as $featureloc) {
-
-    // build the src name so we can keep track of the different parts for each feature
-    $src = $featureloc->srcfeature_id->feature_id . "-" . $featureloc->srcfeature_id->type_id->cvterm_id;
-
-    // orient the parts to the beginning of the feature sequence
-    if (!empty($rel_locs[$src]['parts'])) {
-      $parts = $rel_locs[$src]['parts'];
-      $rparts = array();  // we will fill this up if we're on the reverse strand
-
-      foreach ($parts as $start => $types) {
-        foreach ($types as $type_name => $type) {
-          if ($featureloc->strand >= 0) {
-             // this is on the forward strand.  We need to convert the start on the src feature to the
-             // start on this feature's sequence
-             $parts[$start][$type_name]['start'] = $parts[$start][$type_name]['start'] - $featureloc->fmin;
-             $parts[$start][$type_name]['end']   = $parts[$start][$type_name]['end'] - $featureloc->fmin;
-             $parts[$start][$type_name]['type']  = $type_name;
-          }
-          else {
-             // this is on the reverse strand.  We need to swap the start and stop and calculate from the
-             // begining of the reverse sequence
-             $size = ($featureloc->fmax - $featureloc->fmin);
-             $start_orig = $parts[$start][$type_name]['start'];
-             $end_orig = $parts[$start][$type_name]['end'];
-             $new_start = $size - ($end_orig - $featureloc->fmin);
-             $new_end = $size - ($start_orig - $featureloc->fmin);
-
-             $rparts[$new_start][$type_name]['start'] = $new_start;
-             $rparts[$new_start][$type_name]['end']   = $new_end;
-             $rparts[$new_start][$type_name]['type']  = $type_name;
-          }
-        }
-      }
-
-      // now sort the parts
-      // if we're on the reverse strand we need to resort
-      if ($featureloc->strand >= 0) {
-        usort($parts, 'tripal_feature_sort_rel_parts_by_start');
-      }
-      else {
-        usort($rparts, 'tripal_feature_sort_rel_parts_by_start');
-        $parts = $rparts;
-      }
-
-      $floc_sequences[$src]['src'] = $src;
-      $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
-      $args = array(':feature_id' => $featureloc->srcfeature_id->feature_id);
-      $start = $featureloc->fmin + 1;
-      $size = $featureloc->fmax - $featureloc->fmin;
-      // TODO: fix the hard coded $start and $size
-      // the $start and $size variables are hard-coded in the SQL statement
-      // because the db_query function places quotes around all placeholders
-      // (e.g. :start & :size) and screws up the substring function
-      $sql = "
-        SELECT substring(residues from $start for $size) as residues
-        FROM {feature}
-        WHERE feature_id = :feature_id
-      ";
-      $sequence = chado_query($sql, $args)->fetchObject();
-      $residues = $sequence->residues;
-      if ($featureloc->strand < 0) {
-         $residues = tripal_feature_reverse_complement($residues);
-      }
-      $strand = '.';
-      if ($featureloc->strand == 1) {
-        $strand = '+';
-      }
-      elseif ($featureloc->strand == -1) {
-        $strand = '-';
-      }
-      $floc_sequences[$src]['location'] = tripal_get_location_string($featureloc);
-      $floc_sequences[$src]['defline'] = tripal_get_fasta_defline($featureloc->feature_id, $featureloc);
-      $floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence($residues, $parts, $floc_sequences[$src]['defline']);
-    }
-  }
-  return $floc_sequences;
-}
-
-/**
- * This function is for features that align through an intermediate such
- * as 'EST_match' or 'match'.  This occurs in the case where two sequences
- * align but where one does not align perfectly.  Some ESTs may be in a contig
- * but not all of the EST.  Portions may overhang and not be included in the
- * consensus if quality is bad.
- * For example:
- *    Feature 1: Contig --------------------
- *    Feature 2: EST_match           -------
- *    Feature 3: EST                 ---------
- *
- * The feature provided to the function will always be the feature 1.  The
- * featureloc columns prefixed with 'right' (e.g. right_fmin) belong to the
- * alignment of feature 3 with feature 2
- *
- * Features may align to more than one feature and are not matches. We do
- * not want to include these, so we have to filter on the SO terms:
- * match, or %_match
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_get_matched_alignments($feature) {
-
-   $sql = "
-     SELECT
-       FL1.featureloc_id    as left_featureloc_id,
-       FL1.srcfeature_id    as left_srcfeature_id,
-       FL1.feature_id       as left_feature_id,
-       FL1.fmin             as left_fmin,
-       FL1.is_fmin_partial  as left_is_fmin_partial,
-       FL1.fmax             as left_fmax,
-       FL1.is_fmax_partial  as left_is_fmax_partial,
-       FL1.strand           as left_strand,
-       FL1.phase            as left_phase,
-       FL1.locgroup         as left_locgroup,
-       FL1.rank             as left_rank,
-       FL2.featureloc_id    as right_featureloc_id,
-       FL2.srcfeature_id    as right_srcfeature_id,
-       FL2.feature_id       as right_feature_id,
-       FL2.fmin             as right_fmin,
-       FL2.is_fmin_partial  as right_is_fmin_partial,
-       FL2.fmax             as right_fmax,
-       FL2.is_fmax_partial  as right_is_fmax_partial,
-       FL2.strand           as right_strand,
-       FL2.phase            as right_phase,
-       FL2.locgroup         as right_locgroup,
-       FL2.rank             as right_rank
-     FROM {feature} F1
-       INNER JOIN {featureloc} FL1 on FL1.srcfeature_id = F1.feature_id
-       INNER JOIN {feature} F2 on FL1.feature_id = F2.feature_id
-       INNER JOIN {featureloc} FL2 on FL2.feature_id = F2.feature_id
-       INNER JOIN {cvterm} CVT2 on F2.type_id = CVT2.cvterm_id
-     WHERE
-       F1.feature_id = :feature_id  AND
-       (CVT2.name = 'match' or CVT2.name like '%_match')
-     ORDER BY FL1.fmin
-   ";
-
-   $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
-
-   // iterate through the results and add them to our featurelocs array
-   $featurelocs = array();
-   while ($fl = $results->fetchObject()) {
-     // ignore featurelocs where the left and right srcfeature is the same
-     if (strcmp($fl->left_srcfeature_id, $fl->right_srcfeature_id) == 0) {
-       continue;
-     }
-     $featurelocs[] = $fl ;
-   }
-   return $featurelocs;
-}
-
-/**
- * Load the arguments for the organism feature counts browser
- *
- * @param $organism
- *  The organism of interest
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_load_organism_feature_counts($organism) {
-
-  $args = array();
-  $order = array();
-  $names = array();
-
-  // build the where clause for the SQL statement if we have a custom term list
-  // we'll also keep track of the names the admin provided (if any) and the
-  // order that the terms should appear.
-  $is_custom = 0;
-  $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
-  $where = '';
-  if ($temp) {
-    $is_custom = 1;
-    $temp = explode("\n", $temp);
-    $i = 0;
-    foreach ($temp as $value) {
-      // separate the key value pairs
-      $temp2 = explode("=", $value);
-      $feature_type = rtrim($temp2[0]);
-      $order[] = $feature_type;  // save the order of the these terms
-      $where .= " OFC.feature_type = :name$i OR ";
-      $args[":name$i"] = rtrim($temp2[0]);
-
-      // if the admin specified a new name then store that otherwise use the
-      // the default sequence ontology term name
-      if(count($temp2) == 2) {
-        $names[] = rtrim($temp2[1]);
-      }
-      else {
-        $names[] = $feature_type;
-      }
-      $i++;
-    }
-    if ($where) {
-      $where = drupal_substr($where, 0, -4);  # remove OR from the end
-      $where = "($where) AND";
-    }
-  }
-
-  // get the feature counts.  This is dependent on a materialized view
-  // installed with the organism module
-  $sql = "
-    SELECT OFC.num_features,OFC.feature_type,CVT.definition
-    FROM {organism_feature_count} OFC
-      INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
-    WHERE $where organism_id = :organism_id
-    ORDER BY num_features desc
-  ";
-  $args[':organism_id'] = $organism->organism_id;
-  $org_features = chado_query($sql, $args);
-
-  // iterate through the types
-  $types = array();
-  while ($type = $org_features->fetchObject()) {
-    $types[$type->feature_type] = $type;
-    // if we don't have an order this means we didn't go through the loop
-    // above to set the names, so do that now
-    if (!$is_custom) {
-      $names[] = $type->feature_type;
-      $order[] = $type->feature_type;
-    }
-  }
-
-  // now reorder the types
-  $ordered_types = array();
-  foreach ($order as $type) {
-    $ordered_types[] = $types[$type];
-  }
-  return array(
-    'types' => $ordered_types,
-    'names' => $names
-  );
-}
-
-/**
- * Used to sort the list of relationship parts by start position
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_sort_rel_parts_by_start($a, $b) {
-  foreach ($a as $type_name => $details) {
-     $astart = $a[$type_name]['start'];
-     break;
-  }
-  foreach ($b as $type_name => $details) {
-     $bstart = $b[$type_name]['start'];
-     break;
-  }
-  return strnatcmp($astart, $bstart);
-}
-
-/**
- * Used to sort the list of relationship parts by start position
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_sort_rel_parts_by_end($a, $b) {
-  $val = strnatcmp($b['end'], $a['end']);
-  if ($val == 0) {
-     return strcmp($a['type'], $b['type']);
-  }
-  return $val;
-}
-
-/**
- * Returns the marked up fasta sequence for the described feature
- *
- * @param $sequence
- * @param $parts
- * @param $defline
- *
- * @ingroup tripal_feature
- */
-function tripal_feature_color_sequence($sequence, $parts, $defline) {
-
-
-  $types = array();
-  // first get the list of types so we can create a color legend
-  foreach ($parts as $index => $t) {
-    foreach ($t as $type_name => $details) {
-       $types[$type_name] = 1;
-    }
-  }
-
-  $newseq = "<div id=\"tripal_feature-featureloc_sequence-legend\">Legend: ";
-  foreach ($types as $type_name => $present) {
-    $newseq .= "<span id=\"tripal_feature-legend-$type_name\" class=\"tripal_feature-legend-item tripal_feature-featureloc_sequence-$type_name\" script=\"\">$type_name</span>";
-  }
-  $newseq .= "</div>Hold the cursor over a type above to highlight its positions in the sequence below.";
-
-
-  // set the background color of the rows based on the type
-  $pos = 0;
-  $newseq .= "<pre class=\"tripal_feature-sequence\">";
-  $newseq .= ">$defline\n";
 
-  // iterate through the parts. They should be in order.
-  $starts   = array(); // an array holding all of the children starting locations
-  $ends     = array(); // an array holding all of the children's ending locations
-  $seqcount = 0;
-  foreach ($parts as $index => $types) {
-
-    // get the start for this part.  All types in this part start at the
-    // same position so we only need the first record
-    foreach ($types as $type => $child) {
-      $start = $child['start'];
-      $starts[$start][] = $type;
-    }
-
-    // next, sort the parts by their end. We want the span tag to
-    // to be added in the order the parts end.
-    usort($types, 'tripal_feature_sort_rel_parts_by_end');
-
-    // iterate through the types in order that then end and create a 
-    // span for it.
-    foreach ($types as $type) {
-      $end = $type['end'];
-      $ends[$end][] = $type;
-    }
-  }
-
-  // iterate through each nucleotide in the sequence, add a new line very
-  // 50 characters and add the spans as we encounter them
-  for ($i = 0; $i < strlen($sequence); $i++) {
-
-    // if we are at and end of a span then close it
-    if (array_key_exists($i, $ends)) {
-      foreach ($ends[$i] as $index => $type) {
-        $newseq .= "</span>";
-      }
-    }
-    
-    // if we are at and end of a span then close it
-    if (array_key_exists($i, $starts)) {
-      foreach ($starts[$i] as $index => $type) {
-        $class = "tripal_feature-featureloc_sequence-" . $type;
-        $newseq .= "<span class=\"$class\">";
-      }
-    }
-
-    $newseq .= $sequence{$i};
-    $seqcount++;
-    if ($seqcount % 50 == 0) {
-      $newseq .= "\n";
-    }
-  }
-
-  $newseq .= "</pre>";
-  return $newseq;
-}
 
 /**
  * The CV module will create the JSON array necessary for buillding a