Procházet zdrojové kódy

This commit adds the option to change the horizontal scale in phylotrees to either linear (default) or logarithmic, as we've found that a logarithmic scale sometimes makes phylotrees a good deal more legible.
This commit also fixes two bugs in the phylotree code where the specified colors per feature were not working, and the feature names were not linking correctly. These bugs were fixed by @almasaeed2010.

Noah Caldwell před 4 roky
rodič
revize
aa6c910082

+ 129 - 110
legacy/tripal_phylogeny/theme/js/tripal_phylogeny.js

@@ -2,129 +2,148 @@
 
 
 (function ($) {
 (function ($) {
 
 
-  var height = 0; // will be dynamically sized
+  "use strict";
 
 
-  $(document).ready( function () {
+  // Will be dynamically sized.
+  var height = 0;
 
 
-    // Callback function to determine node size.
-    var nodeSize = function(d) {
-      var size;
-      if (d.cvterm_name == "phylo_root") {
-        size = treeOptions['root_node_size']; 
-      }
-      if (d.cvterm_name == "phylo_interior") {
-        size = treeOptions['interior_node_size']; 
-      }
-      if (d.cvterm_name == "phylo_leaf") {
-        size = treeOptions['leaf_node_size']; 
-      }
-      return size;
+  // Store our function as a property of Drupal.behaviors.
+  Drupal.behaviors.TripalPhylotree = {
+    attach: function (context, settings) {
+
+      // Retrieve the data for this tree.
+      var data_url = Drupal.settings.tripal_chado.phylotree_url;
+      $.getJSON(data_url, function(treeData) {
+        phylogeny_display_data(treeData);
+        $('.phylogram-ajax-loader').hide();
+      });
     }
     }
+  }
 
 
-    // Callback function to determine the node color.
-    var organismColor = function(d) {
-      var color = null;
-      if (d.genus) {
-        color = organismColors[d.genus + ' ' + d.species];
-      }
-      if (color) { 
-        return color; 
-      }
-      else { 
-        return 'grey'; 
-      }
-    };
+  // Callback function to determine node size.
+  var phylogeny_node_size = function(d) {
+    var size;
+    var tree_options = Drupal.settings.tripal_chado.tree_options;
+    if (d.cvterm_name == "phylo_root") {
+      size = tree_options['root_node_size'];
+    }
+    if (d.cvterm_name == "phylo_interior") {
+      size = tree_options['interior_node_size'];
+    }
+    if (d.cvterm_name == "phylo_leaf") {
+      size = tree_options['leaf_node_size'];
+    }
+    return size;
+  }
 
 
-    // Callback for mouseover event on graph node d.
-    var nodeMouseOver = function(d) {
-      var el = $(this);
-      el.attr('cursor', 'pointer');
-      var circle = el.find('circle');
-      // highlight in yellow no matter if leaf or interior node
-      circle.attr('fill', 'yellow');
-      if(!d.children) {
-        // only leaf nodes have descriptive text
-        var txt = el.find('text');
-        txt.attr('font-weight', 'bold');
-      }
-    };
-    
-    // Callback for mouseout event on graph node d.
-    var nodeMouseOut = function(d) {
-      var el = $(this);
-      el.attr('cursor', 'default');
-      var circle = el.find('circle');
-      if(!d.children) {
-        // restore the color based on organism id for leaf nodes
-        circle.attr('fill', organismColor(d));
-        var txt = el.find('text');
-        txt.attr('font-weight', 'normal');
+  // Callback function to determine the node color.
+  var phylogeny_organism_color = function(d) {
+    var organism_color = Drupal.settings.tripal_chado.org_colors;
+    var color = null;
+
+    if (d.fo_genus) {
+      color = organism_color[d.fo_organism_id];
+    }
+    if (color) {
+      return color;
+    }
+    else {
+      return 'grey';
+    }
+  };
+
+  // Callback for mouseover event on graph node d.
+  var phylogeny_node_mouse_over = function(d) {
+    var el = $(this);
+    el.attr('cursor', 'pointer');
+    var circle = el.find('circle');
+    // highlight in yellow no matter if leaf or interior node
+    circle.attr('fill', 'yellow');
+    if(!d.children) {
+      // only leaf nodes have descriptive text
+      var txt = el.find('text');
+      txt.attr('font-weight', 'bold');
+    }
+  };
+
+  // Callback for mouseout event on graph node d.
+  var phylogeny_node_mouse_out = function(d) {
+    var el = $(this);
+    el.attr('cursor', 'default');
+    var circle = el.find('circle');
+    if(!d.children) {
+      // restore the color based on organism id for leaf nodes
+      circle.attr('fill', phylogeny_organism_color(d));
+      var txt = el.find('text');
+      txt.attr('font-weight', 'normal');
+    }
+    else {
+      // restore interior nodes to white
+      circle.attr('fill', 'white');
+    }
+  };
+
+  // Callback for mousedown/click event on graph node d.
+  var phylogeny_node_mouse_down = function(d) {
+    var el = $(this);
+    var title = (! d.children ) ? d.name : 'interior node ' + d.phylonode_id;
+
+    if(d.children) {
+      // interior node
+      if(d.phylonode_id) {
       }
       }
       else {
       else {
-        // restore interior nodes to white
-        circle.attr('fill', 'white');
+        // this shouldn't happen but ok
       }
       }
-    };
-    
-    // Callback for mousedown/click event on graph node d.
-    var nodeMouseDown = function(d) {
-      var el = $(this);
-      var title = (! d.children ) ? d.name : 'interior node ' + d.phylonode_id;
+    }
+    else {
+      if(d.feature_eid) {
+        window.location.href = baseurl + '/bio_data/' + d.feature_eid;
 
 
-      if(d.children) {
-        // interior node
-        if(d.phylonode_id) {
-        }
-        else {
-          // this shouldn't happen but ok
-        }
+        return;
       }
       }
-      else {
-        // If this node is not associated with a feature but it has an 
-        // organism node then this is a taxonomic node and we want to
-        // link it to the organism page.
-        if (!d.feature_id && d.organism_node_id) {
-          window.location.replace(baseurl + '/node/' + d.organism_node_id);
-        }
-        // leaf node
+      // If this node is not associated with a feature but it has an
+      // organism node then this is a taxonomic node and we want to
+      // link it to the organism page.
+      if (!d.feature_id && d.organism_nid) {
+        window.location.replace(baseurl + '/node/' + d.organism_nid);
+      }
+      if (!d.feature_id && d.organism_eid) {
+        window.location.replace(baseurl + '/bio_data/' + d.organism_eid);
       }
       }
-    };
+      // leaf node
+    }
+  };
 
 
-    // AJAX function for retrieving the tree data.
-    $.getJSON(phylotreeDataURL, function(treeData) {
-      displayData(treeData);
-      $('.phylogram-ajax-loader').hide();
+  // Creates the tree using the d3.phylogram.js library.
+  function phylogeny_display_data(treeData) {
+    var height = phylogeny_graph_height(treeData);
+    var tree_options = Drupal.settings.tripal_chado.tree_options;
+    d3.phylogram.build('#phylogram', treeData, {
+      'width' : tree_options['phylogram_width'],
+      'height' : height,
+      'fill' : phylogeny_organism_color,
+      'size' : phylogeny_node_size,
+      'nodeMouseOver' : phylogeny_node_mouse_over,
+      'nodeMouseOut' : phylogeny_node_mouse_out,
+      'nodeMouseDown' : phylogeny_node_mouse_down,
+      'skipTicks' : tree_options['skipTicks']
     });
     });
+  }
 
 
-    // Creates the tree using the d3.phylogram.js library.
-    function displayData(treeData) {
-      height = graphHeight(treeData);
-      d3.phylogram.build('#phylogram', treeData, {
-        'width' : treeOptions['phylogram_width'],
-        'height' : height,
-        'fill' : organismColor,
-        'size' : nodeSize,
-        'nodeMouseOver' : nodeMouseOver,
-        'nodeMouseOut' : nodeMouseOut,
-        'nodeMouseDown' : nodeMouseDown,
-        'skipTicks' : treeOptions['skipTicks']
-      });
-    }
-
-    /* graphHeight() generate graph height based on leaf nodes */
-    function graphHeight(data) {
-      function countLeafNodes(node) {
-        if(! node.children) {
-          return 1;
-        }
-        var ct = 0;
-        node.children.forEach( function(child) {
-          ct+= countLeafNodes(child);
-        });
-        return ct;
+  /* graphHeight() generate graph height based on leaf nodes */
+  function phylogeny_graph_height(data) {
+    function count_leaf_nodes(node) {
+      if(! node.children) {
+        return 1;
       }
       }
-      var leafNodeCt = countLeafNodes(data);
-      return 22 * leafNodeCt;
+      var ct = 0;
+      node.children.forEach( function(child) {
+        ct+= count_leaf_nodes(child);
+      });
+      return ct;
     }
     }
-  });
-})(jQuery);
+    var leafNodeCt = count_leaf_nodes(data);
+    return 22 * leafNodeCt;
+  }
+})(jQuery);

+ 58 - 33
tripal_chado/includes/tripal_chado.phylotree.inc

@@ -4,7 +4,8 @@
  *
  *
  * @param $phylotree
  * @param $phylotree
  */
  */
-function tripal_phylogeny_prepare_tree_viewer($phylotree) {
+function tripal_phylogeny_prepare_tree_viewer($phylotree)
+{
 
 
   // If the phylotree is not provided then just return;
   // If the phylotree is not provided then just return;
   if (!$phylotree) {
   if (!$phylotree) {
@@ -59,6 +60,7 @@ function tripal_phylogeny_prepare_tree_viewer($phylotree) {
         'interior_node_size' => variable_get('tripal_phylogeny_default_interior_node_size', 1),
         'interior_node_size' => variable_get('tripal_phylogeny_default_interior_node_size', 1),
         'leaf_node_size' => variable_get('tripal_phylogeny_default_leaf_node_size', 6),
         'leaf_node_size' => variable_get('tripal_phylogeny_default_leaf_node_size', 6),
         'skipTicks' => $skip_ticks,
         'skipTicks' => $skip_ticks,
+        'phylogram_scale' => variable_get('tripal_phylogeny_default_phylogram_scale', 6),
       ],
       ],
       'org_colors' => $colors,
       'org_colors' => $colors,
     ],
     ],
@@ -99,7 +101,8 @@ function tripal_phylogeny_prepare_tree_viewer($phylotree) {
  *
  *
  * @ingroup tripal_phylogeny
  * @ingroup tripal_phylogeny
  */
  */
-function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
+function tripal_phylogeny_ajax_get_tree_json($phylotree_id)
+{
 
 
   $phylotree = chado_generate_var('phylotree', ['phylotree_id' => $phylotree_id]);
   $phylotree = chado_generate_var('phylotree', ['phylotree_id' => $phylotree_id]);
 
 
@@ -135,8 +138,7 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
         LEFT OUTER JOIN [chado_organism] co       ON co.organism_id = o.organism_id
         LEFT OUTER JOIN [chado_organism] co       ON co.organism_id = o.organism_id
       WHERE n.phylotree_id = :phylotree_id
       WHERE n.phylotree_id = :phylotree_id
     ";
     ";
-  }
-  else {
+  } else {
     $sql = "
     $sql = "
       SELECT
       SELECT
         n.phylonode_id, n.parent_phylonode_id, n.label AS name, n.distance AS length,
         n.phylonode_id, n.parent_phylonode_id, n.label AS name, n.distance AS length,
@@ -165,13 +167,13 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
 
 
   if ($results) {
   if ($results) {
     while ($r = $results->fetchObject()) {
     while ($r = $results->fetchObject()) {
-      $phylonode_id = (int) $r->phylonode_id;
+      $phylonode_id = (int)$r->phylonode_id;
 
 
       // expect all nodes to have these properties
       // expect all nodes to have these properties
       $node = [
       $node = [
         'phylonode_id' => $phylonode_id,
         'phylonode_id' => $phylonode_id,
-        'parent_phylonode_id' => (int) $r->parent_phylonode_id,
-        'length' => (double) $r->length,
+        'parent_phylonode_id' => (int)$r->parent_phylonode_id,
+        'length' => (double)$r->length,
         'cvterm_name' => $r->cvterm_name,
         'cvterm_name' => $r->cvterm_name,
       ];
       ];
 
 
@@ -186,30 +188,28 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
       }
       }
       // If this node is associated with a feature then add in the details
       // If this node is associated with a feature then add in the details
       if ($r->feature_id) {
       if ($r->feature_id) {
-        $node['feature_id'] = (int) $r->feature_id;
+        $node['feature_id'] = (int)$r->feature_id;
         $node['feature_name'] = $r->feature_name;
         $node['feature_name'] = $r->feature_name;
         if (module_exists('tripal_phylogeny')) {
         if (module_exists('tripal_phylogeny')) {
-          $node['feature_nid'] = (int) $r->feature_nid;
-        }
-        else {
+          $node['feature_nid'] = (int)$r->feature_nid;
+        } else {
           $entity_id = chado_get_record_entity_by_table('feature', $r->feature_id);
           $entity_id = chado_get_record_entity_by_table('feature', $r->feature_id);
-          $node['feature_eid'] = (int) $entity_id;
+          $node['feature_eid'] = (int)$entity_id;
         }
         }
       }
       }
       // Add in the organism fields when they are available via the
       // Add in the organism fields when they are available via the
       // phylonode_organism table.
       // phylonode_organism table.
       if ($r->organism_id) {
       if ($r->organism_id) {
-        $node['organism_id'] = (int) $r->organism_id;
+        $node['organism_id'] = (int)$r->organism_id;
         $node['common_name'] = $r->common_name;
         $node['common_name'] = $r->common_name;
         $node['abbreviation'] = $r->abbreviation;
         $node['abbreviation'] = $r->abbreviation;
         $node['genus'] = $r->genus;
         $node['genus'] = $r->genus;
         $node['species'] = $r->species;
         $node['species'] = $r->species;
         if (module_exists('tripal_phylogeny')) {
         if (module_exists('tripal_phylogeny')) {
-          $node['organism_nid'] = (int) $r->organism_nid;
-        }
-        else {
+          $node['organism_nid'] = (int)$r->organism_nid;
+        } else {
           $entity_id = chado_get_record_entity_by_table('organism', $r->organism_id);
           $entity_id = chado_get_record_entity_by_table('organism', $r->organism_id);
-          $node['organism_eid'] = (int) $entity_id;
+          $node['organism_eid'] = (int)$entity_id;
         }
         }
         // If the node does not have a name but is linked to an organism
         // If the node does not have a name but is linked to an organism
         // then set the name to be that of the genus and species.
         // then set the name to be that of the genus and species.
@@ -220,17 +220,16 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
       // Add in the organism fields when they are available via the
       // Add in the organism fields when they are available via the
       // the phylonode.feature_id FK relationship.
       // the phylonode.feature_id FK relationship.
       if ($r->fo_organism_id) {
       if ($r->fo_organism_id) {
-        $node['fo_organism_id'] = (int) $r->fo_organism_id;
+        $node['fo_organism_id'] = (int)$r->fo_organism_id;
         $node['fo_common_name'] = $r->fo_common_name;
         $node['fo_common_name'] = $r->fo_common_name;
         $node['fo_abbreviation'] = $r->fo_abbreviation;
         $node['fo_abbreviation'] = $r->fo_abbreviation;
         $node['fo_genus'] = $r->fo_genus;
         $node['fo_genus'] = $r->fo_genus;
         $node['fo_species'] = $r->fo_species;
         $node['fo_species'] = $r->fo_species;
         if (module_exists('tripal_phylogeny')) {
         if (module_exists('tripal_phylogeny')) {
-          $node['fo_organism_nid'] = (int) $r->fo_organism_nid;
-        }
-        else {
+          $node['fo_organism_nid'] = (int)$r->fo_organism_nid;
+        } else {
           $entity_id = chado_get_record_entity_by_table('organism', $r->fo_organism_id);
           $entity_id = chado_get_record_entity_by_table('organism', $r->fo_organism_id);
-          $node['fo_organism_eid'] = (int) $entity_id;
+          $node['fo_organism_eid'] = (int)$entity_id;
         }
         }
       }
       }
 
 
@@ -244,8 +243,7 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
         $parent_ref = &$phylonodes[$node['parent_phylonode_id']];
         $parent_ref = &$phylonodes[$node['parent_phylonode_id']];
         // Append node refernce to children.
         // Append node refernce to children.
         $parent_ref['children'][] = &$node;
         $parent_ref['children'][] = &$node;
-      }
-      else {
+      } else {
         $root_phylonode_ref = &$node;
         $root_phylonode_ref = &$node;
       }
       }
     }
     }
@@ -262,7 +260,8 @@ function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {
  *
  *
  */
  */
 
 
-function tripal_phylogeny_admin_phylotrees_listing() {
+function tripal_phylogeny_admin_phylotrees_listing()
+{
   $output = '';
   $output = '';
 
 
   // set the breadcrumb
   // set the breadcrumb
@@ -278,8 +277,7 @@ function tripal_phylogeny_admin_phylotrees_listing() {
   $view = views_embed_view('tripal_phylogeny_admin_phylotree', 'default');
   $view = views_embed_view('tripal_phylogeny_admin_phylotree', 'default');
   if (isset($view)) {
   if (isset($view)) {
     $output .= $view;
     $output .= $view;
-  }
-  else {
+  } else {
     $output .= '<p>The Phylotree module uses primarily views to provide an '
     $output .= '<p>The Phylotree module uses primarily views to provide an '
       . 'administrative interface. Currently one or more views needed for this '
       . 'administrative interface. Currently one or more views needed for this '
       . 'administrative interface are disabled. <strong>Click each of the following links to '
       . 'administrative interface are disabled. <strong>Click each of the following links to '
@@ -297,7 +295,8 @@ function tripal_phylogeny_admin_phylotrees_listing() {
  * @param unknown $form
  * @param unknown $form
  * @param unknown $form_state
  * @param unknown $form_state
  */
  */
-function tripal_phylogeny_default_plots_form($form, &$form_state) {
+function tripal_phylogeny_default_plots_form($form, &$form_state, array $category = array())
+{
   $form = [];
   $form = [];
 
 
   $form['plot_settings'] = [
   $form['plot_settings'] = [
@@ -319,6 +318,27 @@ function tripal_phylogeny_default_plots_form($form, &$form_state) {
     '#size' => 5,
     '#size' => 5,
   ];
   ];
 
 
+  $category += array(
+    'category' => '',
+    'recipients' => '',
+    'reply' => '',
+    'weight' => 0,
+    'selected' => 0,
+    'cid' => NULL,
+  );
+  $form['plot_settings']['phylogram_scale'] = [
+    '#type' => 'select',
+    '#title' => t('Phylogram Scale'),
+    '#description' => 'Please specify the scale to use.',
+    '#default_value' => variable_get('tripal_phylogeny_default_phylogram_scale', 1),
+    '#options' => array(
+      1 => t('Linear'),
+      2 => t('Logarithmic'),
+    ),
+    '#size' => 2,
+  ];
+
+
   $form['node_settings'] = [
   $form['node_settings'] = [
     '#type' => 'fieldset',
     '#type' => 'fieldset',
     '#title' => t('Node Settings'),
     '#title' => t('Node Settings'),
@@ -447,7 +467,8 @@ function tripal_phylogeny_default_plots_form($form, &$form_state) {
  *
  *
  * @ingroup tripal_phylogeny
  * @ingroup tripal_phylogeny
  */
  */
-function tripal_phylogeny_default_plots_form_validate($form, &$form_state) {
+function tripal_phylogeny_default_plots_form_validate($form, &$form_state)
+{
 
 
 }
 }
 
 
@@ -456,7 +477,8 @@ function tripal_phylogeny_default_plots_form_validate($form, &$form_state) {
  * @param unknown $form
  * @param unknown $form
  * @param unknown $form_state
  * @param unknown $form_state
  */
  */
-function tripal_phylogeny_default_plots_form_submit($form, &$form_state) {
+function tripal_phylogeny_default_plots_form_submit($form, &$form_state)
+{
   // Rebuild this form after submission so that any changes are reflected in
   // Rebuild this form after submission so that any changes are reflected in
   // the flat tables.
   // the flat tables.
   $form_state['rebuild'] = TRUE;
   $form_state['rebuild'] = TRUE;
@@ -467,6 +489,7 @@ function tripal_phylogeny_default_plots_form_submit($form, &$form_state) {
     variable_set('tripal_phylogeny_default_root_node_size', $form_state['values']['root_node_size']);
     variable_set('tripal_phylogeny_default_root_node_size', $form_state['values']['root_node_size']);
     variable_set('tripal_phylogeny_default_interior_node_size', $form_state['values']['interior_node_size']);
     variable_set('tripal_phylogeny_default_interior_node_size', $form_state['values']['interior_node_size']);
     variable_set('tripal_phylogeny_default_leaf_node_size', $form_state['values']['leaf_node_size']);
     variable_set('tripal_phylogeny_default_leaf_node_size', $form_state['values']['leaf_node_size']);
+    variable_set('tripal_phylogeny_default_phylogram_scale', $form_state['values']['phylogram_scale']);
 
 
     $num_orgs = $form_state['values']['num_orgs'];
     $num_orgs = $form_state['values']['num_orgs'];
     variable_set("tripal_phylogeny_num_orgs", $num_orgs);
     variable_set("tripal_phylogeny_num_orgs", $num_orgs);
@@ -491,7 +514,8 @@ function tripal_phylogeny_default_plots_form_submit($form, &$form_state) {
  *
  *
  * @param unknown $variables
  * @param unknown $variables
  */
  */
-function theme_tripal_phylogeny_admin_org_color_tables($variables) {
+function theme_tripal_phylogeny_admin_org_color_tables($variables)
+{
   $fields = $variables['element'];
   $fields = $variables['element'];
   $num_orgs = $fields['num_orgs']['#value'];
   $num_orgs = $fields['num_orgs']['#value'];
   $headers = ['Organism', 'Color', ''];
   $headers = ['Organism', 'Color', ''];
@@ -524,7 +548,8 @@ function theme_tripal_phylogeny_admin_org_color_tables($variables) {
  * @param $form
  * @param $form
  * @param $form_state
  * @param $form_state
  */
  */
-function tripal_phylogeny_default_plots_form_ajax_callback($form, $form_state) {
+function tripal_phylogeny_default_plots_form_ajax_callback($form, $form_state)
+{
 
 
   return $form['node_settings']['org_table'];
   return $form['node_settings']['org_table'];
-}
+}

+ 236 - 178
tripal_chado/theme/js/d3.phylogram.js

@@ -41,7 +41,7 @@
       selector: selector of an element that will contain the SVG
       selector: selector of an element that will contain the SVG
       nodes: JS object of nodes
       nodes: JS object of nodes
     Options:
     Options:
-      width       
+      width
         Width of the vis, will attempt to set a default based on the width of
         Width of the vis, will attempt to set a default based on the width of
         the container.
         the container.
       height
       height
@@ -63,219 +63,256 @@
         Skip the tick rule.
         Skip the tick rule.
       skipBranchLengthScaling
       skipBranchLengthScaling
         Make a dendrogram instead of a phylogram.
         Make a dendrogram instead of a phylogram.
-  
+
   d3.phylogram.buildRadial(selector, nodes, options)
   d3.phylogram.buildRadial(selector, nodes, options)
     Creates a radial dendrogram.
     Creates a radial dendrogram.
-    Options: same as build, but without diagonal, skipTicks, and 
+    Options: same as build, but without diagonal, skipTicks, and
       skipBranchLengthScaling
       skipBranchLengthScaling
-  
+
   d3.phylogram.rightAngleDiagonal()
   d3.phylogram.rightAngleDiagonal()
     Similar to d3.diagonal except it create an orthogonal crook instead of a
     Similar to d3.diagonal except it create an orthogonal crook instead of a
     smooth Bezier curve.
     smooth Bezier curve.
-    
+
   d3.phylogram.radialRightAngleDiagonal()
   d3.phylogram.radialRightAngleDiagonal()
     d3.phylogram.rightAngleDiagonal for radial layouts.
     d3.phylogram.rightAngleDiagonal for radial layouts.
 */
 */
 
 
-if (!d3) { throw "d3 wasn't included!"};
-(function() {
+if (!d3) {
+  throw "d3 wasn't included!"
+}
+;
+(function () {
   d3.phylogram = {}
   d3.phylogram = {}
-  d3.phylogram.rightAngleDiagonal = function() {
-    var projection = function(d) { return [d.y, d.x]; }
-    
-    var path = function(pathData) {
-      return "M" + pathData[0] + ' ' + pathData[1] + " " + pathData[2];
+  d3.phylogram.rightAngleDiagonal = function () {
+    var projection = function (d) {
+      return [d.y, d.x];
+    }
+
+    var path = function (pathData) {
+      return "M" + pathData[0] + " " + pathData[1] + " " + pathData[2];
     }
     }
-    
+
     function diagonal(diagonalPath, i) {
     function diagonal(diagonalPath, i) {
       var source = diagonalPath.source,
       var source = diagonalPath.source,
-          target = diagonalPath.target,
-          midpointX = (source.x + target.x) / 2,
-          midpointY = (source.y + target.y) / 2,
-          pathData = [source, {x: target.x, y: source.y}, target];
+        target = diagonalPath.target,
+        midpointX = (source.x + target.x) / 2,
+        midpointY = (source.y + target.y) / 2,
+        pathData = [source, {x: target.x, y: source.y}, target];
       pathData = pathData.map(projection);
       pathData = pathData.map(projection);
-      return path(pathData)
+      return path(pathData);
     }
     }
-    
-    diagonal.projection = function(x) {
-      if (!arguments.length) return projection;
+
+    diagonal.projection = function (x) {
+      if (!arguments.length) {
+        return projection;
+      }
       projection = x;
       projection = x;
       return diagonal;
       return diagonal;
     };
     };
-    
-    diagonal.path = function(x) {
-      if (!arguments.length) return path;
+
+    diagonal.path = function (x) {
+      if (!arguments.length) {
+        return path;
+      }
       path = x;
       path = x;
       return diagonal;
       return diagonal;
     };
     };
-    
+
     return diagonal;
     return diagonal;
   }
   }
-  
-  d3.phylogram.radialRightAngleDiagonal = function() {
+
+  d3.phylogram.radialRightAngleDiagonal = function () {
     return d3.phylogram.rightAngleDiagonal()
     return d3.phylogram.rightAngleDiagonal()
-      .path(function(pathData) {
+      .path(function (pathData) {
         var src = pathData[0],
         var src = pathData[0],
-            mid = pathData[1],
-            dst = pathData[2],
-            radius = Math.sqrt(src[0]*src[0] + src[1]*src[1]),
-            srcAngle = d3.phylogram.coordinateToAngle(src, radius),
-            midAngle = d3.phylogram.coordinateToAngle(mid, radius),
-            clockwise = Math.abs(midAngle - srcAngle) > Math.PI ? midAngle <= srcAngle : midAngle > srcAngle,
-            rotation = 0,
-            largeArc = 0,
-            sweep = clockwise ? 0 : 1;
+          mid = pathData[1],
+          dst = pathData[2],
+          radius = Math.sqrt(src[0] * src[0] + src[1] * src[1]),
+          srcAngle = d3.phylogram.coordinateToAngle(src, radius),
+          midAngle = d3.phylogram.coordinateToAngle(mid, radius),
+          clockwise = Math.abs(midAngle - srcAngle) > Math.PI ? midAngle <= srcAngle : midAngle > srcAngle,
+          rotation = 0,
+          largeArc = 0,
+          sweep = clockwise ? 0 : 1;
         return 'M' + src + ' ' +
         return 'M' + src + ' ' +
-          "A" + [radius,radius] + ' ' + rotation + ' ' + largeArc+','+sweep + ' ' + mid +
+          "A" + [radius, radius] + ' ' + rotation + ' ' + largeArc + ',' + sweep + ' ' + mid +
           'L' + dst;
           'L' + dst;
       })
       })
-      .projection(function(d) {
+      .projection(function (d) {
         var r = d.y, a = (d.x - 90) / 180 * Math.PI;
         var r = d.y, a = (d.x - 90) / 180 * Math.PI;
         return [r * Math.cos(a), r * Math.sin(a)];
         return [r * Math.cos(a), r * Math.sin(a)];
-      })
+      });
   }
   }
-  
+
   // Convert XY and radius to angle of a circle centered at 0,0
   // Convert XY and radius to angle of a circle centered at 0,0
-  d3.phylogram.coordinateToAngle = function(coord, radius) {
+  d3.phylogram.coordinateToAngle = function (coord, radius) {
     var wholeAngle = 2 * Math.PI,
     var wholeAngle = 2 * Math.PI,
-        quarterAngle = wholeAngle / 4
-    
+      quarterAngle = wholeAngle / 4
+
     var coordQuad = coord[0] >= 0 ? (coord[1] >= 0 ? 1 : 2) : (coord[1] >= 0 ? 4 : 3),
     var coordQuad = coord[0] >= 0 ? (coord[1] >= 0 ? 1 : 2) : (coord[1] >= 0 ? 4 : 3),
-        coordBaseAngle = Math.abs(Math.asin(coord[1] / radius))
-    
+      coordBaseAngle = Math.abs(Math.asin(coord[1] / radius))
+
     // Since this is just based on the angle of the right triangle formed
     // Since this is just based on the angle of the right triangle formed
-    // by the coordinate and the origin, each quad will have different 
+    // by the coordinate and the origin, each quad will have different
     // offsets
     // offsets
     switch (coordQuad) {
     switch (coordQuad) {
       case 1:
       case 1:
         coordAngle = quarterAngle - coordBaseAngle
         coordAngle = quarterAngle - coordBaseAngle
-        break
+        break;
       case 2:
       case 2:
         coordAngle = quarterAngle + coordBaseAngle
         coordAngle = quarterAngle + coordBaseAngle
-        break
+        break;
       case 3:
       case 3:
-        coordAngle = 2*quarterAngle + quarterAngle - coordBaseAngle
-        break
+        coordAngle = 2 * quarterAngle + quarterAngle - coordBaseAngle
+        break;
       case 4:
       case 4:
-        coordAngle = 3*quarterAngle + coordBaseAngle
+        coordAngle = 3 * quarterAngle + coordBaseAngle
     }
     }
-    return coordAngle
+    return coordAngle;
   }
   }
 
 
-  function scaleBranchLengths(nodes, w) {
+  function scaleBranchLengths(nodes, w, options) {
     // Visit all nodes and adjust y pos width distance metric
     // Visit all nodes and adjust y pos width distance metric
-    var visitPreOrder = function(root, callback) {
+    var visitPreOrder = function (root, callback) {
       callback(root)
       callback(root)
       if (root.children) {
       if (root.children) {
-        for (var i = root.children.length - 1; i >= 0; i--){
+        for (var i = root.children.length - 1; i >= 0; i--) {
           visitPreOrder(root.children[i], callback);
           visitPreOrder(root.children[i], callback);
-        };
+        }
       }
       }
     }
     }
-    visitPreOrder(nodes[0], function(node) {
-      node.rootDist = (node.parent ? node.parent.rootDist : 0) + (node.length || 0)
+    visitPreOrder(nodes[0], function (node) {
+      node.rootDist = (node.parent ? node.parent.rootDist : 0) + (node.length || 0);
     })
     })
-    var rootDists = nodes.map(function(n) { return n.rootDist; });
-    var yscale = d3.scale.linear()
-      .domain([0, d3.max(rootDists)])
-      .range([0, w]);
-    visitPreOrder(nodes[0], function(node) {
-      node.y = yscale(node.rootDist)
+    var rootDists = nodes.map(function (n) {
+      return n.rootDist;
+    });
+    var yscale;
+    switch (parseInt(options.phylogram_scale)) {
+      case 1:
+        yscale = d3.scale.linear()
+          .domain([0, d3.max(rootDists)])
+          .range([0, w]);
+        break;
+      case 2:
+        yscale = d3.scale.log()
+          .domain([0.01, d3.max(rootDists)])
+          .range([0, w]);
+        break;
+      default: // shouldn't happen
+        break;
+    }
+    visitPreOrder(nodes[0], function (node) {
+      node.y = yscale(node.rootDist);
     })
     })
-    return yscale
+    return yscale;
   }
   }
-  
-  d3.phylogram.build = function(selector, nodes, options) {
+
+  d3.phylogram.build = function (selector, nodes, options) {
     options = options || {}
     options = options || {}
     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
-        h = options.height || d3.select(selector).style('height') || d3.select(selector).attr('height'),
-        w = parseInt(w),
-        h = parseInt(h);
-    var fill = options.fill || function(d) {
+      h = options.height || d3.select(selector).style('height') || d3.select(selector).attr('height'),
+      w = parseInt(w),
+      h = parseInt(h);
+    var fill = options.fill || function (d) {
       return 'cyan';
       return 'cyan';
     };
     };
-    var size = options.size || function(d) {
+    var size = options.size || function (d) {
       return 6;
       return 6;
     }
     }
-    var nodeMouseOver = options.nodeMouseOver || function(d) {};
-    var nodeMouseOut  = options.nodeMouseOut  || function(d) {};
-    var nodeMouseDown = options.nodeMouseDown || function(d) {};
-    
+    var nodeMouseOver = options.nodeMouseOver || function (d) {
+    };
+    var nodeMouseOut = options.nodeMouseOut || function (d) {
+    };
+    var nodeMouseDown = options.nodeMouseDown || function (d) {
+    };
+
     var tree = options.tree || d3.layout.cluster()
     var tree = options.tree || d3.layout.cluster()
       .size([h, w])
       .size([h, w])
-      .sort(function(node) { return node.children ? node.children.length : -1; })
-      .children(options.children || function(node) {
+      .sort(function (node) {
+        return node.children ? node.children.length : -1;
+      })
+      .children(options.children || function (node) {
         return node.children;
         return node.children;
       });
       });
     var diagonal = options.diagonal || d3.phylogram.rightAngleDiagonal();
     var diagonal = options.diagonal || d3.phylogram.rightAngleDiagonal();
     var vis = options.vis || d3.select(selector).append("svg:svg")
     var vis = options.vis || d3.select(selector).append("svg:svg")
-        .attr("width", w + 300)
-        .attr("height", h + 30)
-        .append("svg:g")
-        .attr("transform", "translate(20, 20)");
-    var nodes = tree(nodes);
-    
+      .attr("width", w + 300)
+      .attr("height", h + 30)
+      .append("svg:g")
+      .attr("transform", "translate(20, 20)");
+    nodes = tree(nodes);
+
     if (options.skipBranchLengthScaling) {
     if (options.skipBranchLengthScaling) {
-      var yscale = d3.scale.linear()
-        .domain([0, w])
-        .range([0, w]);
-    } 
-    else {
-      var yscale = scaleBranchLengths(nodes, w)
+      switch (options.phylogram_scale) {
+        case 1:
+          var yscale = d3.scale.linear()
+            .domain([0, d3.max(rootDists)])
+            .range([0, w]);
+        case 2:
+          var yscale = d3.scale.log()
+            .domain([0.01, d3.max(rootDists)])
+            .range([0, w]);
+      }
+
+    } else {
+      yscale = scaleBranchLengths(nodes, w, options);
     }
     }
-    
+
     if (!options.skipTicks) {
     if (!options.skipTicks) {
       vis.selectAll('line')
       vis.selectAll('line')
-          .data(yscale.ticks(10))
-          .enter().append('svg:line')
-          .attr('y1', 0)
-          .attr('y2', h)
-          .attr('x1', yscale)
-          .attr('x2', yscale)
-          .attr("stroke", "#ddd");
+        .data(yscale.ticks(10))
+        .enter().append('svg:line')
+        .attr('y1', 0)
+        .attr('y2', h)
+        .attr('x1', yscale)
+        .attr('x2', yscale)
+        .attr("stroke", "#ddd");
 
 
       vis.selectAll("text.rule")
       vis.selectAll("text.rule")
-          .data(yscale.ticks(10))
-          .enter().append("svg:text")
-          .attr("class", "rule")
-          .attr("x", yscale)
-          .attr("y", 0)
-          .attr("dy", -3)
-          .attr("text-anchor", "middle")
-          .attr('font-size', '9px')
-          .attr('fill', 'grey')
-          .text(function(d) { return Math.round(d*100) / 100; });
+        .data(yscale.ticks(10))
+        .enter().append("svg:text")
+        .attr("class", "rule")
+        .attr("x", yscale)
+        .attr("y", 0)
+        .attr("dy", -3)
+        .attr("text-anchor", "middle")
+        .attr('font-size', '9px')
+        .attr('fill', 'grey')
+        .text(function (d) {
+          return Math.round(d * 100) / 100;
+        });
     }
     }
-        
+
     var link = vis.selectAll("path.link")
     var link = vis.selectAll("path.link")
-        .data(tree.links(nodes))
-        .enter().append("svg:path")
-        .attr("class", "link")
-        .attr("d", diagonal)
-        .attr("fill", "none")
-        .attr("stroke", "#aaa")
-        .attr("stroke-width", "4px");
-        
+      .data(tree.links(nodes))
+      .enter().append("svg:path")
+      .attr("class", "link")
+      .attr("d", diagonal)
+      .attr("fill", "none")
+      .attr("stroke", "#aaa")
+      .attr("stroke-width", "4px");
+
     var node = vis.selectAll("g.node")
     var node = vis.selectAll("g.node")
-        .data(nodes)
-        .enter().append("svg:g")
-        .attr("class", function(n) {
-          if (n.children) {
-            if (n.depth == 0) {
-              return "root node"
-            } 
-            else {
-              return "inner node"
-            }
-          } 
-          else {
-            return "leaf node"
+      .data(nodes)
+      .enter().append("svg:g")
+      .attr("class", function (n) {
+        if (n.children) {
+          if (n.depth == 0) {
+            return "root node"
+          } else {
+            return "inner node"
           }
           }
-        })
-        .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
+        } else {
+          return "leaf node"
+        }
+      })
+      .attr("transform", function (d) {
+        return "translate(" + d.y + "," + d.x + ")";
+      })
 
 
-     // style the root node
-     vis.selectAll('g.root.node')
+    // style the root node
+    vis.selectAll('g.root.node')
       .append('svg:circle')
       .append('svg:circle')
       .on('click', nodeMouseDown)
       .on('click', nodeMouseDown)
       .on('mouseover', nodeMouseOver)
       .on('mouseover', nodeMouseOver)
@@ -305,16 +342,16 @@ if (!d3) { throw "d3 wasn't included!"};
       .attr('stroke', 'dimgrey')
       .attr('stroke', 'dimgrey')
       .attr('stroke-width', '2px')
       .attr('stroke-width', '2px')
       .attr('fill', 'white');
       .attr('fill', 'white');
-    
+
     if (!options.skipLabels) {
     if (!options.skipLabels) {
       vis.selectAll('g.inner.node')
       vis.selectAll('g.inner.node')
         .append("svg:text")
         .append("svg:text")
-          .attr("dx", -6)
-          .attr("dy", -6)
-          .attr("text-anchor", 'end')
-          .attr('font-size', '9px')
-          .attr('fill', 'black')
-        //.text(function(d) { return d.length.toFixed(4); }); // hide length
+        .attr("dx", -6)
+        .attr("dy", -6)
+        .attr("text-anchor", 'end')
+        .attr('font-size', '9px')
+        .attr('fill', 'black')
+      //.text(function(d) { return d.length.toFixed(4); }); // hide length
 
 
       vis.selectAll('g.leaf.node').append("svg:text")
       vis.selectAll('g.leaf.node').append("svg:text")
         .attr("dx", 8)
         .attr("dx", 8)
@@ -323,80 +360,101 @@ if (!d3) { throw "d3 wasn't included!"};
         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
         .attr('font-size', '10px')
         .attr('font-size', '10px')
         .attr('fill', 'black')
         .attr('fill', 'black')
-        .text(function(d) {
+        .text(function (d) {
           // return d.name + ' (' + d.length.toFixed(4) + ')'; // hide length
           // return d.name + ' (' + d.length.toFixed(4) + ')'; // hide length
           return d.name;
           return d.name;
-         });
+        });
     }
     }
     return {tree: tree, vis: vis}
     return {tree: tree, vis: vis}
   }
   }
-  
-  d3.phylogram.buildRadial = function(selector, nodes, options) {
+
+  d3.phylogram.buildRadial = function (selector, nodes, options) {
     options = options || {};
     options = options || {};
-    
-    var fill = options.fill || function(d) {
+
+    var fill = options.fill || function (d) {
       return 'cyan';
       return 'cyan';
     };
     };
-    var size = options.size || function(d) {
+    var size = options.size || function (d) {
       return 6;
       return 6;
     }
     }
-    var nodeMouseOver = options.nodeMouseOver || function(d) {};
-    var nodeMouseOut = options.nodeMouseOut || function(d) {};
-    var nodeMouseDown = options.nodeMouseDown || function(d) {};
-    
+    var nodeMouseOver = options.nodeMouseOver || function (d) {
+    };
+    var nodeMouseOut = options.nodeMouseOut || function (d) {
+    };
+    var nodeMouseDown = options.nodeMouseDown || function (d) {
+    };
+
     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
-        r = w / 2,
-        labelWidth = options.skipLabels ? 10 : options.labelWidth || 120;
-    
+      r = w / 2,
+      labelWidth = options.skipLabels ? 10 : options.labelWidth || 120;
+
     var vis = d3.select(selector).append("svg:svg")
     var vis = d3.select(selector).append("svg:svg")
-        .attr("width", r * 2)
-        .attr("height", r * 2)
-        .append("svg:g")
-        .attr("transform", "translate(" + r + "," + r + ")");
-        
+      .attr("width", r * 2)
+      .attr("height", r * 2)
+      .append("svg:g")
+      .attr("transform", "translate(" + r + "," + r + ")");
+
     var tree = d3.layout.tree()
     var tree = d3.layout.tree()
       .size([360, r - labelWidth])
       .size([360, r - labelWidth])
-      .sort(function(node) { return node.children ? node.children.length : -1; })
-      .children(options.children || function(node) {
+      .sort(function (node) {
+        return node.children ? node.children.length : -1;
+      })
+      .children(options.children || function (node) {
         return node.children;
         return node.children;
       })
       })
-      .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
+      .separation(function (a, b) {
+        return (a.parent == b.parent ? 1 : 2) / a.depth;
+      });
 
 
     var phylogram = d3.phylogram.build(selector, nodes, {
     var phylogram = d3.phylogram.build(selector, nodes, {
       vis: vis,
       vis: vis,
       tree: tree,
       tree: tree,
-      fill : fill,
+      fill: fill,
       size: size,
       size: size,
-      nodeMouseOver : nodeMouseOver,
-      nodeMouseOut : nodeMouseOut,
-      nodeMouseDown : nodeMouseDown,
+      nodeMouseOver: nodeMouseOver,
+      nodeMouseOut: nodeMouseOut,
+      nodeMouseDown: nodeMouseDown,
       skipBranchLengthScaling: true,
       skipBranchLengthScaling: true,
       skipTicks: true,
       skipTicks: true,
       skipLabels: options.skipLabels,
       skipLabels: options.skipLabels,
       diagonal: d3.phylogram.radialRightAngleDiagonal()
       diagonal: d3.phylogram.radialRightAngleDiagonal()
     })
     })
     vis.selectAll('g.node')
     vis.selectAll('g.node')
-      .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
-    
+      .attr("transform", function (d) {
+        return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
+      })
+
     if (!options.skipLabels) {
     if (!options.skipLabels) {
       vis.selectAll('g.leaf.node text')
       vis.selectAll('g.leaf.node text')
-        .attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
+        .attr("dx", function (d) {
+          return d.x < 180 ? 8 : -8;
+        })
         .attr("dy", ".31em")
         .attr("dy", ".31em")
-        .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
-        .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
+        .attr("text-anchor", function (d) {
+          return d.x < 180 ? "start" : "end";
+        })
+        .attr("transform", function (d) {
+          return d.x < 180 ? null : "rotate(180)";
+        })
         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
         .attr('font-size', '10px')
         .attr('font-size', '10px')
         .attr('fill', 'black')
         .attr('fill', 'black')
-        .text(function(d) {
+        .text(function (d) {
           return d.name;
           return d.name;
         });
         });
 
 
       vis.selectAll('g.inner.node text')
       vis.selectAll('g.inner.node text')
-        .attr("dx", function(d) { return d.x < 180 ? -6 : 6; })
-        .attr("text-anchor", function(d) { return d.x < 180 ? "end" : "start"; })
-        .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; });
+        .attr("dx", function (d) {
+          return d.x < 180 ? -6 : 6;
+        })
+        .attr("text-anchor", function (d) {
+          return d.x < 180 ? "end" : "start";
+        })
+        .attr("transform", function (d) {
+          return d.x < 180 ? null : "rotate(180)";
+        });
     }
     }
-    
+
     return {tree: tree, vis: vis}
     return {tree: tree, vis: vis}
   }
   }
 }());
 }());

+ 23 - 16
tripal_chado/theme/js/tripal_phylogeny.js

@@ -1,16 +1,16 @@
 /* phylotree d3js graphs */
 /* phylotree d3js graphs */
 
 
 (function ($) {
 (function ($) {
-    
+
   "use strict";
   "use strict";
 
 
   // Will be dynamically sized.
   // Will be dynamically sized.
-  var height = 0; 
+  var height = 0;
 
 
   // Store our function as a property of Drupal.behaviors.
   // Store our function as a property of Drupal.behaviors.
   Drupal.behaviors.TripalPhylotree = {
   Drupal.behaviors.TripalPhylotree = {
     attach: function (context, settings) {
     attach: function (context, settings) {
-      
+
       // Retrieve the data for this tree.
       // Retrieve the data for this tree.
       var data_url = Drupal.settings.tripal_chado.phylotree_url;
       var data_url = Drupal.settings.tripal_chado.phylotree_url;
       $.getJSON(data_url, function(treeData) {
       $.getJSON(data_url, function(treeData) {
@@ -25,13 +25,13 @@
     var size;
     var size;
     var tree_options = Drupal.settings.tripal_chado.tree_options;
     var tree_options = Drupal.settings.tripal_chado.tree_options;
     if (d.cvterm_name == "phylo_root") {
     if (d.cvterm_name == "phylo_root") {
-      size = tree_options['root_node_size']; 
+      size = tree_options['root_node_size'];
     }
     }
     if (d.cvterm_name == "phylo_interior") {
     if (d.cvterm_name == "phylo_interior") {
-      size = tree_options['interior_node_size']; 
+      size = tree_options['interior_node_size'];
     }
     }
     if (d.cvterm_name == "phylo_leaf") {
     if (d.cvterm_name == "phylo_leaf") {
-      size = tree_options['leaf_node_size']; 
+      size = tree_options['leaf_node_size'];
     }
     }
     return size;
     return size;
   }
   }
@@ -40,14 +40,15 @@
   var phylogeny_organism_color = function(d) {
   var phylogeny_organism_color = function(d) {
     var organism_color = Drupal.settings.tripal_chado.org_colors;
     var organism_color = Drupal.settings.tripal_chado.org_colors;
     var color = null;
     var color = null;
-    if (d.genus) {
-      color = organism_color[d.organism_id];
+
+    if (d.fo_genus) {
+      color = organism_color[d.fo_organism_id];
     }
     }
-    if (color) { 
-      return color; 
+    if (color) {
+      return color;
     }
     }
-    else { 
-      return 'grey'; 
+    else {
+      return 'grey';
     }
     }
   };
   };
 
 
@@ -64,7 +65,7 @@
       txt.attr('font-weight', 'bold');
       txt.attr('font-weight', 'bold');
     }
     }
   };
   };
-  
+
   // Callback for mouseout event on graph node d.
   // Callback for mouseout event on graph node d.
   var phylogeny_node_mouse_out = function(d) {
   var phylogeny_node_mouse_out = function(d) {
     var el = $(this);
     var el = $(this);
@@ -81,7 +82,7 @@
       circle.attr('fill', 'white');
       circle.attr('fill', 'white');
     }
     }
   };
   };
-  
+
   // Callback for mousedown/click event on graph node d.
   // Callback for mousedown/click event on graph node d.
   var phylogeny_node_mouse_down = function(d) {
   var phylogeny_node_mouse_down = function(d) {
     var el = $(this);
     var el = $(this);
@@ -96,7 +97,12 @@
       }
       }
     }
     }
     else {
     else {
-      // If this node is not associated with a feature but it has an 
+      if(d.feature_eid) {
+        window.location.href = baseurl + '/bio_data/' + d.feature_eid;
+
+        return;
+      }
+      // If this node is not associated with a feature but it has an
       // organism node then this is a taxonomic node and we want to
       // organism node then this is a taxonomic node and we want to
       // link it to the organism page.
       // link it to the organism page.
       if (!d.feature_id && d.organism_nid) {
       if (!d.feature_id && d.organism_nid) {
@@ -121,7 +127,8 @@
       'nodeMouseOver' : phylogeny_node_mouse_over,
       'nodeMouseOver' : phylogeny_node_mouse_over,
       'nodeMouseOut' : phylogeny_node_mouse_out,
       'nodeMouseOut' : phylogeny_node_mouse_out,
       'nodeMouseDown' : phylogeny_node_mouse_down,
       'nodeMouseDown' : phylogeny_node_mouse_down,
-      'skipTicks' : tree_options['skipTicks']
+      'skipTicks' : tree_options['skipTicks'],
+      'phylogram_scale' : tree_options['phylogram_scale']
     });
     });
   }
   }