X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=forester%2Fjava%2Fsrc%2Forg%2Fforester%2Fphylogeny%2FPhylogenyNode.java;h=819ba7a6b21a62aa805a22afed295f7b1f7da972;hb=7d44b232d0b61c02ef01d96d3db1d68744015bd7;hp=5ef3b5fff544d8ed96d4f5c8042fad57b673abca;hpb=9e7512a2c885b4f1e58e310225235087f5ea3738;p=jalview.git diff --git a/forester/java/src/org/forester/phylogeny/PhylogenyNode.java b/forester/java/src/org/forester/phylogeny/PhylogenyNode.java index 5ef3b5f..819ba7a 100644 --- a/forester/java/src/org/forester/phylogeny/PhylogenyNode.java +++ b/forester/java/src/org/forester/phylogeny/PhylogenyNode.java @@ -27,33 +27,38 @@ package org.forester.phylogeny; -import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.forester.archaeopteryx.Archaeopteryx; import org.forester.io.parsers.nhx.NHXFormatException; import org.forester.io.parsers.nhx.NHXParser; +import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException; +import org.forester.io.parsers.phyloxml.PhyloXmlUtil; import org.forester.phylogeny.data.BranchData; +import org.forester.phylogeny.data.Confidence; import org.forester.phylogeny.data.NodeData; -import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory; -import org.forester.phylogeny.factories.PhylogenyFactory; -import org.forester.phylogeny.iterators.ChildNodeIteratorForward; -import org.forester.phylogeny.iterators.PhylogenyNodeIterator; +import org.forester.phylogeny.data.PhylogenyDataUtil; import org.forester.phylogeny.iterators.PreorderTreeIterator; import org.forester.util.ForesterUtil; -public class PhylogenyNode implements PhylogenyNodeI, Comparable { +/** + * Warning. Implementation of method 'compareTo' only looks at + * node name. Thus, use of this class in SortedSets might lead + * to unexpected behavior. + * + */ +public final class PhylogenyNode implements Comparable { - /** Value of -99.0 is used as default value. */ - public final static double DISTANCE_DEFAULT = -1024.0; + public enum NH_CONVERSION_SUPPORT_VALUE_STYLE { + NONE, IN_SQUARE_BRACKETS, AS_INTERNAL_NODE_NAMES; + } private static int _node_count = 0; private byte _indicator; private int _id; private int _sum_ext_nodes; private float _x; private float _y; - private double _distance_parent; + private double _distance_parent = PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT; private boolean _collapse; private PhylogenyNode _parent; private PhylogenyNode _link; @@ -67,12 +72,18 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * Default constructor for PhylogenyNode. */ public PhylogenyNode() { - init(); + // init(); setId( PhylogenyNode.getNodeCount() ); PhylogenyNode.increaseNodeCount(); setSumExtNodes( 1 ); // For ext node, this number is 1 (not 0!!) } + public void removeConnections() { + _parent = null; + _link = null; + _descendants = null; + } + /** * Adds PhylogenyNode n to the list of child nodes and sets the _parent of n * to this. @@ -80,9 +91,8 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * @param n * the PhylogenyNode to add */ - @Override - final public void addAsChild( final PhylogenyNodeI node ) { - final PhylogenyNode n = ( PhylogenyNode ) node; + final public void addAsChild( final PhylogenyNode node ) { + final PhylogenyNode n = node; addChildNode( n ); n.setParent( this ); } @@ -100,6 +110,7 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable } @Override + // this is poor, as it only compares on names! final public int compareTo( final PhylogenyNode o ) { final PhylogenyNode n = o; if ( ( getName() == null ) || ( n.getName() == null ) ) { @@ -190,12 +201,12 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable return ( this_data.getTaxonomy().isEqual( other_data.getTaxonomy() ) && this_data.getSequence() .isEqual( other_data.getSequence() ) ); } - else if ( this_data.isHasSequence() && other_data.isHasSequence() ) { - return ( this_data.getSequence().isEqual( other_data.getSequence() ) ); - } else if ( this_data.isHasTaxonomy() && other_data.isHasTaxonomy() ) { return ( this_data.getTaxonomy().isEqual( other_data.getTaxonomy() ) ); } + else if ( this_data.isHasSequence() && other_data.isHasSequence() ) { + return ( this_data.getSequence().isEqual( other_data.getSequence() ) ); + } else if ( getName().length() > 0 ) { // Node name is not empty, and equal. return true; @@ -272,7 +283,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * @throws IllegalArgumentException * if n is out of bounds */ - @Override final public PhylogenyNode getChildNode( final int i ) { if ( isExternal() ) { throw new UnsupportedOperationException( "attempt to get the child node of an external node." ); @@ -337,6 +347,9 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable } final public List getDescendants() { + if ( _descendants == null ) { + _descendants = new ArrayList(); + } return _descendants; } @@ -344,7 +357,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * Returns the length of the branch leading to the _parent of this * PhylogenyNode (double). */ - @Override final public double getDistanceToParent() { return _distance_parent; } @@ -420,7 +432,23 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable if ( isInternal() && !isCollapse() ) { throw new UnsupportedOperationException( "attempt to get next external node of an uncollapsed internal node" ); } - else if ( isLastExternalNode() ) { + if ( isRoot() ) { + return null; + } + if ( getParent().isCollapse() ) { + throw new UnsupportedOperationException( "attempt to get next external node of node with a collapsed parent" ); + } + // This checks if last node. + PhylogenyNode n = this; + boolean last = true; + while ( !n.isRoot() ) { + if ( !n.isLastChildNode() ) { + last = false; + break; + } + n = n.getParent(); + } + if ( last ) { return null; } int index = getChildNodeIndex(); @@ -431,148 +459,17 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable .isLastChildNode() ) ) { index = current_node.getChildNodeIndex(); previous_node = current_node; - System.out.println(" " + previous_node.getName()); current_node = current_node.getParent(); } - // if ( !current_node.isCollapse() ) { - current_node = current_node.getChildNode( index + 1 ); - //} + if ( index < ( current_node.getNumberOfDescendants() - 1 ) ) { + current_node = current_node.getChildNode( index + 1 ); + } while ( current_node.isInternal() && !current_node.isCollapse() ) { current_node = current_node.getFirstChildNode(); } return current_node; } - - public static void main( final String[] args ) { - try { - final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); - PhylogenyNode n; - List ext = new ArrayList(); -// final StringBuffer sb0 = new StringBuffer( -// "((a,b)ab,(((c,d)cd,e)cde,(f,(g,h))fgh)cdefgh)abcdefgh" ); -// final Phylogeny t0 = factory.create( sb0, new NHXParser() )[ 0 ]; -// -// t0.getNode( "cd" ).setCollapse( true ); -// t0.getNode( "cde" ).setCollapse( true ); - // n = t0.getFirstExternalNode(); - -// while ( n != null ) { -// System.out.println( n.getName() ); -// ext.add( n ); -// n = n.getNextExternalNodeWhileTakingIntoAccountCollapsedNodes(); -// } -// -// // Archaeopteryx.createApplication( t ); -// if ( !ext.get( 0 ).getName().equals( "a" ) ) { -// System.out.println( "0 fail" ); -// } -// if ( !ext.get( 1 ).getName().equals( "b" ) ) { -// System.out.println( "1 fail" ); -// } -// if ( !ext.get( 2 ).getName().equals( "cde" ) ) { -// System.out.println( "2 fail" ); -// } -// if ( !ext.get( 3 ).getName().equals( "f" ) ) { -// System.out.println( "3 fail" ); -// } -// if ( !ext.get( 4 ).getName().equals( "g" ) ) { -// System.out.println( "4 fail" ); -// } -// if ( !ext.get( 5 ).getName().equals( "h" ) ) { -// System.out.println( "5 fail" ); -// } - // if ( !ext.get( 6 ).getName().equals( "a" ) ) { - // System.out.println( "6 fail" ); - // } - // if ( !ext.get( 7 ).getName().equals( "a" ) ) { - // System.out.println( "7 fail" ); - // } - - - final StringBuffer sb1 = new StringBuffer( - "((a,b)ab,(((c,d)cd,e)cde,(f,(g,h))fgh)cdefgh)abcdefgh" ); - final Phylogeny t1 = factory.create( sb1, new NHXParser() )[ 0 ]; - - t1.getNode( "ab" ).setCollapse( true ); - t1.getNode( "cd" ).setCollapse( true ); - t1.getNode( "cde" ).setCollapse( true ); - // n = t1.getFirstExternalNode(); - n = t1.getNode( "ab" ); - ext = new ArrayList(); - while ( n != null ) { - System.out.println( n.getName() ); - ext.add( n ); - n = n.getNextExternalNodeWhileTakingIntoAccountCollapsedNodes(); - } - - // Archaeopteryx.createApplication( t1 ); - if ( !ext.get( 0 ).getName().equals( "ab" ) ) { - System.out.println( "0 fail" ); - } - - if ( !ext.get( 1 ).getName().equals( "cde" ) ) { - System.out.println( "1 fail" ); - } - if ( !ext.get( 2 ).getName().equals( "f" ) ) { - System.out.println( "2 fail" ); - } - if ( !ext.get( 3 ).getName().equals( "g" ) ) { - System.out.println( "3 fail" ); - } - if ( !ext.get( 4 ).getName().equals( "h" ) ) { - System.out.println( "4 fail" ); - } - - // - // - final StringBuffer sb2 = new StringBuffer( - "((a,b)ab,(((c,d)cd,e)cde,(f,(g,h)gh)fgh)cdefgh)abcdefgh" ); - final Phylogeny t2 = factory.create( sb2, new NHXParser() )[ 0 ]; - - t2.getNode( "ab" ).setCollapse( true ); - t2.getNode( "cd" ).setCollapse( true ); - t2.getNode( "cde" ).setCollapse( true ); - t2.getNode( "c" ).setCollapse( true ); - t2.getNode( "d" ).setCollapse( true ); - t2.getNode( "e" ).setCollapse( true ); - t2.getNode( "gh" ).setCollapse( true ); - // t2.getNode( "h" ).setCollapse( true ); - // n = t1.getFirstExternalNode(); - n = t2.getNode( "ab" ); - ext = new ArrayList(); - while ( n != null ) { - System.out.println( n.getName() ); - ext.add( n ); - n = n.getNextExternalNodeWhileTakingIntoAccountCollapsedNodes(); - } - - // Archaeopteryx.createApplication( t1 ); - if ( !ext.get( 0 ).getName().equals( "ab" ) ) { - System.out.println( "0 fail" ); - } - - if ( !ext.get( 1 ).getName().equals( "cde" ) ) { - System.out.println( "1 fail" ); - } - if ( !ext.get( 2 ).getName().equals( "f" ) ) { - System.out.println( "2 fail" ); - } - if ( !ext.get( 3 ).getName().equals( "g" ) ) { - System.out.println( "3 fail" ); - } - if ( !ext.get( 4 ).getName().equals( "h" ) ) { - System.out.println( "4 fail" ); - } - - - } - catch ( IOException e ) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - + public final NodeData getNodeData() { if ( _node_data == null ) { _node_data = new NodeData(); @@ -590,20 +487,22 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable /** * Returns the ID (int) of this PhylogenyNode. */ - @Override final public int getId() { return _id; } - /** - * Returns the name of this node. - */ - @Override final public String getName() { return getNodeData().getNodeName(); } + final public List getAllDescendants() { + return _descendants; + } + final public int getNumberOfDescendants() { + if ( _descendants == null ) { + return 0; + } return _descendants.size(); } @@ -695,13 +594,12 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable return result; } - final private void init() { - _descendants = new ArrayList(); - _parent = null; - _id = 0; - initializeData(); - } - + // final private void init() { + //_descendants = new ArrayList(); + // _parent = null; //TODO not needed? + // _id = 0; //TODO not needed? + //initializeData(); //TODO not needed? + //} /** * Deletes data of this PhylogenyNode. Links to the other Nodes in the * Phylogeny, the ID and the sum of external nodes are NOT deleted. Field @@ -709,18 +607,17 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * * @see #getLink() (Last modified: 12/20/03) */ - final public void initializeData() { - _indicator = 0; - _x = 0; - _y = 0; - //_node_name = ""; - _distance_parent = PhylogenyNode.DISTANCE_DEFAULT; - _collapse = false; - _link = null; - _branch_data = null; - _node_data = null; - } - + // final private void initializeData() { + // _indicator = 0; + // _x = 0; + // _y = 0; + // //_node_name = ""; + // _distance_parent = PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT; + // _collapse = false; + // _link = null; + // _branch_data = null; + // _node_data = null; + // } /** * Returns whether this PhylogenyNode should be drawn as collapsed. */ @@ -742,6 +639,9 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * @return true if this PhylogenyNode is external, false otherwise */ final public boolean isExternal() { + if ( _descendants == null ) { + return true; + } return ( getNumberOfDescendants() < 1 ); } @@ -833,6 +733,28 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable return true; } + public final int calculateDepth() { + PhylogenyNode n = this; + int steps = 0; + while ( n._parent != null ) { + steps++; + n = n._parent; + } + return steps; + } + + public final double calculateDistanceToRoot() { + PhylogenyNode n = this; + double d = 0.0; + while ( n._parent != null ) { + if ( n._distance_parent > 0.0 ) { + d += n._distance_parent; + } + n = n._parent; + } + return d; + } + /** * Checks whether this PhylogenyNode is a root. * @@ -847,13 +769,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable } // --------------------------------------------------------- - // Iterator - // --------------------------------------------------------- - final public PhylogenyNodeIterator iterateChildNodesForward() { - return new ChildNodeIteratorForward( this ); - } - - // --------------------------------------------------------- // Basic printing // --------------------------------------------------------- /** @@ -943,7 +858,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable * Sets the length of the branch leading to the _parent of this * PhylogenyNode to double d. */ - @Override final public void setDistanceToParent( final double d ) { _distance_parent = d; } @@ -980,7 +894,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable /** * Sets the name of this node. */ - @Override final public void setName( final String node_name ) { getNodeData().setNodeName( node_name ); } @@ -1000,7 +913,6 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable /** * Sets the _parent PhylogenyNode of this PhylogenyNode to n. */ - @Override final public void setParent( final PhylogenyNode n ) { _parent = n; } @@ -1042,10 +954,20 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable // --------------------------------------------------------- // Writing of Nodes to Strings // --------------------------------------------------------- - final public String toNewHampshire( final boolean simple_nh, final boolean write_distance_to_parent ) { + final public String toNewHampshire( final boolean simple_nh, + final boolean write_distance_to_parent, + final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) { final StringBuilder sb = new StringBuilder(); String data = ""; - if ( !ForesterUtil.isEmpty( getName() ) ) { + if ( ( svs == NH_CONVERSION_SUPPORT_VALUE_STYLE.AS_INTERNAL_NODE_NAMES ) && !isExternal() ) { + if ( getBranchData().isHasConfidences() + && ( getBranchData().getConfidence( 0 ).getValue() != Confidence.CONFIDENCE_DEFAULT_VALUE ) ) { + data = Confidence.FORMATTER.format( ForesterUtil + .round( getBranchData().getConfidence( 0 ).getValue(), + PhyloXmlUtil.ROUNDING_DIGITS_FOR_PHYLOXML_DOUBLE_OUTPUT ) ); + } + } + else if ( !ForesterUtil.isEmpty( getName() ) ) { data = getName(); } else if ( getNodeData().isHasTaxonomy() ) { @@ -1081,14 +1003,40 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable sb.append( data ); } } - if ( ( getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) && write_distance_to_parent ) { + if ( write_distance_to_parent && ( getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) ) { sb.append( ":" ); sb.append( getDistanceToParent() ); } + if ( ( svs == NH_CONVERSION_SUPPORT_VALUE_STYLE.IN_SQUARE_BRACKETS ) && !isExternal() + && getBranchData().isHasConfidences() + && ( getBranchData().getConfidence( 0 ).getValue() != Confidence.CONFIDENCE_DEFAULT_VALUE ) ) { + sb.append( "[" ); + sb.append( Confidence.FORMATTER.format( ForesterUtil + .round( getBranchData().getConfidence( 0 ).getValue(), + PhyloXmlUtil.ROUNDING_DIGITS_FOR_PHYLOXML_DOUBLE_OUTPUT ) ) ); + sb.append( "]" ); + } return sb.toString(); } /** + * Swaps the the two childern of a PhylogenyNode node of this Phylogeny. + */ + public final void swapChildren() throws RuntimeException { + if ( isExternal() ) { + throw new RuntimeException( "attempt to swap descendants of external node" ); + } + if ( getNumberOfDescendants() != 2 ) { + throw new RuntimeException( "attempt to swap descendants of node with " + getNumberOfDescendants() + + " descendants" ); + } + final PhylogenyNode a = getChildNode( 0 ); + final PhylogenyNode b = getChildNode( 1 ); + setChildNode( 0, b ); + setChildNode( 1, a ); + } + + /** * Converts this PhylogenyNode to a New Hampshire X (NHX) String * representation. */ @@ -1106,7 +1054,7 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable sb.append( name ); } } - if ( getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) { + if ( getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) { sb.append( ":" ); sb.append( getDistanceToParent() ); } @@ -1127,14 +1075,44 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable @Override final public String toString() { final StringBuilder sb = new StringBuilder(); - if ( !ForesterUtil.isEmpty( getName() ) ) { + if ( getNodeData().isHasTaxonomy() ) { + if ( !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getScientificName() ) ) { + sb.append( getNodeData().getTaxonomy().getScientificName() ); + sb.append( " " ); + } + else if ( ( sb.length() <= 1 ) && !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getTaxonomyCode() ) ) { + sb.append( getNodeData().getTaxonomy().getTaxonomyCode() ); + sb.append( " " ); + } + else if ( getNodeData().getTaxonomy().getIdentifier() != null ) { + sb.append( getNodeData().getTaxonomy().getIdentifier().toString() ); + sb.append( " " ); + } + } + if ( getNodeData().isHasSequence() ) { + if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getName() ) ) { + sb.append( getNodeData().getSequence().getName() ); + sb.append( " " ); + } + if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getSymbol() ) ) { + sb.append( getNodeData().getSequence().getSymbol() ); + sb.append( " " ); + } + if ( getNodeData().getSequence().getAccession() != null ) { + sb.append( getNodeData().getSequence().getAccession().toString() ); + sb.append( " " ); + } + } + if ( ( sb.length() <= 1 ) && !ForesterUtil.isEmpty( getName() ) ) { sb.append( getName() ); sb.append( " " ); } - sb.append( "[" ); - sb.append( getId() ); - sb.append( "]" ); - return sb.toString(); + if ( sb.length() <= 1 ) { + sb.append( "[" ); + sb.append( getId() ); + sb.append( "]" ); + } + return sb.toString().trim(); } /** @@ -1167,27 +1145,28 @@ public class PhylogenyNode implements PhylogenyNodeI, Comparable PhylogenyNode._node_count = i; } - public static PhylogenyNode createInstanceFromNhxString( final String nhx ) throws NHXFormatException { - return new PhylogenyNode( nhx, ForesterUtil.TAXONOMY_EXTRACTION.NO, false ); + public static PhylogenyNode createInstanceFromNhxString( final String nhx ) throws NHXFormatException, + PhyloXmlDataFormatException { + return new PhylogenyNode( nhx, NHXParser.TAXONOMY_EXTRACTION.NO, false ); } public static PhylogenyNode createInstanceFromNhxString( final String nhx, - final ForesterUtil.TAXONOMY_EXTRACTION taxonomy_extraction ) - throws NHXFormatException { + final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction ) + throws NHXFormatException, PhyloXmlDataFormatException { return new PhylogenyNode( nhx, taxonomy_extraction, false ); } public static PhylogenyNode createInstanceFromNhxString( final String nhx, - final ForesterUtil.TAXONOMY_EXTRACTION taxonomy_extraction, + final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction, final boolean replace_underscores ) - throws NHXFormatException { + throws NHXFormatException, PhyloXmlDataFormatException { return new PhylogenyNode( nhx, taxonomy_extraction, replace_underscores ); } private PhylogenyNode( final String nhx, - final ForesterUtil.TAXONOMY_EXTRACTION taxonomy_extraction, - final boolean replace_underscores ) throws NHXFormatException { - init(); + final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction, + final boolean replace_underscores ) throws NHXFormatException, PhyloXmlDataFormatException { + // init(); NHXParser.parseNHX( nhx, this, taxonomy_extraction, replace_underscores ); setId( PhylogenyNode.getNodeCount() ); PhylogenyNode.increaseNodeCount();