trees.inc

@todo Stephen describe this file

File

tripal_cv/includes/trees.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * @todo Stephen describe this file
  5. */
  6. /**
  7. * Renders the cv_list form
  8. *
  9. * @ingroup tripal_cv
  10. */
  11. function tripal_cv_show_browser() {
  12. $content = drupal_get_form('tripal_cv_list_form');
  13. $content .= "
  14. <div id=\"cv_browser\"></div>
  15. ";
  16. return $content;
  17. }
  18. /**
  19. * Generates JSON used for generating an exapandable tree of terms from
  20. * a controlled vocabulary that has associated counts.
  21. *
  22. * The progammer must first create a materialized view that
  23. * will generate count data for a given controlled vocabulary. For example, the Tripal
  24. * Analysis GO creates a materialized view for counting Gene Ontology assignments
  25. * to features. This view is created on install of the module and is named
  26. * 'go_count_analysis'.
  27. *
  28. * Second, the progammer must add an HTML 'div' box to the desired page
  29. * with a class name of 'tripal_cv_tree', and an id of the following format:
  30. *
  31. * tripal_[module_name]_cv_tree_[unique id]
  32. *
  33. * where [module_name] is the name of the tripal module (e.g. tripal_analyisis_go)
  34. * and [unique id] is some unique identifier that the contolling module
  35. * recognizes. This string is the $tree_id variable passed as the first argument
  36. * to the function. For example, the Tripal GO Analysis module generates
  37. * tree ids of the form:
  38. *
  39. * tripal_analysis_go_cv_tree_10-2_bp
  40. *
  41. * In this case the module that will manage this tree is identified as 'tripal_analysis_go' and within
  42. * the [unique id] portion contains the
  43. * organism_id (e.g. 10), analysis_id (e.g. 2) and tree type (bp = biological process).
  44. *
  45. * Second, the programmer must then define a hook in the controlling module for setting
  46. * some options used to build the chart. The hook has the form: hook_cv_tree($tree_id).
  47. * This hook should accept the full $tree_id as the single parameter. For the Tripal
  48. * Analysis GO module the hook is named: tripal_analysis_go_cv_tree.
  49. *
  50. * The array returned by this hook must have the following fields:
  51. * - cv_id
  52. * the cv_id for the controlled vocabulary
  53. * - count_mview
  54. * the name of the materialized view that contains the count data
  55. * this materialized view must have at least two columns, one with the cvterm_id
  56. * for each term and a second column containing the counts. The tree will only
  57. * be expanded to include child terms that have counts.
  58. * - cvterm_id_column
  59. * the column name in the materialized view that contains
  60. * the cvterm_ids
  61. * - count_column
  62. * the column name in the materialized view that contains the
  63. * counts
  64. * - filter
  65. * an SQL compatible WHERE clause string (whithout the word 'WHERE')
  66. * that can be used for filtering the records in the materialized view.
  67. * - label
  68. * the title for the tree
  69. *
  70. * Example from the tripal_analysis_go module:
  71. * @code
  72. * function tripal_analysis_go_cv_tree($tree_id) {
  73. *
  74. * $organism_id = preg_replace("/^tripal_analysis_go_cv_tree_(\d+)-(\d+)_(bp|cc|mf)$/","$1",$tree_id);
  75. * $analysis_id = preg_replace("/^tripal_analysis_go_cv_tree_(\d+)-(\d+)_(bp|cc|mf)$/","$2",$tree_id);
  76. * $type = preg_replace("/^tripal_analysis_go_cv_tree_(\d+)-(\d+)_(bp|cc|mf)$/","$3",$tree_id);
  77. *
  78. * if(strcmp($type,'mf')==0) {
  79. * $class = 'molecular_function';
  80. * }
  81. * if(strcmp($type,'cc')==0) {
  82. * $class = 'cellular_component';
  83. * }
  84. * if(strcmp($type,'bp')==0) {
  85. * $class = 'biological_process';
  86. * }
  87. *
  88. * $options = array(
  89. * cv_id => tripal_cv_get_cv_id($class),
  90. * count_mview => 'go_count_analysis',
  91. * cvterm_id_column => 'cvterm_id',
  92. * count_column => 'feature_count',
  93. * filter => "CNT.organism_id = $organism_id AND CNT.analysis_id = $analysis_id",
  94. * label => 'Features',
  95. * );
  96. * return $options;
  97. * }
  98. *
  99. * @endcode
  100. *
  101. * @param $tree_id
  102. * The unique identifier for the tree
  103. *
  104. * @return
  105. * JSON array needed for the jsTree package for generating expandable trees.
  106. *
  107. * With these three components (materialized view, a 'div' box with proper CSS class and ID, and a hook_cv_tree)
  108. * a tree will be created on the page. There is no need to call this function directly.
  109. *
  110. * @ingroup tripal_cv
  111. */
  112. function tripal_cv_tree($tree_id) {
  113. // parse out the tripal module name from the chart_id to find out
  114. // which Tripal "hook" to call:
  115. $tripal_mod = preg_replace("/^(tripal_.+?)_cv_tree_(.+)$/", "$1", $tree_id);
  116. if ($tripal_mod) {
  117. $callback = $tripal_mod . "_cv_tree";
  118. // now call the function in the module responsible for the tree. This
  119. // should call the tripal_cv_init_cv with the proper parameters set for
  120. // getting the cv_id of the vocabulary to use
  121. $opt = call_user_func_array($callback, array($tree_id));
  122. // we only need to return the cv_id for this function call.
  123. $json_array[] = $opt['cv_id'];
  124. }
  125. $json_array[] = $tree_id;
  126. return drupal_json($json_array);
  127. }
  128. /**
  129. *
  130. * @ingroup tripal_cv
  131. */
  132. function tripal_cv_update_tree() {
  133. $content = array();
  134. $ontology = 'sequence';
  135. // get the id of the term to look up
  136. $cv = check_plain($_REQUEST['cv']);
  137. $term = check_plain($_REQUEST['term']);
  138. $tree_id = check_plain($_REQUEST['tree_id']);
  139. // get the options needed for this tree from the tripal module that
  140. // wants to create the tree
  141. $tripal_mod = preg_replace("/^(tripal_.+?)_cv_tree_(.+)$/", "$1", $tree_id);
  142. if ($tripal_mod) {
  143. $callback = $tripal_mod . "_cv_tree";
  144. $opt = call_user_func_array($callback, array($tree_id));
  145. }
  146. // get the CV root terms
  147. if (strcmp($term, 'root')==0) {
  148. if (!$cv) {
  149. $cv = $opt['cv_id'];
  150. }
  151. $content = tripal_cv_init_tree($cv, $opt['count_mview'],
  152. $opt['cvterm_id_column'], $opt['count_column'], $opt['filter'], $opt['label']);
  153. // get the children terms
  154. }
  155. else {
  156. $content = tripal_cv_get_term_children($term, $opt['count_mview'],
  157. $opt['cvterm_id_column'], $opt['count_column'], $opt['filter'], $opt['label']);
  158. }
  159. drupal_json($content);
  160. }
  161. /**
  162. * Generates JSON needed for jsTree Root-level Branches
  163. *
  164. * This function returns the JSON array for the jsTree
  165. * jQuery code that builds a tree for browsing the ontology. This function
  166. * should be called to generate the root level branches of the tree.
  167. *
  168. * @ingroup tripal_cv
  169. */
  170. function tripal_cv_init_tree($cv_id, $cnt_table = NULL, $fk_column = NULL,
  171. $cnt_column = NULL, $filter = NULL, $label = NULL) {
  172. // get the list of root terms for the provided CV
  173. $sql = "
  174. SELECT *
  175. FROM {cv_root_mview} CRM
  176. WHERE cv_id = %d
  177. ";
  178. $results = chado_query($sql, $cv_id);
  179. // prepare the SQL statement that will allow us to pull out count
  180. // information for each term in the tree.
  181. if ($cnt_table) {
  182. if (!$filter) {
  183. $filter = '(1=1)';
  184. }
  185. $cnt_sql = "
  186. SELECT CVT.name, CVT.cvterm_id, CNT.$cnt_column as num_items
  187. FROM {$cnt_table} CNT
  188. INNER JOIN {cvterm} CVT on CNT.$fk_column = CVT.cvterm_id
  189. WHERE $filter AND CVT.cvterm_id = %d
  190. ORDER BY $cnt_column desc
  191. ";
  192. }
  193. while ($term = db_fetch_object($results)) {
  194. $name = $term->name;
  195. $count = 0;
  196. if ($cnt_table) {
  197. $cnt_results = chado_query($cnt_sql, $term->cvterm_id);
  198. while ($cnt = db_fetch_object($cnt_results)) {
  199. $count += $cnt->cnt;
  200. }
  201. if ($count > 0) {
  202. $name .= " ($count $label(s))";
  203. }
  204. }
  205. $content[] = array(
  206. 'attributes' => array(
  207. 'id' => $term->cvterm_id,
  208. ),
  209. 'state' => 'closed',
  210. 'data' => $name,
  211. 'children' => array(),
  212. );
  213. }
  214. return $content;
  215. }
  216. /**
  217. * Generates SON needed for jsTree -expanding a term to view children
  218. *
  219. * This function returns the JSON array for the jsTree
  220. * jQuery code when expanding a term to view it's children.
  221. *
  222. * @ingroup tripal_cv_api
  223. */
  224. function tripal_cv_get_term_children($cvterm_id, $cnt_table = NULL,
  225. $fk_column = NULL, $cnt_column = NULL, $filter = NULL, $label = NULL) {
  226. // get the children for the term provided
  227. $sql = "
  228. SELECT CVTR.cvterm_relationship_id,CVTR.subject_id,
  229. CVT1.name as subject_name, CVT3.name as type_name, CVTR.type_id,
  230. CVT2.name as object_name,CVTR.object_id
  231. FROM {cvterm_relationship} CVTR
  232. INNER JOIN {CVTerm} CVT1 on CVTR.subject_id = CVT1.cvterm_id
  233. INNER JOIN {CVTerm} CVT2 on CVTR.object_id = CVT2.cvterm_id
  234. INNER JOIN {CVTerm} CVT3 on CVTR.type_id = CVT3.cvterm_id
  235. INNER JOIN {CV} on CV.cv_id = CVT1.cv_id
  236. WHERE CVTR.object_id = %d
  237. ORDER BY CVT1.name
  238. ";
  239. $results = chado_query($sql, $cvterm_id);
  240. // prepare the SQL statement that will allow us to pull out count
  241. // information for each term in the tree.
  242. if ($cnt_table) {
  243. if (!$filter) {
  244. $filter = '(1=1)';
  245. }
  246. $cnt_sql = "
  247. SELECT CVT.name, CVT.cvterm_id, CNT.$cnt_column as num_items
  248. FROM {$cnt_table} CNT
  249. INNER JOIN {cvterm} CVT on CNT.$fk_column = CVT.cvterm_id
  250. WHERE $filter AND CVT.cvterm_id = %d
  251. ORDER BY $cnt_column desc
  252. ";
  253. }
  254. // populate the JSON content array
  255. while ($term = db_fetch_object($results)) {
  256. // count the number of items per term if requested
  257. $name = $term->subject_name;
  258. $count = 0;
  259. if ($cnt_table) {
  260. $cnt_results = chado_query($cnt_sql, $term->subject_id);
  261. while ($cnt = db_fetch_object($cnt_results)) {
  262. $count += $cnt->num_items;
  263. }
  264. if ($count > 0) {
  265. $name .= " (" . number_format($count) . " $label)";
  266. // check if we have any children if so then set the value
  267. $children = db_fetch_object(chado_query($sql, $term->subject_id));
  268. $state = 'leaf';
  269. if ($children) {
  270. $state = 'closed';
  271. }
  272. $content[] = array(
  273. 'attributes' => array(
  274. 'id' => $term->subject_id,
  275. ),
  276. 'state' => $state,
  277. 'data' => $name,
  278. 'children' => array(),
  279. );
  280. }
  281. }
  282. else {
  283. // check if we have any children if so then set the value
  284. $children = db_fetch_object(chado_query($sql, $term->subject_id));
  285. $state = 'leaf';
  286. if ($children) {
  287. $state = 'closed';
  288. }
  289. $content[] = array(
  290. 'attributes' => array(
  291. 'id' => $term->subject_id,
  292. ),
  293. 'state' => $state,
  294. 'data' => $name,
  295. 'children' => array(),
  296. );
  297. }
  298. }
  299. $content[] = $cnt_sql;
  300. return $content;
  301. }
  302. /**
  303. * @todo Stephen: describe what this function does
  304. * @ingroup tripal_cv
  305. */
  306. function tripal_cv_init_browser($cv_id) {
  307. $content = "
  308. <div id=\"tripal_cv_cvterm_info_box\">
  309. <a href=\"#\" onclick=\"$('#tripal_cv_cvterm_info_box').hide()\" style=\"float: right\">Close [X]</a>
  310. <h3>Term Information</h3>
  311. <div id=\"tripal_cv_cvterm_info\"></div>
  312. </div>
  313. <div id=\"tripal_ajaxLoading\" style=\"display:none\">
  314. <div id=\"loadingText\">Loading...</div>
  315. <img src=\"$url\">
  316. </div>
  317. <h3>Tree Browser</h3>
  318. <div id=\"browser\"</div>
  319. </div>
  320. ";
  321. drupal_json(array('update' => "$content"));
  322. }
  323. /**
  324. * Describe a cvterm (Rendered)
  325. *
  326. * @ingroup tripal_cv
  327. */
  328. function tripal_cv_cvterm_info($cvterm_id) {
  329. // get the id of the term to look up
  330. $cv = check_plain($_REQUEST['cv']);
  331. $tree_id = check_plain($_REQUEST['tree_id']);
  332. // first get any additional information to add to the cvterm
  333. if (strcmp($tree_id, 'undefined') != 0) {
  334. $tripal_mod = preg_replace("/^(tripal_.+?)_cv_tree_(.+)$/", "$1", $tree_id);
  335. if ($tripal_mod) {
  336. $callback = $tripal_mod . "_cvterm_add";
  337. $opt = call_user_func_array($callback, array($cvterm_id, $tree_id));
  338. }
  339. }
  340. $sql = "
  341. SELECT CVT.name as cvtermname, CVT.definition, CV.name as cvname,
  342. DBX.accession,DB.urlprefix,DB.db_id,DB.name as dbname
  343. FROM {CVTerm} CVT
  344. INNER JOIN {CV} on CVT.cv_id = CV.cv_id
  345. INNER JOIN {dbxref} DBX on CVT.dbxref_id = DBX.dbxref_id
  346. INNER JOIN {DB} on DBX.db_id = DB.db_id
  347. WHERE CVT.cvterm_id = %d
  348. ";
  349. $cvterm = db_fetch_object(chado_query($sql, $cvterm_id));
  350. $sql = "
  351. SELECT CVTS.synonym, CVT.name as cvname
  352. FROM {cvtermsynonym} CVTS
  353. INNER JOIN {cvterm} CVT on CVTS.type_id = CVT.cvterm_id
  354. WHERE CVTS.cvterm_id = %d
  355. ";
  356. $results = chado_query($sql, $cvterm_id);
  357. while ($synonym = db_fetch_object($results)) {
  358. $synonym_rows .= "<b>$synonym->cvname:</b> $synonym->synonym<br />";
  359. }
  360. $accession = $cvterm->accession;
  361. if ($cvterm->urlprefix) {
  362. $accession = "<a href=\"$cvterm->urlprefix$cvterm->accession\">$cvterm->accession</a>";
  363. }
  364. $content = "
  365. <div id=\"cvterm\">
  366. <table>
  367. <tr><th>Term</th><td>$cvterm->cvtermname</td></tr>
  368. <tr><th>Accession</th><td>$accession</td></tr>
  369. <tr><th>Ontology</th><td>$cvterm->cvname</td></tr>
  370. <tr><th>Definition</th><td>$cvterm->definition</td></tr>
  371. <tr><th>Synonyms</th><td>$synonym_rows</td></tr>
  372. <tr><th>Internal ID</th><td>$cvterm_id</td></tr>
  373. ";
  374. // now add in any additional options from a hook
  375. if ($opt) {
  376. foreach ($opt as $key => $value) {
  377. $content .= "<tr><th>$key</th><td>$value</td>";
  378. }
  379. }
  380. // close out the information table
  381. $content .= "
  382. </table>
  383. </div>
  384. ";
  385. drupal_json(array('update' => $content));
  386. }
  387. /**
  388. * Form listing CVs
  389. *
  390. * @ingroup tripal_cv
  391. */
  392. function tripal_cv_list_form($form_state) {
  393. // get a list of db from chado for user to choose
  394. $sql = "
  395. SELECT DISTINCT CV.name,CV.cv_id
  396. FROM {cvterm_relationship} CVTR
  397. INNER JOIN {cvterm} CVT on CVTR.object_id = CVT.cvterm_id
  398. INNER JOIN {CV} on CV.cv_id = CVT.cv_id
  399. ";
  400. $results = chado_query($sql);
  401. $blastdbs = array();
  402. $cvs[''] = '';
  403. while ($cv = db_fetch_object($results)) {
  404. $cvs[$cv->cv_id] = $cv->name;
  405. }
  406. $form['db_options'] = array(
  407. '#type' => 'value',
  408. '#value' => $cvs
  409. );
  410. $form['cv_list'] = array(
  411. '#title' => t('CVs with relationships'),
  412. '#type' => 'select',
  413. '#description' => t('Choose the controlled vocabulary to browse'),
  414. '#options' => $form['db_options']['#value'],
  415. '#attributes' => array(
  416. 'onChange' => "return tripal_cv_init_browser(this)",
  417. )
  418. );
  419. return $form;
  420. }