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'] = [
  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'] = [
  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'] = [
  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'] = [
  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'] = [
  58. '#type' => 'radios',
  59. '#title' => t('Output format'),
  60. '#options' => [
  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. }