Thursday, February 19, 2009

Label Name Interception

This week I've gotten my hands dirty sifting through lots of code to find both the parser and renderer portions of PhyloWidget. 

The parser reads in the newick strings, and it is found in org.phylowidget.tree.TreeIO.java


public static RootedTree parseNewickString(RootedTree tree, String s)


parses through all the notation, handles determining the different levels of the tree and the parent-child relationships. 

When it's created a string of text it considers the label, it calls:


PhyloNode curNode = newNode(tree, curLabel, nhx, poorMans);



static PhyloNode newNode(RootedTree t, String s, boolean useNhx, boolean poorMan)


...deals with NHX annotation stuff, then...


s = parseNexusLabel(s);


(removes single quotes and replaces underscores with spaces)


t.addVertex(v);

t.setLabel(v, s);


(self explanatory)


So that was pretty exciting, because it allowed me to understand how labels are created and stored in tree nodes, which will be useful since I plan to be able to intercept those labels before render time and change them. In practice, the idea is to display common names in place of scientific names for the organisms in the tree. 


Then I went on to find the renderer. The class LabelRender is found inside NodeRenderer.java. In the method render(), we have


canvas.text(tree.getLabel(n), offX - curTextSize / 3 - s, offY - s - curTextSize / 3);



n is a PhyloNode and tree is a RootedTree so getLabel(vertex) is in RootedTree.java

that calls

vertex.getLabel() which is in PhyloNode.java (extends CachedVertex which extends DefaultVertex)


It is at this point that I intercept the label and change the return value so that the rendered label name is different than the stored one. I created a wrapper class for HashMap called NameLookup, which for testing purposes just stores mappings from each capital letter of the alphabet to the corresponding number, from 1 to 26. 


I created a NameLookup object called map in 

PhyloNode.java and updated the getLabel() method to look up the value in the map and return the resulting string (in this case a number). Any label that is mapped to null in the NameLookup map is changed to the string "Hi Val". The replacement label string gets passed along all the way back to the render. 


For the tree:((A,B),(C,D),(E,F,G,H,'*'),I,J); we end up with the following image

Another way I can do this is store the common names as NHX annotations on the tree, so that I don't have to constantly keep looking up the same names for each update render. I don't know much about NHX, but I'll figure it out if we decide that's the best way. Alternatively, I can just make a "common label" variable in PhyloNode objects and only do the lookup once, when the node is constructed. 

In other news, Val is working on getting me access to image websites so that I can integrate images of the organisms in to the display options. Gotta learn how to interact with web-based applications from within Java, but I took at look at some of the URL and HTML files in the API and it doesn't look too painful. 

No comments: