X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=forester%2Fjava%2Fsrc%2Forg%2Fforester%2Fphylogeny%2FPhylogenyMethods.java;h=806f031f45854d197eccb15af3f7a78fafb33765;hb=4d7228400f44ee88136f3d70d9455b1b1d95de27;hp=dab752308c379fe420054d3c3c83c1bbef5445bd;hpb=10f90f7787d4b1287a910d4e6ae895da14866929;p=jalview.git diff --git a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java index dab7523..806f031 100644 --- a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java +++ b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java @@ -21,7 +21,7 @@ // 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; @@ -36,14 +36,18 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.forester.io.parsers.FastaParser; import org.forester.io.parsers.PhylogenyParser; import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException; import org.forester.io.parsers.phyloxml.PhyloXmlUtil; import org.forester.io.parsers.util.PhylogenyParserException; +import org.forester.phylogeny.data.Accession; +import org.forester.phylogeny.data.Annotation; import org.forester.phylogeny.data.BranchColor; import org.forester.phylogeny.data.BranchWidth; import org.forester.phylogeny.data.Confidence; @@ -62,52 +66,47 @@ import org.forester.util.ForesterUtil; public class PhylogenyMethods { - //private static PhylogenyMethods _instance = null; - //private final PhylogenyNode _farthest_1 = null; - //private final PhylogenyNode _farthest_2 = null; private PhylogenyMethods() { // Hidden constructor. } - // public double calculateFurthestDistance( final Phylogeny phylogeny ) { - // if ( phylogeny.getNumberOfExternalNodes() < 2 ) { - // return 0.0; - // } - // _farthest_1 = null; - // _farthest_2 = null; - // PhylogenyNode node_1 = null; - // PhylogenyNode node_2 = null; - // double farthest_d = -Double.MAX_VALUE; - // final PhylogenyMethods methods = PhylogenyMethods.getInstance(); - // final List ext_nodes = phylogeny.getRoot().getAllExternalDescendants(); - // for( int i = 1; i < ext_nodes.size(); ++i ) { - // for( int j = 0; j < i; ++j ) { - // final double d = methods.calculateDistance( ext_nodes.get( i ), ext_nodes.get( j ) ); - // if ( d < 0.0 ) { - // throw new RuntimeException( "distance cannot be negative" ); - // } - // if ( d > farthest_d ) { - // farthest_d = d; - // node_1 = ext_nodes.get( i ); - // node_2 = ext_nodes.get( j ); - // } - // } - // } - // _farthest_1 = node_1; - // _farthest_2 = node_2; - // return farthest_d; - // } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } - // public PhylogenyNode getFarthestNode1() { - // return _farthest_1; - // } - // public PhylogenyNode getFarthestNode2() { - // return _farthest_2; - // } + public static void extractFastaInformation( final Phylogeny phy ) { + for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) { + final PhylogenyNode node = iter.next(); + if ( !ForesterUtil.isEmpty( node.getName() ) ) { + final Matcher name_m = FastaParser.FASTA_DESC_LINE.matcher( node.getName() ); + if ( name_m.lookingAt() ) { + System.out.println(); + // System.out.println( name_m.group( 1 ) ); + // System.out.println( name_m.group( 2 ) ); + // System.out.println( name_m.group( 3 ) ); + // System.out.println( name_m.group( 4 ) ); + final String acc_source = name_m.group( 1 ); + final String acc = name_m.group( 2 ); + final String seq_name = name_m.group( 3 ); + final String tax_sn = name_m.group( 4 ); + if ( !ForesterUtil.isEmpty( acc_source ) && !ForesterUtil.isEmpty( acc ) ) { + ForesterUtil.ensurePresenceOfSequence( node ); + node.getNodeData().getSequence( 0 ).setAccession( new Accession( acc, acc_source ) ); + } + if ( !ForesterUtil.isEmpty( seq_name ) ) { + ForesterUtil.ensurePresenceOfSequence( node ); + node.getNodeData().getSequence( 0 ).setName( seq_name ); + } + if ( !ForesterUtil.isEmpty( tax_sn ) ) { + ForesterUtil.ensurePresenceOfTaxonomy( node ); + node.getNodeData().getTaxonomy( 0 ).setScientificName( tax_sn ); + } + } + } + } + } + public static DescriptiveStatistics calculatBranchLengthStatistics( final Phylogeny phy ) { final DescriptiveStatistics stats = new BasicDescriptiveStatistics(); for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { @@ -303,6 +302,18 @@ public class PhylogenyMethods { return stats; } + public final static void collapseSubtreeStructure( final PhylogenyNode n ) { + final List eds = n.getAllExternalDescendants(); + final List d = new ArrayList(); + for( final PhylogenyNode ed : eds ) { + d.add( calculateDistanceToAncestor( n, ed ) ); + } + for( int i = 0; i < eds.size(); ++i ) { + n.setChildNode( i, eds.get( i ) ); + eds.get( i ).setDistanceToParent( d.get( i ) ); + } + } + public static int countNumberOfOneDescendantNodes( final Phylogeny phy ) { int count = 0; for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { @@ -327,16 +338,15 @@ public class PhylogenyMethods { public static final HashMap createNameToExtNodeMap( final Phylogeny phy ) { final HashMap nodes = new HashMap(); - for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) { - final PhylogenyNode n = iter.next(); + final List ext = phy.getExternalNodes(); + for( final PhylogenyNode n : ext ) { nodes.put( n.getName(), n ); } return nodes; } - public static void deleteExternalNodesNegativeSelection( final Set to_delete, final Phylogeny phy ) { - phy.clearHashIdToNodeMap(); - for( final Integer id : to_delete ) { + public static void deleteExternalNodesNegativeSelection( final Set to_delete, final Phylogeny phy ) { + for( final Long id : to_delete ) { phy.deleteSubtree( phy.getNode( id ), true ); } phy.clearHashIdToNodeMap(); @@ -364,24 +374,6 @@ public class PhylogenyMethods { p.externalNodesHaveChanged(); } - public static void deleteExternalNodesPositiveSelection( final Set species_to_keep, final Phylogeny phy ) { - // final Set to_delete = new HashSet(); - for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) { - final PhylogenyNode n = it.next(); - if ( n.getNodeData().isHasTaxonomy() ) { - if ( !species_to_keep.contains( n.getNodeData().getTaxonomy() ) ) { - //to_delete.add( n.getNodeId() ); - phy.deleteSubtree( n, true ); - } - } - else { - throw new IllegalArgumentException( "node " + n.getId() + " has no taxonomic data" ); - } - } - phy.clearHashIdToNodeMap(); - phy.externalNodesHaveChanged(); - } - public static List deleteExternalNodesPositiveSelection( final String[] node_names_to_keep, final Phylogeny p ) { final PhylogenyNodeIterator it = p.iteratorExternalForward(); @@ -404,11 +396,27 @@ public class PhylogenyMethods { return deleted; } + public static void deleteExternalNodesPositiveSelectionT( final List species_to_keep, final Phylogeny phy ) { + final Set to_delete = new HashSet(); + for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) { + final PhylogenyNode n = it.next(); + if ( n.getNodeData().isHasTaxonomy() ) { + if ( !species_to_keep.contains( n.getNodeData().getTaxonomy() ) ) { + to_delete.add( n.getId() ); + } + } + else { + throw new IllegalArgumentException( "node " + n.getId() + " has no taxonomic data" ); + } + } + deleteExternalNodesNegativeSelection( to_delete, phy ); + } + final public static void deleteInternalNodesWithOnlyOneDescendent( final Phylogeny phy ) { final ArrayList to_delete = new ArrayList(); for( final PhylogenyNodeIterator iter = phy.iteratorPostorder(); iter.hasNext(); ) { final PhylogenyNode n = iter.next(); - if ( ( !n.isExternal() ) && ( !n.isRoot() ) && ( n.getNumberOfDescendants() == 1 ) ) { + if ( ( !n.isExternal() ) && ( n.getNumberOfDescendants() == 1 ) ) { to_delete.add( n ); } } @@ -437,9 +445,29 @@ public class PhylogenyMethods { phy.externalNodesHaveChanged(); } + public final static List> divideIntoSubTrees( final Phylogeny phy, + final double min_distance_to_root ) { + if ( min_distance_to_root <= 0 ) { + throw new IllegalArgumentException( "attempt to use min distance to root of: " + min_distance_to_root ); + } + final List> l = new ArrayList>(); + setAllIndicatorsToZero( phy ); + for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) { + final PhylogenyNode n = it.next(); + if ( n.getIndicator() != 0 ) { + continue; + } + l.add( divideIntoSubTreesHelper( n, min_distance_to_root ) ); + if ( l.isEmpty() ) { + throw new RuntimeException( "this should not have happened" ); + } + } + return l; + } + public static List getAllDescendants( final PhylogenyNode node ) { final List descs = new ArrayList(); - final Set encountered = new HashSet(); + final Set encountered = new HashSet(); if ( !node.isExternal() ) { final List exts = node.getAllExternalDescendants(); for( PhylogenyNode current : exts ) { @@ -700,39 +728,6 @@ public class PhylogenyMethods { phylogeny.recalculateNumberOfExternalDescendants( true ); } - public static void midpointRootOLD( final Phylogeny phylogeny ) { - // if ( phylogeny.getNumberOfExternalNodes() < 2 ) { - // return; - // } - // final PhylogenyMethods methods = getInstance(); - //final double farthest_d = methods.calculateFurthestDistance( phylogeny ); - // final PhylogenyNode f1 = methods.getFarthestNode1(); - // final PhylogenyNode f2 = methods.getFarthestNode2(); - // if ( farthest_d <= 0.0 ) { - // return; - // } - // double x = farthest_d / 2.0; - // PhylogenyNode n = f1; - // if ( PhylogenyMethods.getDistance( f1, phylogeny.getRoot() ) < PhylogenyMethods.getDistance( f2, phylogeny - // .getRoot() ) ) { - // n = f2; - // } - // while ( ( x > n.getDistanceToParent() ) && !n.isRoot() ) { - // x -= ( n.getDistanceToParent() > 0 ? n.getDistanceToParent() : 0 ); - // n = n.getParent(); - // } - // phylogeny.reRoot( n, x ); - // phylogeny.recalculateNumberOfExternalDescendants( true ); - // final PhylogenyNode a = getFurthestDescendant( phylogeny.getRoot().getChildNode1() ); - // final PhylogenyNode b = getFurthestDescendant( phylogeny.getRoot().getChildNode2() ); - // final double da = getDistance( a, phylogeny.getRoot() ); - // final double db = getDistance( b, phylogeny.getRoot() ); - // if ( Math.abs( da - db ) > 0.000001 ) { - // throw new FailedConditionCheckException( "this should not have happened: midpoint rooting failed: da=" - // + da + ", db=" + db + ", diff=" + Math.abs( da - db ) ); - // } - } - public static void normalizeBootstrapValues( final Phylogeny phylogeny, final double max_bootstrap_value, final double max_normalized_value ) { @@ -764,34 +759,15 @@ public class PhylogenyMethods { } /** - * Returns the set of distinct taxonomies of - * all external nodes of node. - * If at least one the external nodes has no taxonomy, - * null is returned. - * - */ - public static Set obtainDistinctTaxonomies( final PhylogenyNode node ) { - final List descs = node.getAllExternalDescendants(); - final Set tax_set = new HashSet(); - for( final PhylogenyNode n : descs ) { - if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) { - return null; - } - tax_set.add( n.getNodeData().getTaxonomy() ); - } - return tax_set; - } - - /** * Returns a map of distinct taxonomies of * all external nodes of node. * If at least one of the external nodes has no taxonomy, * null is returned. * */ - public static SortedMap obtainDistinctTaxonomyCounts( final PhylogenyNode node ) { + public static Map obtainDistinctTaxonomyCounts( final PhylogenyNode node ) { final List descs = node.getAllExternalDescendants(); - final SortedMap tax_map = new TreeMap(); + final Map tax_map = new HashMap(); for( final PhylogenyNode n : descs ) { if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) { return null; @@ -882,7 +858,7 @@ public class PhylogenyMethods { return; } phy.setIdToNodeMap( null ); - int i = PhylogenyNode.getNodeCount(); + long i = PhylogenyNode.getNodeCount(); for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) { it.next().setId( i++ ); } @@ -913,20 +889,19 @@ public class PhylogenyMethods { } public static void removeNode( final PhylogenyNode remove_me, final Phylogeny phylogeny ) { - if ( remove_me.isRoot() && remove_me.getNumberOfDescendants() != 1 ) { - throw new IllegalArgumentException( "attempt to remove a root node with more than one descendants" ); - } - - if ( remove_me.isRoot() && remove_me.getNumberOfDescendants() == 1 ) { - final PhylogenyNode desc = remove_me.getDescendants().get( 0 ); - - desc.setDistanceToParent( addPhylogenyDistances( remove_me.getDistanceToParent(), - desc.getDistanceToParent() ) ); - desc.setParent( null ); - phylogeny.setRoot( desc ); - phylogeny.clearHashIdToNodeMap(); + if ( remove_me.isRoot() ) { + if ( remove_me.getNumberOfDescendants() == 1 ) { + final PhylogenyNode desc = remove_me.getDescendants().get( 0 ); + desc.setDistanceToParent( addPhylogenyDistances( remove_me.getDistanceToParent(), + desc.getDistanceToParent() ) ); + desc.setParent( null ); + phylogeny.setRoot( desc ); + phylogeny.clearHashIdToNodeMap(); + } + else { + throw new IllegalArgumentException( "attempt to remove a root node with more than one descendants" ); + } } - else if ( remove_me.isExternal() ) { phylogeny.deleteSubtree( remove_me, false ); phylogeny.clearHashIdToNodeMap(); @@ -999,6 +974,10 @@ public class PhylogenyMethods { match = true; } if ( !match && node.getNodeData().isHasSequence() + && match( node.getNodeData().getSequence().getGeneName(), query, case_sensitive, partial ) ) { + match = true; + } + if ( !match && node.getNodeData().isHasSequence() && match( node.getNodeData().getSequence().getSymbol(), query, case_sensitive, partial ) ) { match = true; } @@ -1021,6 +1000,38 @@ public class PhylogenyMethods { } } } + // + if ( !match && node.getNodeData().isHasSequence() + && ( node.getNodeData().getSequence().getAnnotations() != null ) ) { + for( final Annotation ann : node.getNodeData().getSequence().getAnnotations() ) { + if ( match( ann.getDesc(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( ann.getRef(), query, case_sensitive, partial ) ) { + match = true; + break; + } + } + } + if ( !match && node.getNodeData().isHasSequence() + && ( node.getNodeData().getSequence().getCrossReferences() != null ) ) { + for( final Accession x : node.getNodeData().getSequence().getCrossReferences() ) { + if ( match( x.getComment(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( x.getSource(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( x.getValue(), query, case_sensitive, partial ) ) { + match = true; + break; + } + } + } + // if ( !match && ( node.getNodeData().getBinaryCharacters() != null ) ) { Iterator it = node.getNodeData().getBinaryCharacters().getPresentCharacters().iterator(); I: while ( it.hasNext() ) { @@ -1099,6 +1110,10 @@ public class PhylogenyMethods { match = true; } if ( !match && node.getNodeData().isHasSequence() + && match( node.getNodeData().getSequence().getGeneName(), query, case_sensitive, partial ) ) { + match = true; + } + if ( !match && node.getNodeData().isHasSequence() && match( node.getNodeData().getSequence().getSymbol(), query, case_sensitive, partial ) ) { match = true; } @@ -1121,6 +1136,38 @@ public class PhylogenyMethods { } } } + // + if ( !match && node.getNodeData().isHasSequence() + && ( node.getNodeData().getSequence().getAnnotations() != null ) ) { + for( final Annotation ann : node.getNodeData().getSequence().getAnnotations() ) { + if ( match( ann.getDesc(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( ann.getRef(), query, case_sensitive, partial ) ) { + match = true; + break; + } + } + } + if ( !match && node.getNodeData().isHasSequence() + && ( node.getNodeData().getSequence().getCrossReferences() != null ) ) { + for( final Accession x : node.getNodeData().getSequence().getCrossReferences() ) { + if ( match( x.getComment(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( x.getSource(), query, case_sensitive, partial ) ) { + match = true; + break; + } + if ( match( x.getValue(), query, case_sensitive, partial ) ) { + match = true; + break; + } + } + } + // if ( !match && ( node.getNodeData().getBinaryCharacters() != null ) ) { Iterator it = node.getNodeData().getBinaryCharacters().getPresentCharacters().iterator(); I: while ( it.hasNext() ) { @@ -1149,6 +1196,12 @@ public class PhylogenyMethods { return nodes; } + public static void setAllIndicatorsToZero( final Phylogeny phy ) { + for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) { + it.next().setIndicator( ( byte ) 0 ); + } + } + /** * Convenience method. * Sets value for the first confidence value (created if not present, values overwritten otherwise). @@ -1252,6 +1305,11 @@ public class PhylogenyMethods { return n1.getNodeData().getSequence().getSymbol() .compareTo( n2.getNodeData().getSequence().getSymbol() ); } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) { + return n1.getNodeData().getSequence().getGeneName() + .compareTo( n2.getNodeData().getSequence().getGeneName() ); + } if ( ( n1.getNodeData().getSequence().getAccession() != null ) && ( n2.getNodeData().getSequence().getAccession() != null ) && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) @@ -1281,6 +1339,11 @@ public class PhylogenyMethods { return n1.getNodeData().getSequence().getSymbol() .compareTo( n2.getNodeData().getSequence().getSymbol() ); } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) { + return n1.getNodeData().getSequence().getGeneName() + .compareTo( n2.getNodeData().getSequence().getGeneName() ); + } if ( ( n1.getNodeData().getSequence().getAccession() != null ) && ( n2.getNodeData().getSequence().getAccession() != null ) && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) @@ -1347,6 +1410,11 @@ public class PhylogenyMethods { return n1.getNodeData().getSequence().getSymbol() .compareTo( n2.getNodeData().getSequence().getSymbol() ); } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) { + return n1.getNodeData().getSequence().getGeneName() + .compareTo( n2.getNodeData().getSequence().getGeneName() ); + } if ( ( n1.getNodeData().getSequence().getAccession() != null ) && ( n2.getNodeData().getSequence().getAccession() != null ) && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) @@ -1395,13 +1463,16 @@ public class PhylogenyMethods { if ( !n.getNodeData().isHasTaxonomy() ) { throw new IllegalArgumentException( "no taxonomic data in node: " + n ); } - // ref_ext_taxo.add( getSpecies( n ) ); if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) { ref_ext_taxo.add( n.getNodeData().getTaxonomy().getScientificName() ); } if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) { ref_ext_taxo.add( n.getNodeData().getTaxonomy().getTaxonomyCode() ); } + if ( ( n.getNodeData().getTaxonomy().getIdentifier() != null ) + && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getIdentifier().getValue() ) ) { + ref_ext_taxo.add( n.getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() ); + } } final ArrayList nodes_to_delete = new ArrayList(); for( final PhylogenyNodeIterator it = to_be_stripped.iteratorExternalForward(); it.hasNext(); ) { @@ -1410,7 +1481,9 @@ public class PhylogenyMethods { nodes_to_delete.add( n ); } else if ( !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getScientificName() ) ) - && !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) { + && !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) + && !( ( n.getNodeData().getTaxonomy().getIdentifier() != null ) && ref_ext_taxo.contains( n + .getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() ) ) ) { nodes_to_delete.add( n ); } } @@ -1566,6 +1639,24 @@ public class PhylogenyMethods { return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT; } + static double calculateDistanceToAncestor( final PhylogenyNode anc, PhylogenyNode desc ) { + double d = 0; + boolean all_default = true; + while ( anc != desc ) { + if ( desc.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) { + d += desc.getDistanceToParent(); + if ( all_default ) { + all_default = false; + } + } + desc = desc.getParent(); + } + if ( all_default ) { + return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT; + } + return d; + } + /** * Deep copies the phylogeny originating from this node. */ @@ -1602,6 +1693,20 @@ public class PhylogenyMethods { } } + private final static List divideIntoSubTreesHelper( final PhylogenyNode node, + final double min_distance_to_root ) { + final List l = new ArrayList(); + final PhylogenyNode r = moveTowardsRoot( node, min_distance_to_root ); + for( final PhylogenyNode ext : r.getAllExternalDescendants() ) { + if ( ext.getIndicator() != 0 ) { + throw new RuntimeException( "this should not have happened" ); + } + ext.setIndicator( ( byte ) 1 ); + l.add( ext ); + } + return l; + } + /** * Calculates the distance between PhylogenyNodes n1 and n2. * PRECONDITION: n1 is a descendant of n2. @@ -1639,23 +1744,33 @@ public class PhylogenyMethods { return my_s.indexOf( my_query ) >= 0; } else { - return my_s.equals( my_query ); + return Pattern.compile( "(\\b|_)" + Pattern.quote( my_query ) + "(\\b|_)" ).matcher( my_s ).find(); + } + } + + private final static PhylogenyNode moveTowardsRoot( final PhylogenyNode node, final double min_distance_to_root ) { + PhylogenyNode n = node; + PhylogenyNode prev = node; + while ( min_distance_to_root < n.calculateDistanceToRoot() ) { + prev = n; + n = n.getParent(); } + return prev; } public static enum DESCENDANT_SORT_PRIORITY { - TAXONOMY, SEQUENCE, NODE_NAME; + NODE_NAME, SEQUENCE, TAXONOMY; } public static enum PhylogenyNodeField { CLADE_NAME, + SEQUENCE_NAME, + SEQUENCE_SYMBOL, TAXONOMY_CODE, - TAXONOMY_SCIENTIFIC_NAME, TAXONOMY_COMMON_NAME, - SEQUENCE_SYMBOL, - SEQUENCE_NAME, + TAXONOMY_ID, TAXONOMY_ID_UNIPROT_1, TAXONOMY_ID_UNIPROT_2, - TAXONOMY_ID; + TAXONOMY_SCIENTIFIC_NAME; } }