function tripal_feature_get_formatted_sequence

1.x tripal_feature.api.inc 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 = '')

Retrieves the sequence for a feature.

Parameters

$feature_id: The feature_id of the feature for which the sequence will be retrieved

$feature_name: The feature name. This will appear on the FASTA definition line

$num_bases_per_line: Indicate the number of bases to use per line. A new line will be added 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.

$aggregate: Set to '1' if the sequence should only contain sub features, excluding intra 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.

$upstream: An integer specifing the number of upstream bases to include in the output

$downstream: An integer specifying the number of downstream bases to include in the output.

$sub_features: Only include sub features (or child features) of the types provided in the array

$relationship: 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

$rel_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

Return value

The DNA/protein sequence formated as requested.

Related topics

2 calls to tripal_feature_get_formatted_sequence()
tripal_feature_seq_extract_get_features in tripal_feature/includes/seq_extract.inc
tripal_views_handler_field_sequence::render in tripal_views/views/handlers/tripal_views_handler_field_sequence.inc
Prior to display of results we want to format the sequence

File

tripal_feature/api/tripal_feature.api.inc, line 484
Provides an application programming interface (API) for working with features

Code

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 = '') {

  // 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;
  }

  if ($rel_part == "object" or $rel_part == "subject") {
    if ($rel_part == "subject") {
      $psql = '
        PREPARE feature_rel_get_object (int, text) AS
        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
          INNER JOIN cvterm CVTFR            ON CVTFR.cvterm_id = FR.type_id
          INNER JOIN feature FO              ON FO.feature_id   = FR.object_id
          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
      ';
      $status = tripal_core_chado_prepare('feature_rel_get_object', $psql, array('int', 'text'));
      if (!$status) {
        watchdog('tripal_feature', "init: not able to prepare SQL statement '%name'", 
        array('%name' => 'feature_by_subject'), 'WATCHDOG ERROR');
      }
      $sql = "EXECUTE feature_rel_get_object(%d,'%s')";
      $features = chado_query($sql, $feature_id, $relationship);
    }
    if ($rel_part == "object") {
      $psql = '
        PREPARE feature_rel_get_subject (int, text) AS
        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
          INNER JOIN cvterm CVTFR            ON CVTFR.cvterm_id = FR.type_id
          INNER JOIN feature FS              ON FS.feature_id   = FR.subject_id
          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
      ';
      $status = tripal_core_chado_prepare('feature_rel_get_subject', $psql, array('int', 'text'));
      if (!$status) {
        watchdog('tripal_feature', "init: not able to prepare SQL statement '%name'", 
        array('%name' => 'feature_by_object'), 'WATCHDOG ERROR');
      }
      $sql = "EXECUTE feature_rel_get_subject(%d,'%s')";
      $features = chado_query($sql, $feature_id, $relationship);
    }
    $sequences = '';
    while ($feature = db_fetch_object($features)) {

      // recurse and get the sequences for these in the relationship
      if ($rel_part == "subject") {
        $defline = "$feature_name, $relationship, $feature->uniquename $feature->feature_type ($feature->genus $feature->species)";
      }
      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, '', '');
    }
    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) {
      watchdog('tripal_feature', 
      "init: not able to prepare SQL statement '%name'", 
      array('%name' => 'sequence_by_parent'), 'WATCHDOG ERROR');
    }

    // 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) {
      watchdog('tripal_views_handler_field_sequence', 
      "init: not able to prepare SQL statement '%name'", 
      array('%name' => 'ssub_features'), 'WATCHDOG ERROR');
    }
    $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) {
      watchdog('tripal_views_handler_field_sequence', 
      "init: not able to prepare SQL statement '%name'", 
      array('%name' => 'count_sub_features'), 'WATCHDOG ERROR');
    }
  }

  // if we need to get the sequence from the parent then do so now.
  if ($derive_from_parent) {

    // execute the query to get the sequence from the parent
    $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
    $parents = chado_query($sql, $upstream, $downstream, $feature_id);

    while ($parent = db_fetch_object($parents)) {
      $seq = ''; // initialize the sequence for each parent

      // if we are to aggregate then we will ignore the feature returned
      // by the query above and rebuild it using the sub features
      if ($aggregate) {

        // now get the sub features that are located on the parent.
        $sql = "EXECUTE sub_features (%d, %d)";
        $children = chado_query($sql, $feature_id, $parent->srcfeature_id);
        $sql = "EXECUTE count_sub_features (%d, %d)";
        $num_children = db_fetch_object(chado_query($sql, $feature_id, $parent->srcfeature_id));

        // iterate through the sub features and concat their sequences. They
        // should already be in order.
        $types = array();
        $i = 0;
        while ($child = db_fetch_object($children)) {
          // if the callee has specified that only certain sub features should be
          // included then continue if this child is not one of those allowed
          // subfeatures
          if (count($sub_features) > 0 and !in_array($child->type_name, $sub_features)) {
            continue;
          }

          // keep up with the types
          if (!in_array($child->type_name, $types)) {
            $types[] = $child->type_name;
          }

          $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";

          // 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
            // -------------------------- ref
            //    ....---->  ---->        
            //     up    1       2         
            $q = chado_query($sql, $upstream, 0, $child->feature_id);
          }
          elseif ($i == 0 and $parent->strand < 0) { // reverse direction
            // -------------------------- ref
            //    ....<----  <----
            //    down  1       2
            $q = chado_query($sql, 0, $downstream, $child->feature_id);
          }

          // Next, if the last sub feature we need to include the downstream bases. first check if
          // the feature is in teh forward direction or the reverse
          if ($i == $num_children->num_children - 1 and $parent->strand >= 0) { // forward direction
            // -------------------------- ref
            //        ---->  ---->....
            //          1       2 down
            $q = chado_query($sql, 0, $downstream, $child->feature_id);
          }
          elseif ($i == $num_children->num_children - 1 and $parent->strand < 0) { // reverse direction
            // -------------------------- ref
            //        <----  <----....
            //          1       2  up
            $q = chado_query($sql, $upstream, 0, $child->feature_id);
          }

          // 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, 0, 0, $child->feature_id);
          }

          while ($subseq = db_fetch_object($q)) {
            // concatenate the sequences of all the sub features            
            if ($subseq->srcfeature_id == $parent->srcfeature_id) {
              $seq .= $subseq->residues;
            }
          }
          $i++;
        }
      }
      // if this isn't an aggregate then use the parent residues
      else {
        $seq = $parent->residues;
      }

      // get the reverse compliment if feature is on the reverse strand
      $dir = 'forward';
      if ($parent->strand < 0) {
        $seq = tripal_feature_reverse_complement($seq);
        $dir = 'reverse';
      }

      // now format for display
      if ($output_format == 'fasta_html') {
        $seq = wordwrap($seq, $num_bases_per_line, "<br>", TRUE);
      }
      elseif ($output_format == 'fasta_txt') {
        $seq = wordwrap($seq, $num_bases_per_line, "\r\n", TRUE);
      }
      $residues .= ">$feature_name. Sequence derived from feature of type, '$parent->srctypename', of $parent->genus $parent->species: $parent->srcname:" . ($parent->adjfmin + 1) . ".." . $parent->adjfmax . " ($dir). ";
      if (count($types) > 0) {
        $residues .= "Excludes all bases but those of type(s): " . implode(', ', $types) . ". ";
      }
      if ($parent->upstream > 0) {
        $residues .= "Includes " . $parent->upstream . " bases upstream.  ";
      }
      if ($parent->downstream > 0) {
        $residues .= "Includes " . $parent->downstream . " bases downstream.  ";
      }
      if (!$seq) {

        if ($output_format == 'fasta_html') {
          $residues .= "No sequence available.</br>";
        }
        else {
          $residues .= "No sequence available.\r\n";
        }
      }
      else {
        if ($output_format == 'fasta_html') {
          $residues .= "<br>";
        }
        $residues .= "\r\n" . $seq . "\r\n";
        if ($output_format == 'fasta_html') {
          $residues .= "<br>";
        }
      }
    }
  }
  // if we are not getting the sequence from the parent sequence then
  // use what comes through from the feature record
  else {
    $sql = "SELECT * FROM {feature} F WHERE feature_id = %d";
    $values = db_fetch_object(chado_query($sql, $feature_id));
    $residues = $values->residues;
    if ($output_format == 'fasta_html') {
      $residues = wordwrap($residues, $num_bases_per_line, "<br>", TRUE);
    }
    elseif ($output_format == 'fasta_txt') {
      $residues = wordwrap($residues, $num_bases_per_line, "\r\n", TRUE);
    }
    $residues = ">$feature_name\r\n$residues\r\n";
  }

  // format the residues for display
  if ($residues and $num_bases_per_line) {
    if ($output_format == 'fasta_html') {
      $residues = '<span style="font-family: monospace;">' . $residues . '</span>';
    }
  }
  return $residues;
}