Tripal Hackathon @ San Deigo 2017-01-12

Meeting Date: 
Thursday, January 12, 2017
Attendees: 
  • Lacey-Anne Sanderson (both days)

  • Katheryn Buble (both days)

  • Valentin Guignon (both days)

  • Nic Herndon (both days)

  • Emily Grau (both days)

  • Eric Wafula (both days, beginner)

  • Prakash Timilsena (both days, beginner)

  • Meg Staton (meeting only)

  • Abdullah Almsaeed (both days)

  • Ming Chen (both days)

  • Steven Cannon (day 1 and first half of day 2)

  • Eliot Cline (both days)

  • Sudhansu Dash (day 1 and first half of day 2; beginner)

  • Luca Bianco (day 1; beginner)

  • Chris Childers (both days)

  • Ethy Cannon (1 ½ days)

  • Qiaoshan Lin (both days)

  • Sofia Robb (both days)

  • Taein Lee (both days)

  • Victor Unda (both days)

Agenda: 

Thursday, January 12

8:30am  Discuss ideas and break out into groups
9am - 12pm  Break-out Sessions
12pm - 1pm  LUNCH
1pm - 4pm  Break-out Sessions
4pm - 5pm  Round-table Discussion
Friday, January 13
 
 
Topics Covered
  • Module Development with sharing in mind

  • Tripal Download API

  • Using D3.js to display Chado Phylotree

Topic #1: How to make a Tripal module and make it shareable

The first time we attempted to break out into groups it became evident everyone wanted an introduction to making Tripal modules with tips on developing with sharing in mind. As such Lacey with help from other developers in the room gave an impromptu talk with examples:

  • Make a configuration form

  • When making a form you tell drupal to use the form api in hook_menu

  • Try to follow file-naming conventions and put code in the “usual” files. Being able to put most code pretty much anywhere can make it challenging to find bits of code.

  • Be careful with naming of Drupal variables to avoid conflicting with variables used by other variables, preferably prefaced with [machine] module name.

  • Likewise, function names should all be prefaced with [machine] module name

  • Choose a short, descriptive, unique machine name for the module. Note that this name is then used to prefix function and Drupal variable names; there is a limit on the length of Drupal variable names.

  • The module should be customizable.

    • Create hooks

    • Tripal 2: override templates - template name is displayed in admin “blue box” if logged in.

    • Tripal 3: don’t override templates (migrating to Twig templates), instead use Drupal Field API. Also enables use of different storage backends.

    • Your own custom hooks: https://www.drupal.org/docs/7/creating-custom-modules/creating-drupal-7-hooks  Take care the hooks have unique names.

  • Methods for altering a modules weight(d7 and d8)

  • Might want to separate generic and specific code into a core module and a customization of the core module. The core module would then be more shareable.

  • Create default templates inside module; put specific themes in your theme directory.

  • If your module implements hook_init, you need to make sure it will be loaded after Tripal has been initialized. To do so, you need to set the weight of your module to be higher than Tripal’s one. That’s done in your hook_install implementation with a piece of code like this:
     // Set loading order for tripal core.
     $tripal_weight = 0; // needs to be filled with Tripal core or other Tripal modules weight
     $sql_query = "UPDATE {system} SET weight = " . ($tripal_weight + 1) . " WHERE name = 'tripal_mymodule';";
     db_query($sql_query);

  • Materialized Views can adapt to varying methods of story data in chado.

Topic #2a: Tripal Download API

              $query = drupal_get_query_parameters();

  ?>

Download: <?php print l('GFF3', current_path() . '/gff3', array('target' => '_blank', 'query' => $query)); ?>

  • Save the view

Topic #2b: Having fun with D3JS (developing a module to display Chado phylotree)

  • Lead: Valentin Guignon

  • Participants:

    • Ming Chen

    • Katheryn Buble

    • Nic Herndon

    • Chris Childers

    • Qiaoshan Lin

    • Sudhansu Dash

    • Eric Wafula

    • Prakash Raj

    • Eliot Cline

  • UPDATE: the result is available here:
    https://github.com/tripal/tripal_dt

  • Setup: create a custom module copy of the tripal_example module

cd <drupal_sites_directory>/all/modules/

cp -r tripal/tripal_example tripal_dt

cd tripal_dt

mv tripal_example.info tripal_dt.info

mv tripal_example.install tripal_dt.install

mv tripal_example.module tripal_dt.module

mv theme/css/tripal_example.css theme/css/tripal_dt.css

mv theme/templates/tripal_example_base.tpl.php  theme/templates/tripal_dt_tree_page.tpl.php

  • Here is how your tripal_dt.info file should look like:
    name = Tripal Demo Tree

description = A tree module for Tripal.

core = 7.x

project = tripal_dt

package = Tripal Extensions

version = 7.x-2.0

dependencies[] = tripal_core

dependencies[] = tripal_views

dependencies[] = tripal_db

dependencies[] = tripal_cv

  • Open your tripal_dt.install file and only keep the function “tripal_example_requirements” and rename it into “tripal_dt_requirements”

  • Open the tripal_dt.module file

keep only the first two require() lines and change names ( the api and theme requirements)

Remove the hook_permissions implementation (we don’t need them in our case).

Keep the hook_menu implementation and rename it:

function tripal_dt_menu() {

 $items = array();

 $items['tripal_dt'] = array(

'title' => Demo Tree',

'description' => 'A nice D3JS demo tree.',

'page callback' => 'theme',

'page arguments' => array('tripal_dt_tree'),

'access callback' => TRUE,

'type' => MENU_NORMAL_ITEM,

 );

 return $items;

}

We keep the hook_theme implementation (and rename it):

function tripal_dt_theme($existing, $type, $theme, $path) {

   

 $items = array(

'tripal_dt_tree' => array(

       'template' => 'tripal_dt_tree_page',

       'variables' => array(),

       'path' => "$path/theme/templates",

),

);

 return $items;

}

And just remove other functions! :)

  • Now edit themes/tripal_dt.theme.inc and only keep one function:

function tripal_dt_preprocess_tripal_dt_tree(&$variables) {

 // Adds the appropriate JS and CSS specific to our page.

 // Note: those scripts won't be loaded on other pages!

 drupal_add_js(drupal_get_path('module', 'tripal_dt') .'/theme/js/d3.min.js');

 drupal_add_js(drupal_get_path('module', 'tripal_dt') .'/theme/js/d3.dndtree.js');

 drupal_add_css(drupal_get_path('module', 'tripal_dt') .'/theme/css/tripal_dt.css');

 $phylotree_id = 1; // our dataset phylotree_id

 // Loads phylonode records from the database.

 // Note: this process can be long/heavy so it might be a good idea to use

 // Drupal cache features and load the structure from cache if it has already

 // been generated once and saved into cache.

 $columns = array('phylonode_id', 'parent_phylonode_id', 'label');

 $values = array(

'phylotree_id' => $phylotree_id,

 );

 $options = array(

'order_by' => array(

  'phylonode_id' => 'ASC',

),

 );

 $phylonodes = chado_select_record(

'phylonode',

$columns,

$values,

$options

 );

 

 // Raw data table stuff.

 $header = array(

  t('phylonode_id'),

  t('Parent'),

  t('Name'),

 );

 $rows = array();

 

 // JSON data stuff.

 $tree_data = array(); // Store D3 tree structure.

 $node_lookup = array(); // Associate a Chado ID to a D3 node ID.

 $node_index = 1; // Used to generate D3 IDs starting from 1.

 

 // Process each node and fill the data.

 foreach ($phylonodes as $phylonode) {

// Fill raw data table.

$rows[] = array(

  $phylonode->phylonode_id,

  $phylonode->parent_phylonode_id,

  $phylonode->label,

);

   

// Generate the tree structure.

// Get current phylnode Chado ID.

$phylonode_id = $phylonode->phylonode_id;

// Fill lookup table.

$node_lookup[$phylonode_id] = $node_index;

// Store node data.

$tree_data[$node_index] = array(

  'id' => $node_index,

  'name' => $phylonode->label,

);

// Check if node has a parent and if so, add it to its parent.

if ($parent_id = $phylonode->parent_phylonode_id) {

  // Is it the first child?

  $parent_node_id = $node_lookup[$parent_id];

  if (!array_key_exists('children', $tree_data[$parent_node_id])) {

    // Yes, add a new children array to parent.

    $tree_data[$parent_node_id]['children'] = array(

      &$tree_data[$node_index]

    );

  }

  else {

    // No, add child to its siblings.

    $tree_data[$parent_node_id]['children'][] =

      &$tree_data[$node_index];

  }

}

// Next node.

++$node_index;

 }

 

 $variables['table'] = array('header' => $header, 'rows' => $rows);

 $variables['tree'] = $tree_data[1];

}

 

  • Edit theme/templates/tripal_dt_tree_page.tpl.php and fill it with:

<h2>Tree raw data</h2>

<?php

 echo theme('table', $table);

?>

<br/>

<h2>Tree structure</h2>

<pre>

<?php

 echo json_encode(

$tree,

JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES

 );

?>

</pre>

<br/>

<h2>Tree</h2>

<div id="tripal_dt-tree">

</div>

<script>

 jQuery(function() {

var tree_data = <?php print json_encode($tree); ?>;

Drupal.tripal_dt.renderD3JSTree(tree_data);

 });

</script>

Now we need some data to work on, into chado. Here is an example dataset:

INSERT INTO phylotree VALUES (1,  1, 'Testing tree', 1, NULL, 'A tree for testing');

INSERT INTO phylonode VALUES

(1, 1, NULL, 1, 14, 1, NULL, 'Musaceae', NULL),

(2, 1, 1, 2, 9, 1, NULL, 'Musa', NULL),

(3, 1, 1, 10, 13, 1, NULL, 'Ensete', NULL),

(4, 1, 2, 3, 8, 1, NULL, 'Eumusa', NULL),

(5, 1, 4, 4, 5, 1, NULL, 'acuminata', NULL),

(6, 1, 4, 6, 7, 1, NULL, 'balbisiana', NULL),

(7, 1, 3, 11, 12, 1, NULL, 'lasiocarpa', NULL)

;

This dataset represents a subpart of the banana species taxonomy:

   1#Musaceae#14

  /       °°°°°°°°°°\

2#Musa#9           10#Ensete#13

  |                   |

3#Eumusa#8    11#lasiocarpa#12

  |   °°°°°°°°°°\

4#acuminata#5  6#balbisiana#7

You need to add the 2 following JS files into tripal_dt/theme/js/:

All thoses files are available there: https://github.com/tripal/tripal_dt