// Copyright (C) 2000-2001 Washington University School of Medicine
// and Howard Hughes Medical Institute
// All rights reserved
-//
+//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
-//
+//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
//
// Contact: phylosoft @ gmail . com
-// WWW: www.phylosoft.org/forester
+// WWW: https://sites.google.com/site/cmzmasek/home/software/forester
package org.forester.phylogeny;
import org.forester.io.parsers.nhx.NHXFormatException;
import org.forester.io.parsers.nhx.NHXParser;
-import org.forester.io.parsers.util.PhylogenyParserException;
+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.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<PhylogenyNode> {
+/**
+ * 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<PhylogenyNode> {
- /** 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;
* 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 PhylogenyNode( final String nhx ) throws NHXFormatException {
- this( nhx, ForesterUtil.TAXONOMY_EXTRACTION.NO );
- }
-
- public PhylogenyNode( final String nhx, final ForesterUtil.TAXONOMY_EXTRACTION taxonomy_extraction )
- throws NHXFormatException {
- init();
- NHXParser.parseNHX( nhx, this, taxonomy_extraction, false );
- setId( PhylogenyNode.getNodeCount() );
- PhylogenyNode.increaseNodeCount();
- setSumExtNodes( 1 ); // For ext node, this number is 1 (not 0!!)
- }
-
- /**
- * Constructor for PhylogenyNode.
- * <p>
- *
- * @param s
- * String representing one PhylogenyNode in New Hampshire (NH) or
- * New Hampshire X (NHX) format.
- * @throws NHXFormatException
- * @throws PhylogenyParserException
- */
- public PhylogenyNode( final String nhx,
- final ForesterUtil.TAXONOMY_EXTRACTION taxonomy_extraction,
- final boolean replace_underscores ) throws NHXFormatException {
- init();
- NHXParser.parseNHX( nhx, this, taxonomy_extraction, replace_underscores );
- 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;
}
/**
* @param n
* the PhylogenyNode to add
*/
- 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 );
}
getDescendants().add( child );
}
+ @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 ) ) {
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;
}
final public List<PhylogenyNode> getDescendants() {
+ if ( _descendants == null ) {
+ _descendants = new ArrayList<PhylogenyNode>();
+ }
return _descendants;
}
return current_node;
}
+ public final PhylogenyNode getNextExternalNodeWhileTakingIntoAccountCollapsedNodes() {
+ //TODO work on me ~~
+ if ( isInternal() && !isCollapse() ) {
+ throw new UnsupportedOperationException( "attempt to get next external node of an uncollapsed internal node" );
+ }
+ 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();
+ PhylogenyNode previous_node = this;
+ PhylogenyNode current_node = getParent();
+ while ( !current_node.isRoot()
+ && ( current_node.isCollapse() || ( current_node.getNumberOfDescendants() == 1 ) || previous_node
+ .isLastChildNode() ) ) {
+ index = current_node.getChildNodeIndex();
+ previous_node = current_node;
+ current_node = current_node.getParent();
+ }
+ 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 final NodeData getNodeData() {
if ( _node_data == null ) {
_node_data = new NodeData();
return _id;
}
- /**
- * Returns the name of this node.
- */
final public String getName() {
return getNodeData().getNodeName();
}
+ final public List<PhylogenyNode> getAllDescendants() {
+ return _descendants;
+ }
+
final public int getNumberOfDescendants() {
+ if ( _descendants == null ) {
+ return 0;
+ }
return _descendants.size();
}
return result;
}
- final private void init() {
- _descendants = new ArrayList<PhylogenyNode>();
- _parent = null;
- _id = 0;
- initializeData();
- }
-
+ // final private void init() {
+ //_descendants = new ArrayList<PhylogenyNode>();
+ // _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
*
* @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.
*/
* @return true if this PhylogenyNode is external, false otherwise
*/
final public boolean isExternal() {
+ if ( _descendants == null ) {
+ return true;
+ }
return ( getNumberOfDescendants() < 1 );
}
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.
*
}
// ---------------------------------------------------------
- // Iterator
- // ---------------------------------------------------------
- final public PhylogenyNodeIterator iterateChildNodesForward() {
- return new ChildNodeIteratorForward( this );
- }
-
- // ---------------------------------------------------------
// Basic printing
// ---------------------------------------------------------
/**
// ---------------------------------------------------------
// 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() ) {
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.
*/
sb.append( name );
}
}
- if ( getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
+ if ( getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
sb.append( ":" );
sb.append( getDistanceToParent() );
}
@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();
}
/**
synchronized final static void setNodeCount( final int i ) {
PhylogenyNode._node_count = i;
}
+
+ 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 NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction )
+ throws NHXFormatException, PhyloXmlDataFormatException {
+ return new PhylogenyNode( nhx, taxonomy_extraction, false );
+ }
+
+ public static PhylogenyNode createInstanceFromNhxString( final String nhx,
+ final NHXParser.TAXONOMY_EXTRACTION taxonomy_extraction,
+ final boolean replace_underscores )
+ throws NHXFormatException, PhyloXmlDataFormatException {
+ return new PhylogenyNode( nhx, taxonomy_extraction, replace_underscores );
+ }
+
+ private PhylogenyNode( final String nhx,
+ 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();
+ setSumExtNodes( 1 ); // For ext node, this number is 1 (not 0!!)
+ }
}