package newickTreeParsing; import java.io.IOException; import java.io.Serializable; import java.util.*; /** * A class representing a node of a (phylognenetic) tree. The tree that this * node belongs to is of type Tree. Nodes have fields that store a pre- and * post-ordering. * * A TreeNode has a list of children, a unique key, a leftmostleaf and a * rightmost leaf * * @author Tamara Munzner, Li Zhang, Yunhong Zhou * @version 2.2 * @see Tree * @see GridCell */ public class TreeNode implements Serializable{ private double Support; /** Array of child nodes that are attached below this internal node. Null if this is a leaf. */ protected ArrayList children; // eventually turn this into an array (need // to change parser) /** key is unique for nodes in one tree. Keys are pre-ordered (root = 0, depth-traversal ordering). */ public int key; /** Height of font in font points used to draw the label. */ private int fontSize; /** Score for a node in [0,1] that corresponds to the topological similarity between two tree drawers. @see TreePairs#getBestCorrNodeScore(Tree, TreeNode, Tree, int) */ private Double bcnScore; // /** // * The offset of the point with respect to the cell. We only have // * this for the row offset as we assume that the vertical edges // * are all aligned. When computing the Y coordinate of a node, we // * add nodeOffsetR to the pointOffset[1], a fixed parameter set by // * AccordionDrawer. // */ /** * The last frame that had a computed {@link #midYPosition}, for caching. */ protected int computedFrame; // store frame midYPosition was last // calculated (needed to place parents) /** Cached location (world-space) of the mid point in the vertical of a cell where the horizontal tree edge is drawn. * This is (1/2 of cell size + minY) for leaves, midway between first and last child edge for internal nodes. */ private double midYPosition; /** Returns the minimum key value of nodes in the subtree rooted by this node. * @return The index of the smallest descendant node (which is the key for this node). */ // this is the key for this node public int getMin() { return key; } /** Returns the maximum key value of nodes in the subtree rooted but this node. * @return The index of the smallest descendant node (which is the key for the rightmost leaf node). */ // this is the key of the rightmost leaf public int getMax() { return rightmostLeaf.key; } /** * Returns the key for this node. * @return The value of {@link #key} for this node. */ public int getKey() { return key; } /** * Returns the label for this node, which is {@link #name}. * @return The value of {@link #name} for this node. */ public String getName() { return name; } /** * Tests to see if this node has a vertical or horizontal edge component. * @param xy 0/X for horizontal, 1/Y for vertical nodes. * @return True if this node has an edge in the chosen direction. Only root nodes don't have a horizontal edge, and only leaves don't have vertical edges. */ protected boolean getEdge(int xy) { if (xy == 0) return !isRoot(); else return !isLeaf(); } /** Implements Comparable interface - sorts on key field. * @param o The other object to compare this node to. * @return -1 if this is smaller than the object's key, +1 if greater, 0 if equal. */ public int compareTo(Object o) { if (key == ((TreeNode) o).key) return 0; else if (key < ((TreeNode) o).key) return -1; else return 1; } /** The parent of this node. This is null for the root node. */ public TreeNode parent; /** * Node name with default "". Most internal nodes have no name and all leaf * nodes have a name. This becomes the long version of the node name when fully * qualified names are used. */ protected String name = ""; // the long form in fully qualified names /** The text that appears when the node is highlighted or has a name displayed. */ public String label = ""; // always short form /** Distance from this node to the root node. The root is at height 1. */ public int height; /** Weight is the horizontal edge length for the edge immediately above the node. Edge lengths are not determined by this number currently; all edges are stretched to make leaves right aligned, with minimal integral lengths. */ public float weight = 0.0f; /** Leftmost (minimum) leaf node under this internal node (or this node for leaves). */ public TreeNode leftmostLeaf; /** Rightmost (maximum) leaf node under this internal node (or this node for leaves). */ public TreeNode rightmostLeaf; /** The number of leaves under this internal node (or 1 for leaves). */ public int numberLeaves; /** The next preorder node. */ public TreeNode preorderNext = null; /** The next postorder node. */ public TreeNode posorderNext = null; /** * Default tree node constructor. * Children list initially set to capacity 2 as in most case binary. * Used in 2 places: create the root when creating the tree; * the parser uses this to create nodes attached to the root. */ public TreeNode() { children = new ArrayList(2); bcnScore = new Double(0.0); } /** * Clean this node of children. */ public void close() { children.clear(); } /** * Destroy this node. Runs {@link #close()}. */ protected void finalize() throws Throwable { try { close(); } finally { super.finalize(); // System.out.println("finally clean treeNodes"); } } /** * Set the name for this node, the name is usually the label drawn with this node. * @param s The new value of {@link #name}, the name for this node. */ public void setName(String s) { name = s; } /** * Get the number of children under this node. * @return Number of nodes stored in the children array {@link #children}. */ public int numberChildren() { return children.size(); } /** * Get a given child for this node, with range checking and casting. * @param i The child index to get. * @return The i(th) child for this node. */ public TreeNode getChild(int i) { if (i < children.size()) return (TreeNode) children.get(i); else return null; } /** * Tests to determine if this node is a leaf. Does not work for nodes not in the tree structure. * @return True if this node has no linked children, and therefore is a leaf node for the tree. */ public boolean isLeaf() { return children.isEmpty(); } /** * Tests to determine if this node is the root of its tree. Does not work for nodes not in the tree structure. * @return True if this node has no linked parent, and therefore is the root of the tree. */ public boolean isRoot() { return (null == parent); } /** * Tests nodes for equality, based on the name of the node. * @param n Second node to test vs. this node. * @return True if the names of both nodes are the same, false otherwise. */ public boolean equals(TreeNode n) { return (name.equals(n.name)); } /** * Add a child to the end of the list of children. Note there is no remove child method, this is permanent. * Additional processing for linking nodes (setting up pointers and leaf properties, for example) is done later. * @param n New child node for this node. */ public void addChild(TreeNode n) { children.add(n); n.parent = this; } /** * Get the parent for this node. * @return Value of {@link #parent}. */ public TreeNode parent() { return parent; } /** * Set the weight of this treenode, which encodes the length of the horizontal edge. * Edge weights are not implemented currently for drawing. * @param w New edge weight for this node, {@link #weight}. */ public void setWeight(double w) { weight = (float) w; } /** * Get the weight of this treenode, which encodes the length of the horizontal edge. * Edge weights are not implemented currently for drawing. * @return Edge weight for this node, {@link #weight}. */ public float getWeight() { return weight; } /** Get the first child of this node. Doesn't work with leaf nodes. * @return First child of this internal node. */ protected TreeNode firstChild() { return (TreeNode) children.get(0); } /** Get the last child of this node. Doesn't work with leaf nodes. * @return Last child of this internal node. */ public TreeNode lastChild() { return (TreeNode) children.get(children.size() - 1); } /** * Long form printing for a single node. Used in conjunction with * {@link #printSubtree()} to display a whole subtree. * */ public void print() { if (name != null) System.out.print("node name: " + name + "\t"); else System.out.print("node name null,\t"); System.out.println("key: " + key); } /** * For debugging, prints the subtree contents, recursive. * */ private void printSubtree() { print(); for (int i = 0; i < children.size(); i++) getChild(i).printSubtree(); } /** * Set the extreme leaves for this node. This is done in leaf->root direction, so all linking can be done in O(n) time. * */ public void setExtremeLeaves() { if (isLeaf()) { leftmostLeaf = this; rightmostLeaf = this; return; } leftmostLeaf = firstChild().leftmostLeaf; rightmostLeaf = lastChild().rightmostLeaf; } /** root->leaf traversal, depth first in direction of leftmost leaf. */ public void linkNodesInPreorder() { if (isLeaf()) return; preorderNext = firstChild(); for (int i = 0; i < numberChildren() - 1; i++) getChild(i).rightmostLeaf.preorderNext = getChild(i + 1); // rightmostLeaf.preorderNext = null; // redundant } /** Leaf->root traversal, starting at leftmost leaf of tree. */ public void linkNodesInPostorder() { if (isLeaf()) return; // n.posorderNext = null; // redundant for (int i = 0; i < numberChildren() - 1; i++) getChild(i).posorderNext = getChild(i + 1).leftmostLeaf; lastChild().posorderNext = this; } /** * Sets the number of leaves, must be run on leaves first (pre-order) * * @return The number of leaves ({@link #numberLeaves}) including the * current node (leaves = 1) */ public int setNumberLeaves() { numberLeaves = 0; if (isLeaf()) numberLeaves = 1; else for (int i = 0; i < children.size(); i++) numberLeaves += getChild(i).numberLeaves; return numberLeaves; } /** * String value of this node, name + key + tree height information. * @return String representation of this node. */ public String toString() { // String edge[] = {edges[0]!=null?edges[0].toString():"X", // edges[1]!=null?edges[1].toString():"Y"}; return name + "(" + key + " @ " + height + ")"; } /** * Set the {@link #bcnScore} for this node. * @param n New value of {@link #bcnScore}. */ public void setBcnScore(float n) { bcnScore = new Double(n); } /** * Get the BCN score for this treenode. * @return Value of {@link #bcnScore} for this node. */ public Double getBcnScore() { return bcnScore; } public double getSupport() { return Support; } public void setSupport(double support) { Support = support; } //NEW FIELDS!! public double Alcada; //'Alcada' value from cluster.alcada() public boolean AddedtoClusterStructure; //For help in the conversion between data types }