All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.bio.phylogeny.PhyloNode Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.bio.phylogeny;

import java.util.*;
import java.util.List;
import java.util.regex.Pattern;
import java.awt.*;

import com.hfg.util.collection.CollectionUtil;
import com.hfg.util.StringUtil;
import com.hfg.network.Edge;


//------------------------------------------------------------------------------
/**
 Object representation of a node in a Newick format phylogenetic tree.
 Does not work with negative distance values.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // 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 // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class PhyloNode { private List> mEdges; private String mId; private String mLabel; private Color mColor; private Integer mLineIndex; private Integer mVericalLineStartIndex; private Integer mVericalLineEndIndex; private Double mAngle; private static SubnodeCountComparator sSubnodeCountComparator = new PhyloNode().new SubnodeCountComparator(); private static final Pattern sWhitespacePattern = Pattern.compile("\\s+"); // cached values private Float mDistanceFromRoot; //-------------------------------------------------------------------------- public PhyloNode setId(int inValue) { return setId(inValue + ""); } //-------------------------------------------------------------------------- public PhyloNode setId(String inValue) { mId = inValue; return this; } //-------------------------------------------------------------------------- public String getId() { return mId; } //-------------------------------------------------------------------------- public PhyloNode setLabel(String inValue) { mLabel = inValue; return this; } //-------------------------------------------------------------------------- public String getLabel() { return mLabel; } //-------------------------------------------------------------------------- public PhyloNode setColor(Color inValue) { mColor = inValue; return this; } //-------------------------------------------------------------------------- public Color getColor() { return mColor; } //-------------------------------------------------------------------------- public List> getEdges() { return mEdges; } //-------------------------------------------------------------------------- public void addEdge(PhyloNode in2ndNode, Float inDistance) { if (null == mEdges) { mEdges = new ArrayList<>(3); } Edge edge = new Edge<>(this, in2ndNode, inDistance); mEdges.add(edge); in2ndNode.addEdge(edge); } //-------------------------------------------------------------------------- public PhyloNode setAngle(Double inAngleInRadians) { mAngle = inAngleInRadians; return this; } //-------------------------------------------------------------------------- public Double getAngle() { return mAngle; } //-------------------------------------------------------------------------- protected void addEdge(Edge inEdge) { if (null == mEdges) { mEdges = new ArrayList<>(3); } mEdges.add(inEdge); } //-------------------------------------------------------------------------- protected boolean removeEdge(Edge inEdge) { boolean result = false; if (mEdges != null) { result = mEdges.remove(inEdge); // Remove the edge from the other node as well. if (this == inEdge.getFrom()) { inEdge.setFrom(null); if (inEdge.getTo() != null) inEdge.getTo().removeEdge(inEdge); } else if (this == inEdge.getTo()) { inEdge.setTo(null); if (inEdge.getFrom() != null) inEdge.getFrom().removeEdge(inEdge); } } return result; } //-------------------------------------------------------------------------- protected boolean removeEdgeFrom(PhyloNode inNode) { boolean result = false; if (mEdges != null) { for (Edge edge : mEdges) { if (edge.getFrom() == inNode) { mEdges.remove(edge); edge.setTo(null); // Remove the edge from the other node as well. edge.getFrom().removeEdge(edge); result = true; break; } } } return result; } //-------------------------------------------------------------------------- public boolean isLeaf() { return null == mEdges || mEdges.size() < 2; } //-------------------------------------------------------------------------- public void makeRoot() { // Fan out through the tree setting the directionality to flow from the root. for (Edge edge : mEdges) { if (edge.getFrom() != this) edge.switchDirection(); edge.getTo().setRootDirection(edge); } } //-------------------------------------------------------------------------- protected void setRootDirection(Edge inEdge) { for (Edge edge : mEdges) { if (edge == inEdge) continue; if (edge.getFrom() != this) edge.switchDirection(); edge.getTo().setRootDirection(edge); } } /* //-------------------------------------------------------------------------- public Float getMaxDistance() { float maxChildDistance = 0; if (CollectionUtil.hasValues(mChildNodes)) { for (PhyloNode child : mChildNodes) { float childDistance = child.getMaxDistance(); if (childDistance > maxChildDistance) { maxChildDistance = childDistance; } } } return maxChildDistance + (getDistance() != null ? getDistance() : 0); } //-------------------------------------------------------------------------- public Float getDistance() { return mDistance; } */ //-------------------------------------------------------------------------- public PhyloNode getParentNode() { PhyloNode parent = null; Edge parentEdge = getParentEdge(); if (parentEdge != null) { parent = parentEdge.getFrom(); } return parent; } //-------------------------------------------------------------------------- public List getChildNodes() { List childNodes = null; if (CollectionUtil.hasValues(mEdges)) { for (Edge edge : mEdges) { if (edge.getFrom() == this) { if (null == childNodes) { childNodes = new ArrayList<>(4); } childNodes.add(edge.getTo()); } } } return childNodes; } //-------------------------------------------------------------------------- /** Returns the root-facing edge. @return the root-facing Edge for the node */ public Edge getParentEdge() { Edge parentEdge = null; if (CollectionUtil.hasValues(mEdges)) { for (Edge edge : mEdges) { if (edge.getTo() == this) { parentEdge = edge; break; } } } return parentEdge; } //-------------------------------------------------------------------------- /** Returns the leaf-facing edges. @return the leaf-facing Edge for the node */ public List> getLeafFacingEdges() { List> leafFacingEdges = new ArrayList<>(3); if (! isLeaf()) { for (Edge edge : mEdges) { if (edge.getFrom() == this) { leafFacingEdges.add(edge); } } } return leafFacingEdges; } //-------------------------------------------------------------------------- public void orderEdgesByLeafCount() { if (! isLeaf()) { List> leafFacingEdges = getLeafFacingEdges(); if (CollectionUtil.hasValues(leafFacingEdges)) { Collections.sort(leafFacingEdges, sSubnodeCountComparator); } List> newEdgeList = new ArrayList<>(mEdges.size()); for (Edge edge : mEdges) { if (edge.getFrom() != this) { newEdgeList.add(edge); } } newEdgeList.addAll(leafFacingEdges); mEdges = newEdgeList; } } //-------------------------------------------------------------------------- public Float getDistanceFromRoot() { if (null == mDistanceFromRoot) { float distance = 0; Edge parentEdge = getParentEdge(); if (parentEdge != null) { do { if (parentEdge.getDistance() != null) distance += parentEdge.getDistance(); } while (parentEdge.getFrom() != null && (parentEdge = parentEdge.getFrom().getParentEdge()) != null); } mDistanceFromRoot = distance; } return mDistanceFromRoot; } //-------------------------------------------------------------------------- public Float getMaxDistanceToLeaf() { float maxDistance = 0; if (! isLeaf()) { for (Edge edge : mEdges) { if (edge.getFrom() == this) { float childDistance = 0; if (edge.getDistance() != null) childDistance += edge.getDistance(); PhyloNode child = edge.getTo(); if (! child.isLeaf()) childDistance += child.getMaxDistanceToLeaf(); if (childDistance > maxDistance) { maxDistance = childDistance; } } } } return maxDistance; } //-------------------------------------------------------------------------- public int getSubnodeCount() { int subnodeCount = 0; if (! isLeaf()) { for (Edge edge : mEdges) { if (edge.getFrom() == this) { subnodeCount += 1 + edge.getTo().getSubnodeCount(); } } } return subnodeCount; } //-------------------------------------------------------------------------- /** Calculates the distance between two nodes in the tree. @param inNode2 the node to calculate the distance to @return the distance between this node and the specified node */ // Three cases: // 1. node2 is above node1 // 2. node2 is below node1 // 3. node2 and node1 have a common ancestor public Float distanceTo(PhyloNode inNode2) { float result = 0; float distance1 = 0; float distance2 = 0; Map map1 = new HashMap<>(); boolean done = false; Edge parentEdge = getParentEdge(); if (parentEdge != null) { do { map1.put(parentEdge.getTo(), distance1); if (parentEdge.getTo() == inNode2) { result = distance1; done = true; break; } if (parentEdge.getDistance() != null) distance1 += parentEdge.getDistance(); } while (parentEdge.getFrom() != null && (parentEdge = parentEdge.getFrom().getParentEdge()) != null); } if (!done) { parentEdge = inNode2.getParentEdge(); if (parentEdge != null) { do { if (parentEdge.getDistance() != null) distance2 += parentEdge.getDistance(); Float distance = map1.get(parentEdge.getFrom()); if (distance != null) { result = distance + distance2; done = true; break; } } while (parentEdge.getFrom() != null && (parentEdge = parentEdge.getFrom().getParentEdge()) != null); } if (!done) { result = distance1 + distance2; } } return result; } //-------------------------------------------------------------------------- @Override public String toString() { StringBuilder buffer = new StringBuilder(); if (! isLeaf()) { buffer.append("("); for (Edge edge : mEdges) { if (edge.getFrom() == this) { PhyloNode child = edge.getTo(); if (buffer.length() > 1) buffer.append(","); buffer.append(child.toString()); } } buffer.append(")"); } if (StringUtil.isSet(getLabel())) { // Convert spaces to underscores. String label = StringUtil.replaceAllRegexp(mLabel, sWhitespacePattern, "_"); // Convert colons to underscores. label = StringUtil.replaceAll(label, ":", "_"); buffer.append(label); } Edge parentEdge = getParentEdge(); if (parentEdge != null && parentEdge.getDistance() != null) { buffer.append(":" + parentEdge.getDistance()); } return buffer.toString(); } //-------------------------------------------------------------------------- protected void setLineIndex(int inValue) { mLineIndex = inValue; } //-------------------------------------------------------------------------- protected Integer getLineIndex() { return mLineIndex; } //-------------------------------------------------------------------------- protected void setVerticalLineStartIndex(int inValue) { mVericalLineStartIndex = inValue; } //-------------------------------------------------------------------------- protected Integer getVericalLineStartIndex() { return mVericalLineStartIndex; } //-------------------------------------------------------------------------- protected void setVerticalLineEndIndex(int inValue) { mVericalLineEndIndex = inValue; } //-------------------------------------------------------------------------- protected Integer getVericalLineEndIndex() { return mVericalLineEndIndex; } private class SubnodeCountComparator implements Comparator> { public int compare(Edge edge1, Edge edge2) { int node1SubnodeCount = edge1.getTo().getSubnodeCount(); int node2SubnodeCount = edge2.getTo().getSubnodeCount(); if (node1SubnodeCount > node2SubnodeCount) return -1; if (node1SubnodeCount < node2SubnodeCount) return 1; if (edge1.getTo().getLabel() != null) { return edge1.getTo().getLabel().compareTo(edge2.getTo().getLabel()); } return 0; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy