blast_ui.linkouts.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. <?php
  2. /**
  3. * @file
  4. * Provides Link-out functionality for BLAST hits.
  5. *
  6. * Specifically, this is how the URL portion of the hit links in your users
  7. * Blast results is formed.
  8. *
  9. * To implement your own link-out type:
  10. * 1) Register your link-out type by implementing hook_blast_linkout_info().
  11. * Hook blast_linkout_info must return an array of types where each type
  12. * has a name and process function. For exmaple,
  13. * @code
  14. function blast_ui_blast_linkout_info() {
  15. $types = array();
  16. $types['my-link-type'] = array(
  17. 'name' => 'My Amazing Link Type',
  18. 'process function' => 'mymodule_generate_linkout_mylinktype',
  19. );
  20. return $types;
  21. }
  22. * @endcode
  23. *
  24. * 2) Implement the process function you specified to determine the URL
  25. * to be linked to depending on the blast hit. For a full description of
  26. * parameters available to your function, see tripal_blast_generate_linkout_link().
  27. * @code
  28. function mymodule_generate_linkout_mylinktype($url_prefix, $hit, $info, $options = array()) {
  29. // Do some simple steps to generate the suffix based on the $hit.
  30. return l('url name', $url_prefix . $url_postfix);
  31. }
  32. * @endcode
  33. *
  34. * This module will automatically,
  35. * - Add your custom type to the "Link-out Type" select list on Blast Database
  36. * node add/edit forms.
  37. * - If your type is chosen by the user when the Blast Database is created,
  38. * then your process function will be used by blast_report.tpl.php to
  39. * determine the URL that should be used for each hit link.
  40. */
  41. /**
  42. * Implements hook_blast_linkout_info().
  43. * Provide information on basic link-out types: link, GBrowse, JBrowse.
  44. *
  45. * NOTE: Each item must have a 'name' and 'process function' to indicate the
  46. * human-readable name to be used in the Blast Database add/edit form and the
  47. * function to be used to determine the URL for each hit in BLAST results.
  48. */
  49. function blast_ui_blast_linkout_info() {
  50. $types = array();
  51. // A default link-out type requiring no information.
  52. $types['none'] = array(
  53. 'name' => 'None',
  54. 'process function' => 'tripal_blast_generate_linkout_none',
  55. 'help' => 'This will leave the blast results hits as plain text.',
  56. 'require_regex' => FALSE,
  57. 'require_db' => FALSE,
  58. );
  59. $types['link'] = array(
  60. // Human-readable Type name to display to users in the BLAST Database
  61. // create/edit form.
  62. 'name' => 'Generic Link',
  63. // The function used to generate the URL to be linked to.
  64. // This function will have full access to the blast hit and database
  65. // prefix information and is expected to return a URL.
  66. 'process function' => 'tripal_blast_generate_linkout_link',
  67. // Help text to show in the BLAST Database create/edit form so that
  68. // users will know how to use this link-out type. Specifically, info
  69. // about your assumptions for the URL prefix are very helpful.
  70. // HTML is aloud but do not enclose in <p>.
  71. 'help' => 'The External Database choosen below provides its URL prefix when
  72. determining the URL to link-out to. If the link-out type is "Generic Link" then
  73. the hit identifier (determined using fasta header format or regular expression) is
  74. concatenated to the end of the url prefix. For example, if your hit is for "Chr01"
  75. and the URL prefix is "http://myfriendstripalsite.org/name/" then the complete URL
  76. is simply &#60;a href="http://myfriendstripalsite.org/name/Chr01"&#62;Chr01&#60;/a&#62;.',
  77. // Whether or not the link-out requires additional fields from the nodes.
  78. 'require_regex' => TRUE,
  79. 'require_db' => TRUE,
  80. );
  81. $types['gbrowse'] = array(
  82. 'name' => 'GBrowse',
  83. 'process function' => 'tripal_blast_generate_linkout_gbrowse',
  84. 'help' => 'The link created will add a BLAST track to the GBrowse (specified by the
  85. External Database) that shows the HSPs as well as indicating the overall hit.
  86. <strong><em>It is assumed that the Reference of the GBrowse is the same as this BLAST
  87. database (even the names must be consistent).</em></strong> Furthermore, the URL prefix
  88. supplied is expected to have an empty query (?) or be properly ended (;). For
  89. example, "http://mydomain.com/gb/gbrowse/tripalus_databasica/?" OR
  90. "http://mydomain.com/gb/gbrowse/tripalus_databasica/?label=genes+markers;"',
  91. // Whether or not the link-out requires additional fields from the nodes.
  92. 'require_regex' => TRUE,
  93. 'require_db' => TRUE,
  94. );
  95. $types['jbrowse'] = array(
  96. 'name' => 'JBrowse',
  97. 'process function' => 'tripal_blast_generate_linkout_jbrowse',
  98. 'help' => 'The link created will add a "Blast Result" track to the JBrowse (specified by the
  99. External Database) that shows the HSPs as well as indicating the overall hit.
  100. <strong><em>It is assumed that the Reference of the JBrowse is the same as this BLAST
  101. database (even the names must be consistent).</em></strong> Furthermore, the URL prefix
  102. supplied is expected to have an empty query (?) or be properly ended (&). For
  103. example, "http://mydomain.com/jbrowse/tripalus_databasica/?" OR
  104. "http://mydomain.com/jbrowse/tripalus_databasica/?tracks=genes,markers,blast&".
  105. Also <strong><em>the Blast Result track is NOT Displayed by default</em></strong>. Either include "blast"
  106. using the "tracks" directive in the URL prefix or specify it in your JBrowse.conf.',
  107. // Whether or not the link-out requires additional fields from the nodes.
  108. 'require_regex' => TRUE,
  109. 'require_db' => TRUE,
  110. );
  111. return $types;
  112. }
  113. /**
  114. * Generate a basic link-out for a given hit.
  115. *
  116. * Essentially, concatenate the URL prefix with the extracted hit identifier
  117. * and return the URL to be displayed by the BLAST report template.
  118. *
  119. * @param $url_prefix
  120. * The URL prefix for the BLAST Database queried.
  121. * @param $hit
  122. * The blast XML hit object. This object has the following keys based on the
  123. * XML: Hit_num, Hit_id, Hit_def, Hit_accession, Hit_len and Hit_hsps.
  124. * Furthermore, a linkout_id key has beek added that contains the part of the
  125. * Hit_def extracted using a regex provided when the blastdb node was created.
  126. * @param $info
  127. * Additional information that may be useful in creating a link-out. Includes:
  128. * - query_name: the name of the query sequence.
  129. * - score: the score of the blast hit.
  130. * - e-value: the e-value of the blast hit.
  131. * @param $options
  132. * Any additional options needed to determine the type of link-out. None are
  133. * supported by this particular link-out type.
  134. *
  135. * @return
  136. * An html link.
  137. */
  138. function tripal_blast_generate_linkout_link($url_prefix, $hit, $info, $options = array()) {
  139. if (isset($hit->{'linkout_id'})) {
  140. $hit_url = $url_prefix . $hit->{'linkout_id'};
  141. // Split out the CGI params, if any
  142. $params = array();
  143. if (!$paramstr=strstr($hit_url, '?')) {
  144. $url_prefix = $hit_url;
  145. }
  146. else {
  147. $url_parts = preg_split("/\?/", $hit_url);
  148. $url_prefix = $url_parts[0];
  149. $param_list = preg_split("/\&/", $url_parts[1]);
  150. foreach ($param_list as $param) {
  151. $param_parts = preg_split("/=/", $param, 2);
  152. $params[$param_parts[0]] = $param_parts[1];
  153. }
  154. }//URL contains CGI parameters
  155. return l(
  156. $hit->{'linkout_id'},
  157. $url_prefix,
  158. array('attributes' => array('target' => '_blank'), 'query' => $params)
  159. );
  160. }
  161. else {
  162. return FALSE;
  163. }
  164. }
  165. /**
  166. * Generate a GBrowse link-out with location information for a given hit.
  167. *
  168. * NOTE: Assumes the hit is a backbone feature in the GBrowse linked to.
  169. * Otherwise, the basic link can be used.
  170. *
  171. * @param $url_prefix
  172. * The URL prefix for the BLAST Database queried.
  173. * @param $hit
  174. * The blast XML hit object. This object has the following keys based on the
  175. * XML: Hit_num, Hit_id, Hit_def, Hit_accession, Hit_len and Hit_hsps.
  176. * Furthermore, a linkout_id key has beek added that contains the part of the
  177. * Hit_def extracted using a regex provided when the blastdb node was created.
  178. * @param $info
  179. * Additional information that may be useful in creating a link-out. Includes:
  180. * - query_name: the name of the query sequence.
  181. * - score: the score of the blast hit.
  182. * - e-value: the e-value of the blast hit.
  183. * @param $options
  184. * Any additional options needed to determine the type of link-out. None are
  185. * supported by this particular link-out type.
  186. *
  187. * @return
  188. * An html link.
  189. */
  190. function tripal_blast_generate_linkout_gbrowse($url_prefix, $hit, $info, $options = array()) {
  191. // First we need to collect the HSPs to define the ranges we want to
  192. // display on the JBrowse.
  193. $ranges = array();
  194. // We also keep track of all the coordinates in order to later
  195. // calculate the smallest and largest coordinate.
  196. $coords = array();
  197. foreach($info['HSPs'] as $hsp) {
  198. $start = min($hsp['Hsp_hit-from'], $hsp['Hsp_hit-to']);
  199. $stop = max($hsp['Hsp_hit-from'], $hsp['Hsp_hit-to']);
  200. // Format the hsp for inclusion in the new track later.
  201. array_push($ranges, "$start..$stop");
  202. // Add both the start & stop to the coordinate list.
  203. array_push($coords, $start, $stop);
  204. }
  205. // Calculate the minimum & maximum coordinates.
  206. $min = min($coords);
  207. $max = max($coords);
  208. // Now we are finally ready to build the URL.
  209. // First lets set the location of the hit so the GBrowse focuses in on the correct region.
  210. $query = array();
  211. $query['ref'] = $hit->{'linkout_id'};
  212. $query['start'] = $min;
  213. $query['stop'] = $max;
  214. // Next we want to add our BLAST hit to the GBrowse.
  215. $query['add'] = format_string(
  216. '!ref !trackname !featurename !hspcoords',
  217. array(
  218. '!ref' => $hit->{'linkout_id'},
  219. '!trackname' => 'BLAST',
  220. '!featurename' => 'BlastHit',
  221. '!hspcoords' => join ("," , $ranges),
  222. )
  223. );
  224. // Highlight our newly added feature.
  225. $query['h_feat'] = 'BlastHit';
  226. $hit_url = $url_prefix; //. $url_postfix;
  227. $url = l(
  228. $hit->{'linkout_id'},
  229. $hit_url,
  230. array(
  231. 'query' => $query,
  232. 'attributes' => array('target' => '_blank')
  233. )
  234. );
  235. // For some reason GBrowse expects semi-colons (;&) to delineate query paramters
  236. // whereas Drupal throws ampherstands (&) in. This is to fix that.
  237. $url = str_replace('&',';&', $url);
  238. return $url;
  239. }
  240. /**
  241. * Generate a JBrowse link-out with location information for a given hit.
  242. *
  243. * NOTE: Assumes the hit is a backbone feature in the JBrowse linked to.
  244. * Otherwise, the basic link can be used.
  245. * NOTE: This linkout creates a "blast" track but doesn't make it visible. This is to
  246. * allow your default tracks to be visible and give contect to your blast hit. You
  247. * should include "blast" in your jbrowse.conf default track list to ensure your
  248. * users can always see their hits. If you don't have access to the jbrowse.conf,
  249. * you can place the tracks you want to see including 'blast' in the url prefix
  250. * (see example below under @param $url_prefix).
  251. *
  252. * @param $url_prefix
  253. * The URL prefix for the BLAST Database queried. It is assumed that the url prefix
  254. * includes the ? and if there are any key=vale pairs that the last symbol is &.
  255. * For example,
  256. * http://myserver.com/jbrowse/databasica/?
  257. * http://myserver.com/jbrowse/databasica/?tracks=myfavtrack,anoktrack,blast&
  258. *
  259. * @param $hit
  260. * The blast XML hit object. This object has the following keys based on the
  261. * XML: Hit_num, Hit_id, Hit_def, Hit_accession, Hit_len and Hit_hsps.
  262. * Furthermore, the following keys have been added:
  263. * -linkout_id: the part of the Hit_def extracted using a regex provided
  264. * when the blastdb node was created.
  265. * -hit_name: the name of the hit extracted in the template.
  266. * @param $info
  267. * Additional information that may be useful in creating a link-out. Includes:
  268. * - query_name: the name of the query sequence.
  269. * - score: the score of the blast hit.
  270. * - e-value: the e-value of the blast hit.
  271. * @param $options
  272. * Any additional options needed to determine the type of link-out. None are
  273. * supported by this particular link-out type.
  274. *
  275. * @return
  276. * An html link.
  277. */
  278. function tripal_blast_generate_linkout_jbrowse($url_prefix, $hit, $info, $options = array()) {
  279. // First we need to collect the HSPs to define the ranges we want to
  280. // display on the JBrowse.
  281. $ranges = array();
  282. // We also keep track of all the coordinates in order to later
  283. // calculate the smallest and largest coordinate.
  284. $coords = array();
  285. $count = 0;
  286. $strands = array();
  287. foreach($info['HSPs'] as $hsp) {
  288. $count++;
  289. $strand = '1';
  290. $hsp_start = $hsp['Hsp_hit-from'];
  291. $hsp_end = $hsp['Hsp_hit-to'];
  292. $strands[] = $strand;
  293. // Handle alignments on the negative strand.
  294. if (($hsp_end - $hsp_start) < 0) {
  295. $strand = '-1';
  296. $hsp_start = $hsp['Hsp_hit-to'];
  297. $hsp_end = $hsp['Hsp_hit-from'];
  298. }
  299. // Add both the start & stop to the coordinate list.
  300. array_push($coords,$hsp['Hsp_hit-from'] , $hsp['Hsp_hit-to'] );
  301. // Format the hsp for inclusion in the subfeatures section of the track later.
  302. $hsp_def = format_string(
  303. '{"start":!start,"end":!end,"strand":"!strand","type":"!type"}',
  304. array(
  305. '!start' => $hsp_start,
  306. '!end' => $hsp_end,
  307. '!strand' => $strand,
  308. '!type' => 'match_part'
  309. )
  310. );
  311. array_push($ranges, $hsp_def);
  312. }
  313. // Calculate the minimum & maximum coordinates.
  314. $min = min($coords);
  315. $max = max($coords);
  316. // We also want some white-space on either side of out hit
  317. // when we show it in the JBrowse. To make this generic,
  318. // we want our blast hit to take up 2/3 of the screen thus
  319. // we have 1/6 per side for white-space.
  320. $buffer = round(($max - $min) / 6);
  321. $screen_start = $min - $buffer;
  322. $screen_end = $max + $buffer;
  323. // Now we are finally ready to build the URL.
  324. // First lets set the location of the hit so the JBrowse focuses in on the correct region.
  325. $jbrowse_query = array();
  326. $jbrowse_query['loc'] = format_string(
  327. 'loc=!ref:!start..!stop',
  328. array(
  329. '!ref' => $hit->{'linkout_id'},
  330. '!start' => $screen_start,
  331. '!stop' => $screen_end,
  332. )
  333. );
  334. $unique_strands = array_unique($strands);
  335. if (count($unique_strands) === 1) {
  336. $strand = end($strands);
  337. // Next we want to add our BLAST hit to the JBrowse.
  338. $jbrowse_query['addFeatures'] = format_string(
  339. 'addFeatures=[{"seq_id":"!id","start":!min,"end":!max,"name":"!name","strand":!strand,"subfeatures":[!hspcoords]}]',
  340. array(
  341. '!id' => $hit->{'linkout_id'},
  342. '!name' => $info['query_name'] . ' Blast Hit',
  343. '!min' => $min,
  344. '!max' => $max,
  345. '!hspcoords' => join(",", $ranges),
  346. '!strand' => $strand,
  347. )
  348. );
  349. }
  350. else {
  351. $jbrowse_query['addFeatures'] = format_string(
  352. 'addFeatures=[{"seq_id":"!id","start":!min,"end":!max,"name":"!name","subfeatures":[!hspcoords]}]',
  353. array(
  354. '!id' => $hit->{'linkout_id'},
  355. '!name' => $info['query_name'] . ' Blast Hit',
  356. '!min' => $min,
  357. '!max' => $max,
  358. '!hspcoords' => join(",", $ranges),
  359. )
  360. );
  361. }
  362. // Then add a track to display our new feature.
  363. $jbrowse_query['addTracks'] = 'addTracks=[{"label":"blast","key":"BLAST Result","type":"JBrowse/View/Track/CanvasFeatures","store":"url"}]';
  364. $url_postfix = implode('&', $jbrowse_query);
  365. $hit_url = $url_prefix . $url_postfix;
  366. return l(
  367. $hit->{'linkout_id'},
  368. $hit_url,
  369. array('attributes' => array('target' => '_blank'))
  370. );
  371. }