2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // Copyright (C) 2000-2001 Washington University School of Medicine
8 // and Howard Hughes Medical Institute
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 // Contact: phylosoft @ gmail . com
26 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
28 package org.forester.phylogeny;
30 import java.util.ArrayList;
31 import java.util.List;
33 import org.forester.io.parsers.nhx.NHXFormatException;
34 import org.forester.io.parsers.nhx.NHXParser;
35 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
36 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
37 import org.forester.phylogeny.data.BranchData;
38 import org.forester.phylogeny.data.Confidence;
39 import org.forester.phylogeny.data.NodeData;
40 import org.forester.phylogeny.data.PhylogenyDataUtil;
41 import org.forester.phylogeny.iterators.PreorderTreeIterator;
42 import org.forester.util.ForesterUtil;
45 * Warning. Implementation of method 'compareTo' only looks at
46 * node name. Thus, use of this class in SortedSets might lead
47 * to unexpected behavior.
50 public final class PhylogenyNode implements Comparable<PhylogenyNode> {
52 private static long NODE_COUNT = 0;
53 private BranchData _branch_data;
54 private boolean _collapse;
55 private ArrayList<PhylogenyNode> _descendants;
56 private double _distance_parent = PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
58 private byte _indicator;
59 private PhylogenyNode _link;
60 private NodeData _node_data;
61 private PhylogenyNode _parent;
62 private int _sum_ext_nodes;
64 private float _x_secondary;
66 private float _y_secondary;
69 * Default constructor for PhylogenyNode.
71 public PhylogenyNode() {
72 setId( PhylogenyNode.getNodeCount() );
73 PhylogenyNode.increaseNodeCount();
74 setSumExtNodes( 1 ); // For ext node, this number is 1 (not 0!!)
77 private PhylogenyNode( final String nhx,
78 final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction,
79 final boolean replace_underscores ) throws NHXFormatException, PhyloXmlDataFormatException {
80 NHXParser.parseNHX( nhx, this, taxonomy_extraction, replace_underscores );
81 setId( PhylogenyNode.getNodeCount() );
82 PhylogenyNode.increaseNodeCount();
83 setSumExtNodes( 1 ); // For ext node, this number is 1 (not 0!!).
87 * Adds PhylogenyNode n to the list of child nodes and sets the _parent of n
91 * the PhylogenyNode to add
93 final public void addAsChild( final PhylogenyNode node ) {
94 final PhylogenyNode n = node;
99 public final int calculateDepth() {
100 PhylogenyNode n = this;
102 while ( n._parent != null ) {
109 public final double calculateDistanceToRoot() {
110 PhylogenyNode n = this;
112 while ( n._parent != null ) {
113 if ( n._distance_parent > 0.0 ) {
114 d += n._distance_parent;
122 // this is poor, as it only compares on names!
123 final public int compareTo( final PhylogenyNode o ) {
124 final PhylogenyNode n = o;
125 if ( ( getName() == null ) || ( n.getName() == null ) ) {
128 return getName().compareTo( n.getName() );
132 * Returns a new PhylogenyNode which has its data copied from this
133 * PhylogenyNode. Links to the other Nodes in the same Phylogeny are NOT
134 * copied (e.g. _link to _parent). Field "_link" IS copied.
138 final public PhylogenyNode copyNodeData() {
139 final PhylogenyNode node = new PhylogenyNode();
140 PhylogenyNode.decreaseNodeCount();
142 node._sum_ext_nodes = _sum_ext_nodes;
143 node._indicator = _indicator;
146 node._distance_parent = _distance_parent;
147 node._collapse = _collapse;
149 if ( _node_data != null ) {
150 node._node_data = ( NodeData ) _node_data.copy();
152 if ( _branch_data != null ) {
153 node._branch_data = ( BranchData ) _branch_data.copy();
159 * Returns a new PhylogenyNode which has the same data as this
160 * PhylogenyNode. Links to the other Nodes in the same Phylogeny are NOT
161 * copied (e.g. _link to _parent). Field "_link" IS copied.
165 final public PhylogenyNode copyNodeDataShallow() {
166 final PhylogenyNode node = new PhylogenyNode();
167 PhylogenyNode.decreaseNodeCount();
169 node._sum_ext_nodes = _sum_ext_nodes;
170 node._indicator = _indicator;
173 node._distance_parent = _distance_parent;
174 node._collapse = _collapse;
176 node._node_data = _node_data;
177 node._branch_data = _branch_data;
183 * Based on node name, sequence, and taxonomy.
187 final public boolean equals( final Object o ) {
191 else if ( o == null ) {
194 else if ( o.getClass() != this.getClass() ) {
195 throw new IllegalArgumentException( "attempt to check [" + this.getClass() + "] equality to " + o + " ["
196 + o.getClass() + "]" );
199 final PhylogenyNode other = ( PhylogenyNode ) o;
200 if ( !getName().equals( other.getName() ) ) {
203 final NodeData this_data = getNodeData();
204 final NodeData other_data = other.getNodeData();
205 if ( ( this_data.isHasSequence() && other_data.isHasSequence() )
206 && ( this_data.isHasTaxonomy() && other_data.isHasTaxonomy() ) ) {
207 return ( this_data.getTaxonomy().isEqual( other_data.getTaxonomy() ) && this_data.getSequence()
208 .isEqual( other_data.getSequence() ) );
210 else if ( this_data.isHasTaxonomy() && other_data.isHasTaxonomy() ) {
211 return ( this_data.getTaxonomy().isEqual( other_data.getTaxonomy() ) );
213 else if ( this_data.isHasSequence() && other_data.isHasSequence() ) {
214 return ( this_data.getSequence().isEqual( other_data.getSequence() ) );
216 else if ( getName().length() > 0 ) {
217 // Node name is not empty, and equal.
226 final public List<PhylogenyNode> getAllDescendants() {
231 * Returns a List containing references to all external children of this
234 * @return List of references to external Nodes
236 final public List<PhylogenyNode> getAllExternalDescendants() {
237 final List<PhylogenyNode> nodes = new ArrayList<PhylogenyNode>();
238 if ( isExternal() ) {
242 PhylogenyNode node1 = this;
243 while ( !node1.isExternal() ) {
244 node1 = node1.getFirstChildNode();
246 PhylogenyNode node2 = this;
247 while ( !node2.isExternal() ) {
248 node2 = node2.getLastChildNode();
250 while ( node1 != node2 ) {
252 node1 = node1.getNextExternalNode();
259 * Returns a List containing references to all names of the external
260 * children of this PhylogenyNode.
262 * @return List of references to names of external Nodes
264 final public List<String> getAllExternalDescendantsNames() {
265 final List<PhylogenyNode> c = getAllExternalDescendants();
266 final List<String> n = new ArrayList<String>( c.size() );
267 for( final PhylogenyNode phylogenyNode : c ) {
268 n.add( phylogenyNode.getName() );
273 final public BranchData getBranchData() {
274 if ( _branch_data == null ) {
275 _branch_data = new BranchData();
281 * This return child node n of this node.
284 * the index of the child to get
285 * @return the child node with index n
286 * @throws IllegalArgumentException
287 * if n is out of bounds
289 final public PhylogenyNode getChildNode( final int i ) {
290 if ( isExternal() ) {
291 throw new UnsupportedOperationException( "attempt to get the child node of an external node." );
293 if ( ( i >= getNumberOfDescendants() ) || ( i < 0 ) ) {
294 throw new IllegalArgumentException( "attempt to get child node " + i + " of a node with "
295 + getNumberOfDescendants() + " child nodes" );
297 return getDescendants().get( i );
301 * Convenience method. Returns the first child PhylogenyNode of this
304 final public PhylogenyNode getChildNode1() {
305 return getChildNode( 0 );
309 * Convenience method. Returns the second child PhylogenyNode of this
312 * [last modified May 18, 2005 by CMZ]
314 final public PhylogenyNode getChildNode2() {
315 return getChildNode( 1 );
319 * This gets the child node index of this node.
322 * @return the child node index of this node
323 * @throws UnsupportedOperationException
324 * if this node is a root node
326 final public int getChildNodeIndex() {
327 return getChildNodeIndex( getParent() );
331 * This gets the child node index of this node, given that parent is its
334 * [last modified Aug 14, 2006 by CMZ]
336 * @return the child node index of this node
337 * @throws UnsupportedOperationException
338 * if this node is a root node
340 final public int getChildNodeIndex( final PhylogenyNode parent ) {
342 throw new UnsupportedOperationException( "Cannot get the child index for a root node." );
344 for( int i = 0; i < parent.getNumberOfDescendants(); ++i ) {
345 if ( parent.getChildNode( i ) == this ) {
349 throw new RuntimeException( "Unexpected exception: Could not determine the child index for node: " + this );
352 final public List<PhylogenyNode> getDescendants() {
353 if ( _descendants == null ) {
354 _descendants = new ArrayList<PhylogenyNode>();
360 * Returns the length of the branch leading to the _parent of this
361 * PhylogenyNode (double).
363 final public double getDistanceToParent() {
364 return _distance_parent;
368 * Convenience method. Returns the first child node of this node.
370 * [last modified May 18, 2005 by CMZ]
372 * @return the first child node of this node
374 public final PhylogenyNode getFirstChildNode() {
375 return getChildNode( 0 );
379 * Returns the ID (int) of this PhylogenyNode.
381 final public long getId() {
386 * Returns the _indicator value of this PhylogenyNode.
388 public final byte getIndicator() {
393 * Convenience method. Returns the last child node of this node.
395 * [last modified May 18, 2005 by CMZ]
397 * @return the last child node of this node
399 public final PhylogenyNode getLastChildNode() {
400 return getChildNode( getNumberOfDescendants() - 1 );
404 * Returns a refernce to the linked PhylogenyNode of this PhylogenyNode.
405 * Currently, this method is only used for the speciation-_duplication
406 * assignment algorithms.
408 public final PhylogenyNode getLink() {
412 final public String getName() {
413 return getNodeData().getNodeName();
417 * Returns a refernce to the next external PhylogenyNode of this
418 * PhylogenyNode. TODO should be in Phylogeny. Returns null if no next
419 * external node is available.
421 public final PhylogenyNode getNextExternalNode() {
422 if ( isInternal() ) {
423 throw new UnsupportedOperationException( "attempt to get next external node of an internal node" );
425 else if ( isLastExternalNode() ) {
428 int index = getChildNodeIndex();
429 PhylogenyNode previous_node = this;
430 PhylogenyNode current_node = getParent();
431 while ( !current_node.isRoot()
432 && ( ( current_node.getNumberOfDescendants() == 1 ) || previous_node.isLastChildNode() ) ) {
433 index = current_node.getChildNodeIndex();
434 previous_node = current_node;
435 current_node = current_node.getParent();
437 current_node = current_node.getChildNode( index + 1 );
438 while ( current_node.isInternal() ) {
439 current_node = current_node.getFirstChildNode();
444 public final PhylogenyNode getNextExternalNodeWhileTakingIntoAccountCollapsedNodes() {
446 if ( isInternal() && !isCollapse() ) {
447 throw new UnsupportedOperationException( "attempt to get next external node of an uncollapsed internal node" );
452 if ( getParent().isCollapse() ) {
453 throw new UnsupportedOperationException( "attempt to get next external node of node with a collapsed parent" );
455 // This checks if last node.
456 PhylogenyNode n = this;
458 while ( !n.isRoot() ) {
459 if ( !n.isLastChildNode() ) {
468 int index = getChildNodeIndex();
469 PhylogenyNode previous_node = this;
470 PhylogenyNode current_node = getParent();
471 while ( !current_node.isRoot()
472 && ( current_node.isCollapse() || ( current_node.getNumberOfDescendants() == 1 ) || previous_node
473 .isLastChildNode() ) ) {
474 index = current_node.getChildNodeIndex();
475 previous_node = current_node;
476 current_node = current_node.getParent();
478 if ( index < ( current_node.getNumberOfDescendants() - 1 ) ) {
479 current_node = current_node.getChildNode( index + 1 );
481 while ( current_node.isInternal() && !current_node.isCollapse() ) {
482 current_node = current_node.getFirstChildNode();
487 public final NodeData getNodeData() {
488 if ( _node_data == null ) {
489 _node_data = new NodeData();
494 final public int getNumberOfDescendants() {
495 if ( _descendants == null ) {
498 return _descendants.size();
502 * Returns the total number of external Nodes originating from this
503 * PhylogenyNode (int).
505 final public int getNumberOfExternalNodes() {
506 return _sum_ext_nodes;
509 final public int getNumberOfParents() {
514 * Returns a refernce to the parent PhylogenyNode of this PhylogenyNode.
516 final public PhylogenyNode getParent() {
521 * Returns a refernce to the next external PhylogenyNode of this
522 * PhylogenyNode. TODO should be in Phylogeny. Returns null if no next
523 * external node is available.
525 final public PhylogenyNode getPreviousExternalNode() {
526 if ( isInternal() ) {
527 throw new UnsupportedOperationException( "Cannot get the previous external node for an internal node." );
529 else if ( isRoot() /* TODO && tree is rooted */) {
530 throw new UnsupportedOperationException( "Cannot get the previous external node for a root node." );
532 else if ( isFirstExternalNode() ) {
533 throw new UnsupportedOperationException( "Attempt to get previous external node of the first external node." );
535 int index = getChildNodeIndex();
536 PhylogenyNode previous_node = this;
537 PhylogenyNode current_node = getParent();
538 while ( !current_node.isRoot()
539 && ( ( current_node.getNumberOfDescendants() == 1 ) || previous_node.isFirstChildNode() ) ) {
540 index = current_node.getChildNodeIndex();
541 previous_node = current_node;
542 current_node = current_node.getParent();
544 current_node = current_node.getChildNode( index - 1 );
545 while ( current_node.isInternal() ) {
546 current_node = current_node.getLastChildNode();
552 * Used for drawing of Trees.
554 final public float getXcoord() {
558 final public float getXSecondary() {
563 * Used for drawing of Trees.
565 final public float getYcoord() {
569 final public float getYSecondary() {
574 final public int hashCode() {
575 final NodeData data = getNodeData();
576 if ( ( getName().length() < 1 ) && !data.isHasSequence() && !data.isHasTaxonomy() ) {
577 return super.hashCode();
579 int result = getName().hashCode();
580 if ( data.isHasSequence() ) {
581 result ^= data.getSequence().hashCode();
583 if ( data.isHasTaxonomy() ) {
584 result ^= data.getTaxonomy().hashCode();
590 * Returns whether this PhylogenyNode should be drawn as collapsed.
592 final public boolean isCollapse() {
597 * Returns true if this PhylogenyNode represents a _duplication event, false
600 final public boolean isDuplication() {
601 return getNodeData().isHasEvent() && getNodeData().getEvent().isDuplication();
604 public boolean isEmpty() {
605 return ( ( _node_data == null ) || _node_data.isEmpty() );
609 * Checks whether this PhylogenyNode is external (tip).
611 * @return true if this PhylogenyNode is external, false otherwise
613 final public boolean isExternal() {
614 if ( _descendants == null ) {
617 return ( getNumberOfDescendants() < 1 );
620 final public boolean isFirstChildNode() {
621 if ( isRoot() /* and tree is rooted TODO */) {
622 throw new UnsupportedOperationException( "Cannot determine whether the root is the first child node of its _parent." );
624 return ( getChildNodeIndex() == 0 );
627 final public boolean isFirstExternalNode() {
628 if ( isInternal() ) {
631 PhylogenyNode node = this;
632 while ( !node.isRoot() ) {
633 if ( !node.isFirstChildNode() ) {
636 node = node.getParent();
642 * Returns whether a _duplication or speciation event has been assigned for
643 * this PhylogenyNode.
645 final public boolean isHasAssignedEvent() {
646 if ( !getNodeData().isHasEvent() ) {
649 if ( ( getNodeData().getEvent() ).isUnassigned() ) {
656 * Checks whether this PhylogenyNode is internal (tip).
658 * @return true if this PhylogenyNode is external, false otherwise
660 final public boolean isInternal() {
661 return ( !isExternal() );
665 * Returns true if this node is the last child node of its _parent.
667 * [last modified June 01, 2005 by CMZ]
669 * @return true if this node is the last child node of its _parent, false
672 final public boolean isLastChildNode() {
673 if ( isRoot() /* and tree is rooted TODO */) {
674 throw new UnsupportedOperationException( "Cannot determine whether the root is the last child node of its _parent." );
676 return ( getChildNodeIndex() == ( getParent().getNumberOfDescendants() - 1 ) );
679 final public boolean isLastExternalNode() {
680 if ( isInternal() ) {
683 PhylogenyNode node = this;
684 while ( !node.isRoot() ) {
685 if ( !node.isLastChildNode() ) {
688 node = node.getParent();
694 * Checks whether this PhylogenyNode is a root.
696 * @return true if this PhylogenyNode is the root, false otherwise
698 final public boolean isRoot() {
699 return _parent == null;
702 final public boolean isSpeciation() {
703 return getNodeData().isHasEvent() && getNodeData().getEvent().isSpeciation();
706 // ---------------------------------------------------------
708 // ---------------------------------------------------------
710 * Prints to the console the subtree originating from this PhylogenyNode in
713 public void preorderPrint() {
714 System.out.println( this + "\n" );
715 if ( isInternal() ) {
716 for( int i = 0; i < getNumberOfDescendants(); ++i ) {
717 getChildNode( i ).preorderPrint();
722 final public void removeChildNode( final int i ) {
723 if ( isExternal() ) {
724 throw new UnsupportedOperationException( "cannot get the child node for a external node." );
726 if ( ( i >= getNumberOfDescendants() ) || ( i < 0 ) ) {
727 throw new IllegalArgumentException( "attempt to get child node " + i + " of a node with "
728 + getNumberOfDescendants() + " child nodes." );
730 getDescendants().remove( i );
733 final public void removeChildNode( final PhylogenyNode remove_me ) {
734 removeChildNode( remove_me.getChildNodeIndex() );
737 public void removeConnections() {
743 final public void setBranchData( final BranchData branch_data ) {
744 _branch_data = branch_data;
748 * Sets the first child PhylogenyNode of this PhylogenyNode to n.
750 final public void setChild1( final PhylogenyNode n ) {
751 setChildNode( 0, n );
755 * Sets the second child PhylogenyNode of this PhylogenyNode to n.
757 final public void setChild2( final PhylogenyNode n ) {
758 setChildNode( 1, n );
762 * Inserts PhylogenyNode n at the specified position i into the list of
763 * child nodes. This does not allow null slots in the list of child nodes:
764 * If i is larger than the number of child nodes, n is just added to the
765 * list, not place at index i.
768 * the index of position where to add the child
770 * the PhylogenyNode to add
772 final public void setChildNode( final int i, final PhylogenyNode node ) {
773 node.setParent( this );
774 if ( getNumberOfDescendants() <= i ) {
775 addChildNode( node );
778 getDescendants().set( i, node );
783 * Sets whether this PhylogenyNode should be drawn as collapsed.
785 final public void setCollapse( final boolean b ) {
790 * Sets the length of the branch leading to the _parent of this
791 * PhylogenyNode to double d.
793 final public void setDistanceToParent( final double d ) {
794 _distance_parent = d;
798 * Sets the _indicator value of this PhylogenyNode to i.
800 final public void setIndicator( final byte i ) {
805 * Sets the linked PhylogenyNode of this PhylogenyNode to n. Currently, this
806 * method is only used for the speciation-_duplication assignment
809 final public void setLink( final PhylogenyNode n ) {
814 * Sets the name of this node.
816 final public void setName( final String node_name ) {
817 getNodeData().setNodeName( node_name );
821 * Sets the _parent PhylogenyNode of this PhylogenyNode to n.
823 final public void setParent( final PhylogenyNode n ) {
828 * Sets the total number of external Nodes originating from this
829 * PhylogenyNode to i (int).
831 final public void setSumExtNodes( final int i ) {
833 throw new IllegalArgumentException( "attempt to set sum of external nodes to less than one" );
839 * Used for drawing of Trees.
841 final public void setXcoord( final float x ) {
845 final public void setXSecondary( final float x_secondary ) {
846 _x_secondary = x_secondary;
851 * Used for drawing of Trees.
853 final public void setYcoord( final float y ) {
857 final public void setYSecondary( final float y_secondary ) {
858 _y_secondary = y_secondary;
862 * Swaps the the two childern of a PhylogenyNode node of this Phylogeny.
864 public final void swapChildren() throws RuntimeException {
865 if ( isExternal() ) {
866 throw new RuntimeException( "attempt to swap descendants of external node" );
868 if ( getNumberOfDescendants() != 2 ) {
869 throw new RuntimeException( "attempt to swap descendants of node with " + getNumberOfDescendants()
872 final PhylogenyNode a = getChildNode( 0 );
873 final PhylogenyNode b = getChildNode( 1 );
874 setChildNode( 0, b );
875 setChildNode( 1, a );
878 // ---------------------------------------------------------
879 // Writing of Nodes to Strings
880 // ---------------------------------------------------------
881 final public String toNewHampshire( final boolean simple_nh,
882 final boolean write_distance_to_parent,
883 final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) {
884 final StringBuilder sb = new StringBuilder();
886 if ( ( svs == NH_CONVERSION_SUPPORT_VALUE_STYLE.AS_INTERNAL_NODE_NAMES ) && !isExternal() ) {
887 if ( getBranchData().isHasConfidences()
888 && ( getBranchData().getConfidence( 0 ).getValue() != Confidence.CONFIDENCE_DEFAULT_VALUE ) ) {
889 data = Confidence.FORMATTER.format( ForesterUtil
890 .round( getBranchData().getConfidence( 0 ).getValue(),
891 PhyloXmlUtil.ROUNDING_DIGITS_FOR_PHYLOXML_DOUBLE_OUTPUT ) );
894 else if ( !ForesterUtil.isEmpty( getName() ) ) {
897 else if ( getNodeData().isHasTaxonomy() ) {
898 if ( !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
899 data = getNodeData().getTaxonomy().getTaxonomyCode();
901 else if ( !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getScientificName() ) ) {
902 data = getNodeData().getTaxonomy().getScientificName();
904 else if ( !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getCommonName() ) ) {
905 data = getNodeData().getTaxonomy().getCommonName();
907 else if ( getNodeData().getTaxonomy().getTaxonomyCode() != null ) {
908 data = getNodeData().getTaxonomy().getTaxonomyCode();
911 else if ( getNodeData().isHasSequence() ) {
912 if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getName() ) ) {
913 data = getNodeData().getSequence().getName();
916 if ( data.length() > 0 ) {
917 data = ForesterUtil.replaceIllegalNhCharacters( data );
918 if ( simple_nh && ( data.length() > 10 ) ) {
919 data = data.substring( 0, 11 );
921 if ( ForesterUtil.isContainsParanthesesableNhCharacter( data ) ) {
930 if ( write_distance_to_parent && ( getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) ) {
932 sb.append( getDistanceToParent() );
934 if ( ( svs == NH_CONVERSION_SUPPORT_VALUE_STYLE.IN_SQUARE_BRACKETS ) && !isExternal()
935 && getBranchData().isHasConfidences()
936 && ( getBranchData().getConfidence( 0 ).getValue() != Confidence.CONFIDENCE_DEFAULT_VALUE ) ) {
938 sb.append( Confidence.FORMATTER.format( ForesterUtil
939 .round( getBranchData().getConfidence( 0 ).getValue(),
940 PhyloXmlUtil.ROUNDING_DIGITS_FOR_PHYLOXML_DOUBLE_OUTPUT ) ) );
943 return sb.toString();
947 * Converts this PhylogenyNode to a New Hampshire X (NHX) String
950 final public String toNewHampshireX() {
951 final StringBuffer sb = new StringBuffer();
952 final StringBuffer s_nhx = new StringBuffer();
953 if ( !ForesterUtil.isEmpty( getName() ) ) {
954 final String name = ForesterUtil.replaceIllegalNhCharacters( getName() );
955 if ( ForesterUtil.isContainsParanthesesableNhCharacter( name ) ) {
964 if ( getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
966 sb.append( getDistanceToParent() );
968 if ( getNodeDataDirectly() != null ) {
969 s_nhx.append( getNodeDataDirectly().toNHX() );
971 if ( getBranchDataDirectly() != null ) {
972 s_nhx.append( getBranchDataDirectly().toNHX() );
974 if ( s_nhx.length() > 0 ) {
975 sb.append( "[&&NHX" );
979 return sb.toString();
983 final public String toString() {
984 final StringBuilder sb = new StringBuilder();
985 if ( getNodeData().isHasTaxonomy() ) {
986 if ( !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getScientificName() ) ) {
987 sb.append( getNodeData().getTaxonomy().getScientificName() );
990 else if ( ( sb.length() <= 1 ) && !ForesterUtil.isEmpty( getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
991 sb.append( getNodeData().getTaxonomy().getTaxonomyCode() );
994 else if ( getNodeData().getTaxonomy().getIdentifier() != null ) {
995 sb.append( getNodeData().getTaxonomy().getIdentifier().toString() );
999 if ( getNodeData().isHasSequence() ) {
1000 if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getName() ) ) {
1001 sb.append( getNodeData().getSequence().getName() );
1004 if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getSymbol() ) ) {
1005 sb.append( getNodeData().getSequence().getSymbol() );
1008 if ( !ForesterUtil.isEmpty( getNodeData().getSequence().getGeneName() ) ) {
1009 sb.append( getNodeData().getSequence().getGeneName() );
1012 if ( getNodeData().getSequence().getAccession() != null ) {
1013 sb.append( getNodeData().getSequence().getAccession().toString() );
1017 if ( ( sb.length() <= 1 ) && !ForesterUtil.isEmpty( getName() ) ) {
1018 sb.append( getName() );
1021 if ( sb.length() <= 1 ) {
1023 sb.append( getId() );
1026 return sb.toString().trim();
1030 * Sets the Id of this PhylogenyNode to i. In most cases, this number
1031 * should not be set to values lower than getNodeCount() -- which this method
1034 synchronized final protected void setId( final long i ) {
1035 if ( i < getNodeCount() ) {
1036 throw new IllegalArgumentException( "attempt to set node id to a value less than total node count (thus violating the uniqueness of node ids)" );
1041 final BranchData getBranchDataDirectly() {
1042 return _branch_data;
1045 final NodeData getNodeDataDirectly() {
1049 final void setChildNodeOnly( final int i, final PhylogenyNode node ) {
1050 if ( getNumberOfDescendants() <= i ) {
1051 addChildNode( node );
1054 getDescendants().set( i, node );
1059 * Sets the indicators of all the children of this PhylogenyNode to zero.
1061 final void setIndicatorsToZero() {
1062 for( final PreorderTreeIterator it = new PreorderTreeIterator( this ); it.hasNext(); ) {
1063 it.next().setIndicator( ( byte ) 0 );
1068 * Adds PhylogenyNode n to the list of child nodes. But does NOT set the
1069 * _parent of n to this.
1071 * @see addAsChild( PhylogenyNode n )
1073 * the PhylogenyNode to add
1075 final private void addChildNode( final PhylogenyNode child ) {
1076 getDescendants().add( child );
1079 public static PhylogenyNode createInstanceFromNhxString( final String nhx ) throws NHXFormatException,
1080 PhyloXmlDataFormatException {
1081 return new PhylogenyNode( nhx, NHXParser.TAXONOMY_EXTRACTION.NO, false );
1084 public static PhylogenyNode createInstanceFromNhxString( final String nhx,
1085 final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction )
1086 throws NHXFormatException, PhyloXmlDataFormatException {
1087 return new PhylogenyNode( nhx, taxonomy_extraction, false );
1090 public static PhylogenyNode createInstanceFromNhxString( final String nhx,
1091 final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction,
1092 final boolean replace_underscores )
1093 throws NHXFormatException, PhyloXmlDataFormatException {
1094 return new PhylogenyNode( nhx, taxonomy_extraction, replace_underscores );
1098 * Returns the total number of all Nodes created so far.
1100 * @return total number of Nodes (long)
1102 synchronized final public static long getNodeCount() {
1107 * Decreases the total number of all Nodes created so far by one.
1109 final static synchronized void decreaseNodeCount() {
1114 * Sets the total number of all Nodes created so far to i.
1116 synchronized final static void setNodeCount( final long i ) {
1117 PhylogenyNode.NODE_COUNT = i;
1121 * Increases the total number of all Nodes created so far by one.
1123 synchronized final private static void increaseNodeCount() {
1127 public enum NH_CONVERSION_SUPPORT_VALUE_STYLE {
1128 AS_INTERNAL_NODE_NAMES, IN_SQUARE_BRACKETS, NONE;