tripal_views_handler_field_sequence.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. /**
  3. * @file
  4. * Contains tripal_views_handler_field_sequence
  5. */
  6. /**
  7. * Handles display of sequence data. If will aggregate sequences that need
  8. * to be aggregated (e.g. coding sequences) and provide
  9. *
  10. * @ingroup tripal_views
  11. */
  12. class tripal_views_handler_field_sequence extends views_handler_field {
  13. /**
  14. * {@inheritdoc}
  15. */
  16. function options_form(&$form, &$form_state) {
  17. parent::options_form($form, $form_state);
  18. $form['display'] = array(
  19. '#type' => 'fieldset',
  20. '#title' => 'Format Output',
  21. '#description' => t('Alter the way a sequence is displayed')
  22. );
  23. $default_num_bases_per_line = '50';
  24. if ($this->options['display']['num_bases_per_line']) {
  25. $default_num_bases_per_line = $this->options['display']['num_bases_per_line'];
  26. }
  27. $default_output_format = 'raw';
  28. if ($this->options['display']['output_format']) {
  29. $default_ouput_format = $this->options['display']['output_format'];
  30. }
  31. $form['display']['num_bases_per_line'] = array(
  32. '#type' => 'textfield',
  33. '#title' => t('Number of bases per line'),
  34. '#description' => t('Specify the number of bases per line. An HTML <br> tag ' .
  35. 'will be inserted after the number of bases indicated. If no value is ' .
  36. 'provided. The sequence will be one long string (default)'),
  37. '#default_value' => $default_num_bases_per_line,
  38. );
  39. $form['display']['derive_from_parent'] = array(
  40. '#type' => 'checkbox',
  41. '#title' => t('Derive sequence from parent'),
  42. '#description' => t('Rather than use the sequence from the \'residues\' of this feature, you may ' .
  43. 'derive the sequence from the parent features to which it is aligned. This is useful in the case that the feature ' .
  44. 'does not have sequence associated with it and we need to get it through it\'s alignment. ' .
  45. 'Note: this will slow queries with large numbers of results on the page.'),
  46. '#default_value' => $this->options['display']['derive_from_parent'],
  47. );
  48. $form['display']['aggregate'] = array(
  49. '#type' => 'checkbox',
  50. '#title' => t('Aggregate sub features'),
  51. '#description' => t('If the feature has sub features (e.g. CDS of an mRNA) then check this '.
  52. 'box to filter the sequence to only include the sub features. Gaps between sub features will be '.
  53. 'excluded from the sequence. This is useful for obtaining a complete CDS from an mRNA '.
  54. 'without intronic sequence'),
  55. '#default_value' => $this->options['display']['aggregate'],
  56. );
  57. $form['display']['output_format'] = array(
  58. '#type' => 'radios',
  59. '#title' => t('Output format'),
  60. '#options' => array(
  61. 'raw' => 'Raw sequence data (no formatting)',
  62. 'fasta_html' => 'FASTA in HTML format',
  63. 'fasta_txt' => 'FASTA in text format',
  64. ),
  65. '#description' => t('Choose an output format. Raw output cannot be used when the sequence is derived from the parent.'),
  66. '#default_value' => $default_ouput_format,
  67. );
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. function query() {
  73. parent::query();
  74. // if we are going to get the sequence from the parent then
  75. // we will need to do more queries in the render function
  76. // and we must have the feature_id to do those
  77. if ($this->options['display']['derive_from_parent']) {
  78. $this->ensure_my_table();
  79. $this->query->add_field($this->table, 'feature_id');
  80. $this->query->add_field($this->table, 'name');
  81. }
  82. }
  83. /**
  84. * {@inheritdoc}
  85. *
  86. * Prior to display of results we want to format the sequence
  87. */
  88. function render($values) {
  89. $residues = '';
  90. // get the number of bases to show per line
  91. $num_bases_per_line = $this->options['display']['num_bases_per_line'];
  92. $output_format = $this->options['display']['output_format'];
  93. // get the residues from the feature.residues column
  94. $field = $this->field_alias;
  95. // get the feature id
  96. $feature_id = $values->feature_feature_id;
  97. $feature_name = $values->feature_name;
  98. // the upstream and downstream values get set by the
  99. // tripal_views_handlers_filter_sequence.inc
  100. $upstream = $_SESSION['upstream'];
  101. $downstream = $_SESSION['downstream'];
  102. if (!$upstream) {
  103. $upstream = 0;
  104. }
  105. if (!$downstream) {
  106. $downstream = 0;
  107. }
  108. $derive_from_parent = $this->options['display']['derive_from_parent'];
  109. $aggregate = $this->options['display']['aggregate'];
  110. $residues = tripal_feature_get_formatted_sequence($feature_id, $feature_name,
  111. $num_bases_per_line, $derive_from_parent, $aggregate, $output_format,
  112. $upstream, $downstream);
  113. /*
  114. // if we need to get the sequence from the parent but there is no aggregation
  115. // then do so now.
  116. if ($this->options['display']['derive_from_parent']) {
  117. // execute our prepared statement
  118. if (tripal_core_is_sql_prepared('sequence_by_parent')) {
  119. $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
  120. $parents = chado_query($sql, $upstream, $downstream, $feature_id);
  121. }
  122. while ($parent = d-b_f-etch_object($parents)) {
  123. $seq = ''; // initialize the sequence for each parent
  124. // if we are to aggregate then we will ignore the feature returned
  125. // by the query above and rebuild it using the sub features
  126. if ($this->options['display']['aggregate']){
  127. // now get the sub features that are located on the parent.
  128. $sql = "EXECUTE sub_features (%d, %d)";
  129. $children = chado_query($sql, $feature_id, $parent->srcfeature_id);
  130. $sql = "EXECUTE count_sub_features (%d, %d)";
  131. $num_children = d-b_f-etch_object(chado_query($sql, $feature_id, $parent->srcfeature_id));
  132. // iterate through the sub features and concat their sequences. They
  133. // should already be in order.
  134. $types = array();
  135. $i = 0;
  136. while($child = d-b_f-etch_object($children)) {
  137. // keep up with the types
  138. if (!in_array($child->type_name,$types)) {
  139. $types[] = $child->type_name;
  140. }
  141. $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
  142. // if the first sub feature we need to include the upstream bases
  143. if ($i == 0 and $parent->strand >= 0) {
  144. // -------------------------- ref
  145. // ....----> ---->
  146. // up 1 2
  147. $q = chado_query($sql, $upstream, 0, $child->feature_id);
  148. }
  149. elseif ($i == 0 and $parent->strand < 0) {
  150. // -------------------------- ref
  151. // ....<---- <----
  152. // down 1 2
  153. $q = chado_query($sql, 0, $downstream, $child->feature_id);
  154. }
  155. // if the last sub feature we need to include the downstream bases
  156. elseif ($i == $num_children->num_children - 1 and $parent->strand >= 0) {
  157. // -------------------------- ref
  158. // ----> ---->....
  159. // 1 2 down
  160. $q = chado_query($sql, 0, $downstream, $child->feature_id);
  161. }
  162. elseif ($i == $num_children->num_children - 1 and $parent->strand < 0) {
  163. // -------------------------- ref
  164. // <---- <----....
  165. // 1 2 up
  166. $q = chado_query($sql, $upstream, 0, $child->feature_id);
  167. }
  168. // for internal sub features we don't want upstream or downstream bases
  169. else {
  170. $sql = "EXECUTE sequence_by_parent (%d, %d, %d)";
  171. $q = chado_query($sql, 0, 0, $child->feature_id);
  172. }
  173. while ($subseq = d-b_f-etch_object($q)){
  174. // concatenate the sequences of all the sub features
  175. if($subseq->srcfeature_id == $parent->srcfeature_id){
  176. $seq .= $subseq->residues;
  177. }
  178. }
  179. $i++;
  180. }
  181. }
  182. // if this isn't an aggregate then use the parent residues
  183. else {
  184. $seq = $parent->residues;
  185. }
  186. // get the reverse compliment if feature is on the reverse strand
  187. $dir = 'forward';
  188. if ($parent->strand < 0) {
  189. $seq = trpial_feature_reverse_complement($seq);
  190. $dir = 'reverse';
  191. }
  192. // now format for display
  193. if ($output_format == 'fasta_html') {
  194. $seq = wordwrap($seq, $num_bases_per_line, "<br>", TRUE);
  195. }
  196. elseif ($output_format == 'fasta_txt') {
  197. $seq = wordwrap($seq, $num_bases_per_line, "\n", TRUE);
  198. }
  199. $residues .= ">$feature_name ($parent->typename) $parent->srcname:" . ($parent->adjfmin + 1) . ".." . $parent->adjfmax ." ($dir). ";
  200. if (count($types) > 0) {
  201. $residues .= "Excludes all bases but those of type(s): " . implode(', ',$types) . ". " ;
  202. }
  203. if ($parent->upstream > 0) {
  204. $residues .= "Includes " . $parent->upstream . " bases upstream. ";
  205. }
  206. if ($parent->downstream > 0) {
  207. $residues .= "Includes " . $parent->downstream . " bases downstream. ";
  208. }
  209. if (!$seq) {
  210. $residues .= "No sequence available\n<br>";
  211. }
  212. else {
  213. if ($output_format == 'fasta_html') {
  214. $residues .= "<br>";
  215. }
  216. $residues .= "\n" . $seq . "\n";
  217. if ($output_format == 'fasta_html') {
  218. $residues .= "<br>";
  219. }
  220. }
  221. }
  222. }
  223. // if we are not getting the sequence from the parent sequence then
  224. // use what comes through from the feature record
  225. else {
  226. $residues = $values->$field;
  227. if ($output_format == 'fasta_html') {
  228. $residues = wordwrap($residues, $num_bases_per_line, "<br>", TRUE);
  229. }
  230. elseif ($output_format == 'fasta_txt') {
  231. $residues = wordwrap($residues, $num_bases_per_line, "\n", TRUE);
  232. }
  233. }
  234. // format the residues for display
  235. if($residues and $num_bases_per_line){
  236. if ($output_format == 'fasta_html') {
  237. $residues = '<span style="font-family: monospace;">' . $residues . '</span>';
  238. }
  239. } */
  240. return $residues;
  241. }
  242. }