tripal_chado.feature.api.inc 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. <?php
  2. /**
  3. * @file
  4. * Provides an application programming interface (API) for working with features
  5. */
  6. /**
  7. * @defgroup tripal_chado_api Feature API
  8. * @ingroup tripal_api
  9. * @{
  10. * Provides an application programming interface (API) for working with features
  11. * @}
  12. */
  13. /**
  14. * Performs a reverse compliment of a nucleotide sequence
  15. *
  16. * @param $sequence
  17. * The nucelotide sequence
  18. *
  19. * @return
  20. * an upper-case reverse complemented sequence
  21. *
  22. * @ingroup tripal_chado_api
  23. */
  24. function tripal_reverse_compliment_sequence($sequence) {
  25. $seq = strtoupper($sequence);
  26. $seq = strrev($seq);
  27. $seq = str_replace("A", "t", $seq);
  28. $seq = str_replace("T", "a", $seq);
  29. $seq = str_replace("G", "c", $seq);
  30. $seq = str_replace("C", "g", $seq);
  31. $seq = str_replace("Y", "r", $seq);
  32. $seq = str_replace("R", "y", $seq);
  33. $seq = str_replace("W", "w", $seq);
  34. $seq = str_replace("S", "s", $seq);
  35. $seq = str_replace("K", "m", $seq);
  36. $seq = str_replace("M", "k", $seq);
  37. $seq = str_replace("D", "h", $seq);
  38. $seq = str_replace("V", "b", $seq);
  39. $seq = str_replace("H", "d", $seq);
  40. $seq = str_replace("B", "v", $seq);
  41. return strtoupper($seq);
  42. }
  43. /**
  44. * Retrieves the sequences for a given feature. If a feature has multiple alignments
  45. * or multiple relationships then multiple sequences will be returned.
  46. *
  47. * @param $feature
  48. * An associative array describing the feature. Valid keys include:
  49. * - feature_id: The feature_id of the feature for which the sequence will be retrieved
  50. * - name: The feature name. This will appear on the FASTA definition line
  51. * - parent_id: (optional) only retrieve a sequence if 'derive_from_parent' is true
  52. * and the parent matches this ID.
  53. * - featureloc_id: (optional) only retrieve a sequence if 'derive_from_parent' is
  54. * true and the alignment is defined with this featureloc_id
  55. * @param $options
  56. * An associative array of options. Valid keys include:
  57. * - width: Indicate the number of bases to use per line. A new line will be added
  58. * after the specified number of bases on each line.
  59. * - is_html: Set to '1' if the sequence is meant to be displayed on a web page.
  60. * This will cause a <br> tag to separate lines of the FASTA sequence.
  61. * - derive_from_parent: Set to '1' if the sequence should be obtained from the parent
  62. * to which this feature is aligned.
  63. * - aggregate: Set to '1' if the sequence should only contain sub features, excluding
  64. * intro sub feature sequence. For example, set this option to obtain just
  65. * the coding sequence of an mRNA.
  66. * - upstream: An integer specifing the number of upstream bases to include in the output
  67. * - downstream: An integer specifying the number of downstream bases to include in the
  68. * output.
  69. * - sub_feature_types: Only include sub features (or child features) of the types
  70. * provided in the array
  71. * - relationship_type: If a relationship name is provided (e.g. sequence_of) then any
  72. * sequences that are in relationships of this type with matched sequences are also included
  73. * - relationship_part: If a relationship is provided in the preceeding argument then
  74. * the rel_part must be either 'object' or 'subject' to indicate which side of the
  75. * relationship the matched features belong
  76. *
  77. * @return
  78. * an array of matching sequence in the following keys for each sequence:
  79. * 'types' => an array of feature types that were used to derive the sequence (e.g. from an aggregated sequence)
  80. * 'upstream' => the number of upstream bases included in the sequence
  81. * 'downstream' => the number of downstream bases included in the sequence
  82. * 'defline' => the definintion line used to create a FASTA sequence
  83. * 'residues' => the residues
  84. * 'featureloc_id' => the featureloc_id if the sequences is from an alignment
  85. *
  86. * @ingroup tripal_chado_api
  87. */
  88. function tripal_get_feature_sequences($feature, $options) {
  89. // default values for finding the feature
  90. $feature_id = array_key_exists('feature_id', $feature) ? $feature['feature_id'] : 0;
  91. $parent_id = array_key_exists('parent_id', $feature) ? $feature['parent_id'] : 0;
  92. $featureloc_id = array_key_exists('featureloc_id', $feature) ? $feature['featureloc_id'] : 0;
  93. $feature_name = array_key_exists('name', $feature) ? $feature['name'] : '';
  94. // default values for building the sequence
  95. $num_bases_per_line = array_key_exists('width', $options) ? $options['width'] : 50;
  96. $derive_from_parent = array_key_exists('derive_from_parent', $options) ? $options['derive_from_parent'] : 0;
  97. $aggregate = array_key_exists('aggregate', $options) ? $options['aggregate'] : 0;
  98. $upstream = array_key_exists('upstream', $options) ? $options['upstream'] : 0;
  99. $downstream = array_key_exists('downstream', $options) ? $options['downstream'] : 0;
  100. $sub_features = array_key_exists('sub_feature_types', $options) ? $options['sub_feature_types'] : array();
  101. $relationship = array_key_exists('relationship_type', $options) ? $options['relationship_type'] : '';
  102. $rel_part = array_key_exists('relationship_part', $options) ? $options['relationship_part'] : '';
  103. $is_html = array_key_exists('is_html', $options) ? $options['is_html'] : 0;
  104. // make sure the sub_features variable is an array
  105. if (!is_array($sub_features)) {
  106. tripal_report_error('tripal_chado', TRIPAL_ERROR,
  107. "'sub_features' option must be an array for function tripal_get_feature_sequences().",
  108. array()
  109. );
  110. return array();
  111. }
  112. // if a relationship was specified then retreive and the sequences that
  113. // have the given relationship and the recurse to extract the appropriate
  114. // sequence
  115. if ($rel_part == "object" or $rel_part == "subject") {
  116. if ($rel_part == "subject") {
  117. $sql = '
  118. SELECT FO.feature_id, FO.name, FO.uniquename, CVTO.name as feature_type, O.genus, O.species
  119. FROM {feature} FS
  120. INNER JOIN {feature_relationship} FR ON FR.subject_id = FS.feature_id
  121. INNER JOIN {cvterm} CVTFR ON CVTFR.cvterm_id = FR.type_id
  122. INNER JOIN {feature} FO ON FO.feature_id = FR.object_id
  123. INNER JOIN {cvterm} CVTO ON CVTO.cvterm_id = FO.type_id
  124. INNER JOIN {organism} O ON O.organism_id = FO.organism_id
  125. WHERE
  126. FS.feature_id = :feature_id AND
  127. CVTFR.name = :relationship
  128. ';
  129. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  130. }
  131. if ($rel_part == "object") {
  132. $sql = '
  133. SELECT FS.feature_id, FS.name, FS.uniquename, CVTO.name as feature_type, O.genus, O.species
  134. FROM {feature} FO
  135. INNER JOIN {feature_relationship} FR ON FR.object_id = FO.feature_id
  136. INNER JOIN {cvterm} CVTFR ON CVTFR.cvterm_id = FR.type_id
  137. INNER JOIN {feature} FS ON FS.feature_id = FR.subject_id
  138. INNER JOIN {cvterm} CVTO ON CVTO.cvterm_id = FS.type_id
  139. INNER JOIN {organism} O ON O.organism_id = FS.organism_id
  140. WHERE
  141. FO.feature_id = :feature_id AND
  142. CVTFR.name = :relationship
  143. ';
  144. $features = chado_query($sql, array(':feature_id' => $feature_id, ':relationship' => $relationship));
  145. }
  146. $sequences = '';
  147. while ($feature = $features->fetchObject()) {
  148. // recurse and get the sequences for these in the relationship
  149. if ($rel_part == "subject") {
  150. $defline = "$feature_name, $relationship, $feature->uniquename $feature->feature_type ($feature->genus $feature->species)";
  151. }
  152. if ($rel_part == "object") {
  153. $defline = "$feature->uniquename $feature->feature_type ($feature->genus $feature->species), $relationship, $feature_name";
  154. }
  155. return tripal_get_feature_sequences(
  156. array(
  157. 'feature_id' => $feature->feature_id,
  158. 'name' => $defline,
  159. 'parent_id' => $parent_id,
  160. ),
  161. array(
  162. 'width' => $num_bases_per_line,
  163. 'derive_from_parent' => $derive_from_parent,
  164. 'aggregate' => $aggregate,
  165. 'upstream' => $upstream,
  166. 'downstream' => $downstream,
  167. 'sub_features' => $sub_features,
  168. )
  169. );
  170. }
  171. }
  172. // prepare the queries we're going to use later during the render phase
  173. // This SQL statement uses conditionals in the select clause to handle
  174. // cases cases where the alignment is in the reverse direction and when
  175. // the upstream and downstream extensions go beyond the lenght of the
  176. // parent sequence.
  177. $parent_sql ='
  178. SELECT featureloc_id, srcname, srcfeature_id, strand, srctypename, typename,
  179. fmin, fmax, upstream, downstream, adjfmin, adjfmax,
  180. substring(residues from (adjfmin + 1) for (upstream + (fmax - fmin) + downstream)) as residues,
  181. genus, species
  182. FROM (
  183. SELECT
  184. FL.featureloc_id, OF.name srcname, FL.srcfeature_id, FL.strand,
  185. OCVT.name as srctypename, SCVT.name as typename,
  186. FL.fmin, FL.fmax, OO.genus, OO.species,
  187. CASE
  188. WHEN FL.strand >= 0 THEN
  189. CASE
  190. WHEN FL.fmin - :upstream <= 0 THEN 0
  191. ELSE FL.fmin - :upstream
  192. END
  193. WHEN FL.strand < 0 THEN
  194. CASE
  195. WHEN FL.fmin - :downstream <= 0 THEN 0
  196. ELSE FL.fmin - :downstream
  197. END
  198. END as adjfmin,
  199. CASE
  200. WHEN FL.strand >= 0 THEN
  201. CASE
  202. WHEN FL.fmax + :downstream > OF.seqlen THEN OF.seqlen
  203. ELSE FL.fmax + :downstream
  204. END
  205. WHEN FL.strand < 0 THEN
  206. CASE
  207. WHEN FL.fmax + :upstream > OF.seqlen THEN OF.seqlen
  208. ELSE FL.fmax + :upstream
  209. END
  210. END as adjfmax,
  211. CASE
  212. WHEN FL.strand >= 0 THEN
  213. CASE
  214. WHEN FL.fmin - :upstream <= 0 THEN FL.fmin
  215. ELSE :upstream
  216. END
  217. ELSE
  218. CASE
  219. WHEN FL.fmax + :upstream > OF.seqlen THEN OF.seqlen - FL.fmax
  220. ELSE :upstream
  221. END
  222. END as upstream,
  223. CASE
  224. WHEN FL.strand >= 0 THEN
  225. CASE
  226. WHEN FL.fmax + :downstream > OF.seqlen THEN OF.seqlen - FL.fmax
  227. ELSE :downstream
  228. END
  229. ELSE
  230. CASE
  231. WHEN FL.fmin - :downstream <= 0 THEN FL.fmin
  232. ELSE :downstream
  233. END
  234. END as downstream,
  235. OF.residues
  236. FROM {featureloc} FL
  237. INNER JOIN {feature} SF on FL.feature_id = SF.feature_id
  238. INNER JOIN {cvterm} SCVT on SF.type_id = SCVT.cvterm_id
  239. INNER JOIN {feature} OF on FL.srcfeature_id = OF.feature_id
  240. INNER JOIN {cvterm} OCVT on OF.type_id = OCVT.cvterm_id
  241. INNER JOIN {organism} OO on OF.organism_id = OO.organism_id
  242. WHERE SF.feature_id = :feature_id and NOT (OF.residues = \'\' or OF.residues IS NULL)) as tbl1
  243. ';
  244. // this query is meant to get all of the sub features of any given
  245. // feature (arg #1) and order them as they appear on the reference
  246. // feature (arg #2).
  247. $sfsql = '
  248. SELECT SF.feature_id, CVT.name as type_name, SF.type_id
  249. FROM {feature_relationship} FR
  250. INNER JOIN {feature} SF ON SF.feature_id = FR.subject_id
  251. INNER JOIN {cvterm} CVT ON CVT.cvterm_id = SF.type_id
  252. INNER JOIN {featureloc} FL ON FL.feature_id = FR.subject_id
  253. INNER JOIN {feature} PF ON PF.feature_id = FL.srcfeature_id
  254. WHERE FR.object_id = :feature_id and PF.feature_id = :srcfeature_id
  255. ORDER BY FL.fmin ASC
  256. ';
  257. // for counting the number of children
  258. $fsql ='
  259. SELECT count(*) as num_children
  260. FROM {feature_relationship} FR
  261. INNER JOIN {feature} SF ON SF.feature_id = FR.subject_id
  262. INNER JOIN {cvterm} CVT ON CVT.cvterm_id = SF.type_id
  263. INNER JOIN {featureloc} FL ON FL.feature_id = FR.subject_id
  264. INNER JOIN {feature} PF ON PF.feature_id = FL.srcfeature_id
  265. WHERE FR.object_id = :feature_id and PF.feature_id = :srcfeature_id
  266. ';
  267. // the array to be returned
  268. $sequences = array();
  269. // if we need to get the sequence from the parent then do so now.
  270. if ($derive_from_parent) {
  271. // execute the query to get the sequence from the parent
  272. $parents = chado_query($parent_sql, array(':upstream' => $upstream, ':downstream' => $downstream, ':feature_id' => $feature_id));
  273. while ($parent = $parents->fetchObject()) {
  274. // if the user specified a particular parent and this one doesn't match then skip it
  275. if ($parent_id and $parent_id != $parent->srcfeature_id) {
  276. continue;
  277. }
  278. // if the user specified a particular featureloc_id and this one doesn't match then skip it
  279. if ($featureloc_id and $featureloc_id != $parent->featureloc_id) {
  280. continue;
  281. }
  282. $seq = ''; // initialize the sequence for each parent
  283. $notes = '';
  284. // if we are to aggregate then we will ignore the feature returned
  285. // by the query above and rebuild it using the sub features
  286. if ($aggregate) {
  287. // now get the sub features that are located on the parent.
  288. $children = chado_query($sfsql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id));
  289. $num_children = chado_query($fsql, array(':feature_id' => $feature_id, ':srcfeature_id' => $parent->srcfeature_id))->fetchField();
  290. // iterate through the sub features and concat their sequences. They
  291. // should already be in order.
  292. $types = array();
  293. $i = 0;
  294. while ($child = $children->fetchObject()) {
  295. // if the callee has specified that only certain sub features should be
  296. // included then continue if this child is not one of those allowed
  297. // subfeatures
  298. if (count($sub_features) > 0 and !in_array($child->type_name, $sub_features)) {
  299. $i++;
  300. continue;
  301. }
  302. // keep up with the types
  303. if (!in_array($child->type_name, $types)) {
  304. $types[] = $child->type_name;
  305. }
  306. // if the first sub feature we need to include the upstream bases. first check if
  307. // the feature is in the foward direction or the reverse.
  308. if ($i == 0 and $parent->strand >= 0) { // forward direction
  309. // -------------------------- ref
  310. // ....----> ---->
  311. // up 1 2
  312. $q = chado_query($parent_sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  313. }
  314. elseif ($i == 0 and $parent->strand < 0) { // reverse direction
  315. // -------------------------- ref
  316. // ....<---- <----
  317. // down 1 2
  318. $q = chado_query($parent_sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  319. }
  320. // Next, if the last sub feature we need to include the downstream bases. first check if
  321. // the feature is in teh forward direction or the reverse
  322. elseif ($i == $num_children - 1 and $parent->strand >= 0) { // forward direction
  323. // -------------------------- ref
  324. // ----> ---->....
  325. // 1 2 down
  326. $q = chado_query($parent_sql, array(':upstream' => 0, ':downstream' => $downstream, ':feature_id' => $child->feature_id));
  327. }
  328. elseif ($i == $num_children - 1 and $parent->strand < 0) { // reverse direction
  329. // -------------------------- ref
  330. // <---- <----....
  331. // 1 2 up
  332. $q = chado_query($parent_sql, array(':upstream' => $upstream, ':downstream' => 0, ':feature_id' => $child->feature_id));
  333. }
  334. // for internal sub features we don't want upstream or downstream bases
  335. else {
  336. $q = chado_query($parent_sql, array(':upstream' => 0, ':downstream' => 0, ':feature_id' => $child->feature_id));
  337. }
  338. while ($subseq = $q->fetchObject()) {
  339. // concatenate the sequences of all the sub features
  340. if ($subseq->srcfeature_id == $parent->srcfeature_id) {
  341. $seq .= $subseq->residues;
  342. }
  343. if ($subseq->upstream > 0 ) {
  344. $notes .= "Includes " . $subseq->upstream . " bases upstream. ";
  345. }
  346. if ($subseq->downstream > 0) {
  347. $notes .= "Includes " . $subseq->downstream . " bases downstream. ";
  348. }
  349. }
  350. $i++;
  351. }
  352. }
  353. // if this isn't an aggregate then use the parent residues
  354. else {
  355. $seq = $parent->residues;
  356. if ($parent->upstream > 0) {
  357. $notes .= "Includes " . $parent->upstream . " bases upstream. ";
  358. }
  359. if ($parent->downstream > 0) {
  360. $notes .= "Includes " . $parent->downstream . " bases downstream. ";
  361. }
  362. }
  363. // get the reverse compliment if feature is on the reverse strand
  364. $dir = 'forward';
  365. $length = strlen($seq);
  366. if ($parent->strand < 0) {
  367. $seq = tripal_reverse_compliment_sequence($seq);
  368. $dir = 'reverse';
  369. }
  370. // now format for display
  371. if ($is_html) {
  372. $seq = wordwrap($seq, $num_bases_per_line, "<br>", TRUE);
  373. }
  374. else {
  375. $seq = wordwrap($seq, $num_bases_per_line, "\r\n", TRUE);
  376. }
  377. if (!$seq) {
  378. $notes .= "No sequence available.";
  379. }
  380. if (count($types) > 0) {
  381. $notes .= "Excludes all bases but those of type(s): " . implode(', ', $types) . ". " ;
  382. }
  383. // construct the definition line for this feature.
  384. // to construct the defline we need a featureloc record, so we'll create one using
  385. // the information we have
  386. $featureloc = new stdClass;
  387. $featureloc->feature_id = $feature;
  388. $featureloc->fmin = $parent->adjfmin;
  389. $featureloc->fmax = $parent->adjfmax;
  390. $featureloc->strand = $parent->strand;
  391. $featureloc->srcfeature_id = new stdClass;
  392. $featureloc->srcfeature_id->name = $parent->srcname;
  393. $featureloc->srcfeature_id->type_id = $parent->srctypename;
  394. $featureloc->srcfeature_id->organism_id = new stdClass;
  395. $featureloc->srcfeature_id->organism_id->genus = $parent->genus;
  396. $featureloc->srcfeature_id->organism_id->species = $parent->species;
  397. // get a proper feature object
  398. $f = chado_generate_var('feature', array('feature_id' => $feature_id));
  399. $defline = tripal_get_fasta_defline($f, $notes, $featureloc, '', $length);
  400. $sequences[] = array(
  401. 'types' => $types,
  402. 'upstream' => $parent->upstream,
  403. 'downstream' => $parent->downstream,
  404. 'defline' => $defline,
  405. 'residues' => $seq,
  406. 'featureloc_id' => $parent->featureloc_id,
  407. 'length' => $length,
  408. );
  409. }
  410. }
  411. // if we are not getting the sequence from the parent sequence then
  412. // use what comes through from the feature record
  413. else {
  414. $sql = "SELECT * FROM {feature} F WHERE feature_id = :feature_id";
  415. $values = chado_query($sql, array(':feature_id' => $feature_id))->fetchObject();
  416. $residues = $values->residues;
  417. $length = strlen($residues);
  418. if ($is_html) {
  419. $residues = wordwrap($residues, $num_bases_per_line, "<br>", TRUE);
  420. }
  421. else {
  422. $residues = wordwrap($residues, $num_bases_per_line, "\r\n", TRUE);
  423. }
  424. // get the definintion line for this feature
  425. $f = chado_generate_var('feature', array('feature_id' => $feature_id));
  426. $defline = tripal_get_fasta_defline($f, '', NULL, '', $length);
  427. // add to the sequence array
  428. $sequences[] = array(
  429. 'types' => $values->type,
  430. 'upstream' => 0,
  431. 'downstream' => 0,
  432. 'defline' => $defline,
  433. 'residues' => $residues,
  434. 'length' => $length,
  435. );
  436. }
  437. return $sequences;
  438. }
  439. /**
  440. * Retreives or prints multiple sequences from features found using the options provided.
  441. *
  442. * @param $options
  443. * An associative array of options for selecting a feature. Valid keys include:
  444. * - org_commonname: The common name of the organism for which sequences should be retrieved
  445. * - genus: The genus of the organism for which sequences should be retrieved
  446. * - species: The species of the organism for which sequences should be retrieved
  447. * - analysis_name: The name of an analysis to which sequences belong. Only those that are
  448. * associated with the analysis will be retrieved.
  449. * - type: The type of feature (a sequence ontology term).
  450. * - feature_name: the name of the feature. Can be an array of feature names.
  451. * - feature_uname: the uniquename of the feature. Can be an array of feature unique names.
  452. * - upstream: An integer specifing the number of upstream bases to include in the output
  453. * - downstream: An integer specifying the number of downstream bases to include in the
  454. * output.
  455. * - derive_from_parent: Set to '1' if the sequence should be obtained from the parent
  456. * to which this feature is aligned.
  457. * - aggregate: Set to '1' if the sequence should only contain sub features, excluding
  458. * intro sub feature sequence. For example, set this option to obtain just
  459. * the coding sequence of an mRNA.
  460. * - sub_feature_types: Only include sub features (or child features) of the types
  461. * provided in the array
  462. * - relationship_type: If a relationship name is provided (e.g. sequence_of) then any
  463. * sequences that are in relationships of this type with matched sequences are also included
  464. * - relationship_part: If a relationship is provided in the preceeding argument then
  465. * the rel_part must be either 'object' or 'subject' to indicate which side of the
  466. * relationship the matched features belong
  467. * - width: Indicate the number of bases to use per line. A new line will be added
  468. * after the specified number of bases on each line.
  469. * - is_html: Set to '1' if the sequence is meant to be displayed on a web page.
  470. * This will cause a <br> tag to separate lines of the FASTA sequence.
  471. * - print: Set to TRUE to print the sequences rather otherwise an array
  472. * of sequences will be returned.
  473. * @return
  474. * Returns an array of sequences unless the option 'print' is used. If 'print is used
  475. * then nothing is returned but sequences are printed to STDOUT. If returned, the
  476. * sequences will be in an array with the following keys for each sequence:
  477. * 'types' => an array of feature types that were used to derive the sequence (e.g. from an aggregated sequence)
  478. * 'upstream' => the number of upstream bases included in the sequence
  479. * 'downstream' => the number of downstream bases included in the sequence
  480. * 'defline' => the definintion line used to create a FASTA sequence
  481. * 'residues' => the residues
  482. * 'featureloc_id' => the featureloc_id if the sequences is from an alignment
  483. *
  484. * @ingroup tripal_chado_api
  485. */
  486. function tripal_get_bulk_feature_sequences($options) {
  487. // default values for building the sequence
  488. $org_commonname = array_key_exists('org_commonname', $options) ? $options['org_commonname'] : '';
  489. $genus = array_key_exists('genus', $options) ? $options['genus'] : '';
  490. $species = array_key_exists('species', $options) ? $options['species'] : '';
  491. $analysis_name = array_key_exists('analysis_name', $options) ? $options['analysis_name'] : '';
  492. $type = array_key_exists('type', $options) ? $options['type'] : '';
  493. $feature_name = array_key_exists('feature_name', $options) ? $options['feature_name'] : '';
  494. $feature_uname = array_key_exists('feature_uname', $options) ? $options['feature_uname'] : '';
  495. $derive_from_parent = array_key_exists('derive_from_parent', $options) ? $options['derive_from_parent'] : 0;
  496. $aggregate = array_key_exists('aggregate', $options) ? $options['aggregate'] : 0;
  497. $sub_features = array_key_exists('sub_feature_types', $options) ? $options['sub_feature_types'] : array();
  498. $relationship = array_key_exists('relationship_type', $options) ? $options['relationship_type'] : '';
  499. $rel_part = array_key_exists('relationship_part', $options) ? $options['relationship_part'] : '';
  500. $num_bases_per_line = array_key_exists('width', $options) ? $options['width'] : 50;
  501. $upstream = array_key_exists('upstream', $options) ? $options['upstream'] : 0;
  502. $downstream = array_key_exists('downstream', $options) ? $options['downstream'] : 0;
  503. $print = array_key_exists('print', $options) ? $options['print'] : FALSE;
  504. $sub_features = explode(',', $child);
  505. if (!$output_format) {
  506. $output_format = 'fasta_txt';
  507. }
  508. if (!$type and !$feature_name and !$genus) {
  509. print "Please provide a type, feature name or genus\n";
  510. return;
  511. }
  512. // get the list of features
  513. $vars = array();
  514. $sql = "SELECT DISTINCT F.feature_id, F.name, F.uniquename, O.genus, O.species, CVT.name as feature_type " .
  515. "FROM {feature} F " .
  516. " INNER JOIN {organism} O on O.organism_id = F.organism_id " .
  517. " INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id ";
  518. if ($analysis_name) {
  519. $sql .= " INNER JOIN {analysisfeature} AF on AF.feature_id = F.feature_id " .
  520. " INNER JOIN {analysis} A on AF.analysis_id = A.analysis_id ";
  521. }
  522. $sql .= "WHERE (1=1) ";
  523. if ($org_commonname) {
  524. $sql .= "AND O.common_name = :common_name ";
  525. $vars[':common_name'] = $org_commonname;
  526. }
  527. if ($genus) {
  528. $sql .= "AND O.genus = :genus ";
  529. $vars[':genus'] = $genus;
  530. }
  531. if ($species) {
  532. $sql .= "AND O.species = :species ";
  533. $vars[':species'] = $species;
  534. }
  535. if ($type) {
  536. $sql .= "AND CVT.name = :cvtname ";
  537. $vars[':cvtname'] = $type;
  538. }
  539. if ($feature_name) {
  540. if (is_array($feature_name)) {
  541. $sql .= "AND F.name IN (";
  542. foreach ($feature_name as $i => $fname) {
  543. $sql .= ":fname$i, ";
  544. $vars[":fname$i"] = $fname;
  545. }
  546. // remove the trailing comma and close the paren
  547. $sql = substr($sql, 0, -2) . ")";
  548. }
  549. else {
  550. $sql .= "AND F.name = :fname";
  551. $vars[':fname'] = $feature_name;
  552. }
  553. }
  554. if ($feature_uname) {
  555. if (is_array($feature_uname)) {
  556. $sql .= "AND F.uniquename IN (";
  557. foreach ($feature_uname as $i => $funame) {
  558. $sql .= ":funame$i, ";
  559. $vars[":funame$i"] = $funame;
  560. }
  561. // remove the trailing comma and close the paren
  562. $sql = substr($sql, 0, -2) . ")";
  563. }
  564. else {
  565. $sql .= "AND F.uniquename = :funame";
  566. $vars[':funame'] = $feature_uname;
  567. }
  568. }
  569. if ($analysis_name) {
  570. $sql .= "AND A.name = :aname";
  571. $vars[':aname'] = $analysis_name;
  572. }
  573. $num_bases_per_line = 50;
  574. $num_seqs = 0;
  575. $q = chado_query($sql, $vars);
  576. $sequences = array();
  577. while ($feature = $q->fetchObject()) {
  578. // get the sequences
  579. $seqs = tripal_get_feature_sequences(array('feature_id' => $feature->feature_id), $options);
  580. if ($print) {
  581. foreach ($seqs as $seq) {
  582. print ">" . $seq['defline'] . "\n";
  583. print $seq['residues'] . "\n";
  584. }
  585. }
  586. else {
  587. $sequences = array_merge($sequences, $seqs);
  588. }
  589. $num_seqs++;
  590. }
  591. if (!$print) {
  592. return $seqs;
  593. }
  594. elseif ($num_seqs == 0) {
  595. print "No Sequences Found";
  596. }
  597. }
  598. /**
  599. * Returns a definition line that can be used in a FASTA file
  600. *
  601. * @param $feature
  602. * A single feature object containing all the fields from the chado.feature table.
  603. * Best case is to provide an object generated by the chado_generate_var() function.
  604. * @param $notes
  605. * Optional: additional notes to be added to the definition line
  606. * @param $featureloc
  607. * Optional: a single featureloc object generated using chado_generate_var that
  608. * contains a record from the chado.featureloc table. Provide this if the
  609. * sequence was obtained by using the alignment rather than from the feature.residues
  610. * column
  611. * @param $type
  612. * Optional: the type of sequence. By default the feature type is used.
  613. * @param $length
  614. * Optional: the length of the sequence
  615. *
  616. * @return
  617. * A string of the format: uniquename|name|type|feature_id
  618. * or if an alignment: srcfeature_name:fmin..fmax[+-]; alignment of uniquename|name|type|feature_id
  619. */
  620. function tripal_get_fasta_defline($feature, $notes = '', $featureloc = NULL, $type = '', $length = 0) {
  621. // make sure the featureloc object has the srcfeature if not, then add it
  622. if ($featureloc) {
  623. if (!is_object($featureloc->srcfeature_id)) {
  624. $featureloc->srcfeature_id = chado_generate_var('feature', array('feature_id' => $featureloc->srcfeature_id));
  625. }
  626. if (!is_object($featureloc->srcfeature_id->organism_id)) {
  627. $featureloc->srcfeature_id->organism_id = chado_generate_var('organism', array('organism_id' => $featureloc->srcfeature_id->organism_id));
  628. }
  629. }
  630. // make sure the feature object has the organism if not, then add it
  631. if (!is_object($feature->organism_id)) {
  632. $feature->organism_id = chado_generate_var('organism', array('organism_id' => $feature->organism_id));
  633. }
  634. // if a type is not provided then use the default type
  635. if (!$type) {
  636. $type = $feature->type_id->name;
  637. }
  638. // construct the definition line
  639. $defline = $feature->uniquename . " " .
  640. 'ID=' . $feature->uniquename . "|" .
  641. 'Name=' . $feature->name . "|" .
  642. 'organism=' . $feature->organism_id->genus . " " . $feature->organism_id->species . "|" .
  643. 'type=' . $type . '|';
  644. if ($length > 0) {
  645. $defline .= "length=" . $length . "bp|";
  646. }
  647. if ($featureloc) {
  648. $defline .= "location=Sequence derived from alignment at " . tripal_get_location_string($featureloc);
  649. $defline .= " (" . $featureloc->srcfeature_id->organism_id->genus . " " . $featureloc->srcfeature_id->organism_id->species . ")|";
  650. }
  651. if ($notes) {
  652. $defline .= "Notes=$notes|";
  653. }
  654. $defline = substr($defline, 0, -1); // remove the trailing |
  655. return $defline;
  656. }
  657. /**
  658. * Returns a string representing a feature location in an alignment
  659. *
  660. * @param unknown $featureloc
  661. * A single featureloc object generated using chado_generate_var that
  662. * contains a record from the chado.featureloc table.
  663. */
  664. function tripal_get_location_string($featureloc) {
  665. $feature = $featureloc->feature_id;
  666. $strand = '';
  667. if ($featureloc->strand == 1) {
  668. $strand = '+';
  669. }
  670. elseif ($featureloc->strand == -1) {
  671. $strand = '-';
  672. }
  673. return $featureloc->srcfeature_id->name . ":" . ($featureloc->fmin + 1) . ".." . $featureloc->fmax . $strand;
  674. }