X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=forester%2Fjava%2Fsrc%2Forg%2Fforester%2Fphylogeny%2FPhylogenyMethods.java;h=f839fd6ce43d34017dfff00a7164d9f2a2843304;hb=5b11e68cf46c363bd5ae256f794871c194776bd7;hp=7835d6215a3a1f6294cb1d210bcfe3e27d0efdc3;hpb=6be89aad9f2003c1b2bb4a9e6581ac3537d556c2;p=jalview.git diff --git a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java index 7835d62..f839fd6 100644 --- a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java +++ b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java @@ -31,6 +31,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -39,12 +41,14 @@ import java.util.SortedMap; import java.util.TreeMap; 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.BranchColor; import org.forester.phylogeny.data.BranchWidth; import org.forester.phylogeny.data.Confidence; import org.forester.phylogeny.data.DomainArchitecture; +import org.forester.phylogeny.data.Event; import org.forester.phylogeny.data.Identifier; import org.forester.phylogeny.data.PhylogenyDataUtil; import org.forester.phylogeny.data.Sequence; @@ -59,10 +63,9 @@ import org.forester.util.ForesterUtil; public class PhylogenyMethods { - private static PhylogenyMethods _instance = null; - private final Set _temp_hash_set = new HashSet(); - private PhylogenyNode _farthest_1 = null; - private PhylogenyNode _farthest_2 = null; + private static PhylogenyMethods _instance = null; + private PhylogenyNode _farthest_1 = null; + private PhylogenyNode _farthest_2 = null; private PhylogenyMethods() { // Hidden constructor. @@ -77,7 +80,7 @@ public class PhylogenyMethods { * @return distance between node1 and node2 */ public double calculateDistance( final PhylogenyNode node1, final PhylogenyNode node2 ) { - final PhylogenyNode lca = obtainLCA( node1, node2 ); + final PhylogenyNode lca = calculateLCA( node1, node2 ); final PhylogenyNode n1 = node1; final PhylogenyNode n2 = node2; return ( PhylogenyMethods.getDistance( n1, lca ) + PhylogenyMethods.getDistance( n2, lca ) ); @@ -112,6 +115,10 @@ public class PhylogenyMethods { return farthest_d; } + final public static Event getEventAtLCA( final PhylogenyNode n1, final PhylogenyNode n2 ) { + return calculateLCA( n1, n2 ).getNodeData().getEvent(); + } + @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); @@ -125,6 +132,24 @@ public class PhylogenyMethods { return _farthest_2; } + final public static void deleteNonOrthologousExternalNodes( final Phylogeny phy, final PhylogenyNode n ) { + if ( n.isInternal() ) { + throw new IllegalArgumentException( "node is not external" ); + } + final ArrayList to_delete = new ArrayList(); + for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) { + final PhylogenyNode i = it.next(); + if ( !PhylogenyMethods.getEventAtLCA( n, i ).isSpeciation() ) { + to_delete.add( i ); + } + } + for( final PhylogenyNode d : to_delete ) { + phy.deleteSubtree( d, true ); + } + phy.clearHashIdToNodeMap(); + phy.externalNodesHaveChanged(); + } + /** * Returns the LCA of PhylogenyNodes node1 and node2. * @@ -133,22 +158,80 @@ public class PhylogenyMethods { * @param node2 * @return LCA of node1 and node2 */ - public PhylogenyNode obtainLCA( final PhylogenyNode node1, final PhylogenyNode node2 ) { - _temp_hash_set.clear(); - PhylogenyNode n1 = node1; - PhylogenyNode n2 = node2; - _temp_hash_set.add( n1.getId() ); - while ( !n1.isRoot() ) { - n1 = n1.getParent(); - _temp_hash_set.add( n1.getId() ); + public final static PhylogenyNode calculateLCA( PhylogenyNode node1, PhylogenyNode node2 ) { + if ( node1 == null ) { + throw new IllegalArgumentException( "first argument (node) is null" ); + } + if ( node2 == null ) { + throw new IllegalArgumentException( "second argument (node) is null" ); } - while ( !_temp_hash_set.contains( n2.getId() ) && !n2.isRoot() ) { - n2 = n2.getParent(); + if ( node1 == node2 ) { + return node1; } - if ( !_temp_hash_set.contains( n2.getId() ) ) { - throw new IllegalArgumentException( "attempt to get LCA of two nodes which do not share a common root" ); + if ( ( node1.getParent() == node2.getParent() ) ) { + return node1.getParent(); } - return n2; + int depth1 = node1.calculateDepth(); + int depth2 = node2.calculateDepth(); + while ( ( depth1 > -1 ) && ( depth2 > -1 ) ) { + if ( depth1 > depth2 ) { + node1 = node1.getParent(); + depth1--; + } + else if ( depth2 > depth1 ) { + node2 = node2.getParent(); + depth2--; + } + else { + if ( node1 == node2 ) { + return node1; + } + node1 = node1.getParent(); + node2 = node2.getParent(); + depth1--; + depth2--; + } + } + throw new IllegalArgumentException( "illegal attempt to calculate LCA of two nodes which do not share a common root" ); + } + + public static final void preOrderReId( final Phylogeny phy ) { + if ( phy.isEmpty() ) { + return; + } + phy.setIdToNodeMap( null ); + int i = PhylogenyNode.getNodeCount(); + for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) { + it.next().setId( i++ ); + } + PhylogenyNode.setNodeCount( i ); + } + + /** + * Returns the LCA of PhylogenyNodes node1 and node2. + * Precondition: ids are in pre-order (or level-order). + * + * + * @param node1 + * @param node2 + * @return LCA of node1 and node2 + */ + public final static PhylogenyNode calculateLCAonTreeWithIdsInPreOrder( PhylogenyNode node1, PhylogenyNode node2 ) { + if ( node1 == null ) { + throw new IllegalArgumentException( "first argument (node) is null" ); + } + if ( node2 == null ) { + throw new IllegalArgumentException( "second argument (node) is null" ); + } + while ( node1 != node2 ) { + if ( node1.getId() > node2.getId() ) { + node1 = node1.getParent(); + } + else { + node2 = node2.getParent(); + } + } + return node1; } /** @@ -165,20 +248,26 @@ public class PhylogenyMethods { * of this Phylogeny, null if this Phylogeny is empty or if n is * internal */ - public List getOrthologousNodes( final Phylogeny phy, final PhylogenyNode node ) { + public final static List getOrthologousNodes( final Phylogeny phy, final PhylogenyNode node ) { final List nodes = new ArrayList(); + PhylogenyMethods.preOrderReId( phy ); final PhylogenyNodeIterator it = phy.iteratorExternalForward(); while ( it.hasNext() ) { final PhylogenyNode temp_node = it.next(); - if ( ( temp_node != node ) && isAreOrthologous( node, temp_node ) ) { + if ( ( temp_node != node ) && !calculateLCAonTreeWithIdsInPreOrder( node, temp_node ).isDuplication() ) { nodes.add( temp_node ); } } return nodes; } - public boolean isAreOrthologous( final PhylogenyNode node1, final PhylogenyNode node2 ) { - return !obtainLCA( node1, node2 ).isDuplication(); + 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(); + nodes.put( n.getName(), n ); + } + return nodes; } public final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final File file ) throws IOException { @@ -190,6 +279,20 @@ public class PhylogenyMethods { return trees; } + public final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final List files ) + throws IOException { + final List tree_list = new ArrayList(); + for( final File file : files ) { + final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); + final Phylogeny[] trees = factory.create( file, parser ); + if ( ( trees == null ) || ( trees.length == 0 ) ) { + throw new PhylogenyParserException( "Unable to parse phylogeny from file: " + file ); + } + tree_list.addAll( Arrays.asList( trees ) ); + } + return tree_list.toArray( new Phylogeny[ tree_list.size() ] ); + } + final static public void transferInternalNodeNamesToConfidence( final Phylogeny phy ) { final PhylogenyNodeIterator it = phy.iteratorPostorder(); while ( it.hasNext() ) { @@ -232,41 +335,178 @@ public class PhylogenyMethods { } } } - - - - final static public void sortNodeDescendents( PhylogenyNode node ) { + + final static public void sortNodeDescendents( final PhylogenyNode node, final DESCENDANT_SORT_PRIORITY pri ) { + class PhylogenyNodeSortTaxonomyPriority implements Comparator { + + @Override + public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) { + if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) { + return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) { + return n1.getNodeData().getTaxonomy().getTaxonomyCode() + .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getCommonName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getCommonName() ) ) ) { + return n1.getNodeData().getTaxonomy().getCommonName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getCommonName().toLowerCase() ); + } + } + if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) { + return n1.getNodeData().getSequence().getName().toLowerCase() + .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) { + return n1.getNodeData().getSequence().getSymbol() + .compareTo( n2.getNodeData().getSequence().getSymbol() ); + } + if ( ( n1.getNodeData().getSequence().getAccession() != null ) + && ( n2.getNodeData().getSequence().getAccession() != null ) + && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) + && !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getAccession().getValue() ) ) { + return n1.getNodeData().getSequence().getAccession().getValue() + .compareTo( n2.getNodeData().getSequence().getAccession().getValue() ); + } + } + if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) { + return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() ); + } + return 0; + } + } + class PhylogenyNodeSortSequencePriority implements Comparator { + + @Override + public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) { + if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) { + return n1.getNodeData().getSequence().getName().toLowerCase() + .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) { + return n1.getNodeData().getSequence().getSymbol() + .compareTo( n2.getNodeData().getSequence().getSymbol() ); + } + if ( ( n1.getNodeData().getSequence().getAccession() != null ) + && ( n2.getNodeData().getSequence().getAccession() != null ) + && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) + && !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getAccession().getValue() ) ) { + return n1.getNodeData().getSequence().getAccession().getValue() + .compareTo( n2.getNodeData().getSequence().getAccession().getValue() ); + } + } + if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) { + return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) { + return n1.getNodeData().getTaxonomy().getTaxonomyCode() + .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getCommonName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getCommonName() ) ) ) { + return n1.getNodeData().getTaxonomy().getCommonName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getCommonName().toLowerCase() ); + } + } + if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) { + return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() ); + } + return 0; + } + } + class PhylogenyNodeSortNodeNamePriority implements Comparator { + + @Override + public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) { + if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) { + return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() ); + } + if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) { + return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) { + return n1.getNodeData().getTaxonomy().getTaxonomyCode() + .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getCommonName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getCommonName() ) ) ) { + return n1.getNodeData().getTaxonomy().getCommonName().toLowerCase() + .compareTo( n2.getNodeData().getTaxonomy().getCommonName().toLowerCase() ); + } + } + if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) { + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) { + return n1.getNodeData().getSequence().getName().toLowerCase() + .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() ); + } + if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) ) + && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) { + return n1.getNodeData().getSequence().getSymbol() + .compareTo( n2.getNodeData().getSequence().getSymbol() ); + } + if ( ( n1.getNodeData().getSequence().getAccession() != null ) + && ( n2.getNodeData().getSequence().getAccession() != null ) + && !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getAccession().getValue() ) + && !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getAccession().getValue() ) ) { + return n1.getNodeData().getSequence().getAccession().getValue() + .compareTo( n2.getNodeData().getSequence().getAccession().getValue() ); + } + } + return 0; + } + } + Comparator c; + switch ( pri ) { + case SEQUENCE: + c = new PhylogenyNodeSortSequencePriority(); + break; + case NODE_NAME: + c = new PhylogenyNodeSortNodeNamePriority(); + break; + default: + c = new PhylogenyNodeSortTaxonomyPriority(); + } final List descs = node.getDescendants(); - // Collections.sort( arg0, comparator ); - Collections.sort( descs ); - + Collections.sort( descs, c ); int i = 0; - for( PhylogenyNode desc : descs ) { + for( final PhylogenyNode desc : descs ) { node.setChildNode( i++, desc ); } - } - final static public void transferNodeNameToField( final Phylogeny phy, - final PhylogenyMethods.PhylogenyNodeField field ) { + final PhylogenyMethods.PhylogenyNodeField field, + final boolean external_only ) throws PhyloXmlDataFormatException { final PhylogenyNodeIterator it = phy.iteratorPostorder(); while ( it.hasNext() ) { final PhylogenyNode n = it.next(); + if ( external_only && n.isInternal() ) { + continue; + } final String name = n.getName().trim(); if ( !ForesterUtil.isEmpty( name ) ) { switch ( field ) { case TAXONOMY_CODE: - //temp hack - // if ( name.length() > 5 ) { - // n.setName( "" ); - // if ( !n.getNodeData().isHasTaxonomy() ) { - // n.getNodeData().setTaxonomy( new Taxonomy() ); - // } - // n.getNodeData().getTaxonomy().setScientificName( name ); - // break; - // } - // n.setName( "" ); setTaxonomyCode( n, name ); break; @@ -330,6 +570,13 @@ public class PhylogenyMethods { .setIdentifier( new Identifier( id, PhyloXmlUtil.UNIPROT_TAX_PROVIDER ) ); break; } + case TAXONOMY_ID: { + if ( !n.getNodeData().isHasTaxonomy() ) { + n.getNodeData().setTaxonomy( new Taxonomy() ); + } + n.getNodeData().getTaxonomy().setIdentifier( new Identifier( name ) ); + break; + } } } } @@ -348,16 +595,14 @@ public class PhylogenyMethods { return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT; } - // Helper for getUltraParalogousNodes( PhylogenyNode ). - public static boolean areAllChildrenDuplications( final PhylogenyNode n ) { + public final static boolean isAllDecendentsAreDuplications( final PhylogenyNode n ) { if ( n.isExternal() ) { - return false; + return true; } else { if ( n.isDuplication() ) { - //FIXME test me! for( final PhylogenyNode desc : n.getDescendants() ) { - if ( !areAllChildrenDuplications( desc ) ) { + if ( !isAllDecendentsAreDuplications( desc ) ) { return false; } } @@ -369,28 +614,6 @@ public class PhylogenyMethods { } } - public static int calculateDepth( final PhylogenyNode node ) { - PhylogenyNode n = node; - int steps = 0; - while ( !n.isRoot() ) { - steps++; - n = n.getParent(); - } - return steps; - } - - public static double calculateDistanceToRoot( final PhylogenyNode node ) { - PhylogenyNode n = node; - double d = 0.0; - while ( !n.isRoot() ) { - if ( n.getDistanceToParent() > 0.0 ) { - d += n.getDistanceToParent(); - } - n = n.getParent(); - } - return d; - } - public static short calculateMaxBranchesToLeaf( final PhylogenyNode node ) { if ( node.isExternal() ) { return 0; @@ -418,7 +641,7 @@ public class PhylogenyMethods { int max = 0; for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) { final PhylogenyNode node = iter.next(); - final int steps = calculateDepth( node ); + final int steps = node.calculateDepth(); if ( steps > max ) { max = steps; } @@ -430,7 +653,7 @@ public class PhylogenyMethods { double max = 0.0; for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) { final PhylogenyNode node = iter.next(); - final double d = calculateDistanceToRoot( node ); + final double d = node.calculateDistanceToRoot(); if ( d > max ) { max = d; } @@ -438,6 +661,17 @@ public class PhylogenyMethods { return max; } + public static int countNumberOfPolytomies( final Phylogeny phy ) { + int count = 0; + for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode n = iter.next(); + if ( !n.isExternal() && ( n.getNumberOfDescendants() > 2 ) ) { + count++; + } + } + return count; + } + public static DescriptiveStatistics calculatNumberOfDescendantsPerNodeStatistics( final Phylogeny phy ) { final DescriptiveStatistics stats = new BasicDescriptiveStatistics(); for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { @@ -449,13 +683,39 @@ public class PhylogenyMethods { return stats; } - public static DescriptiveStatistics calculatConfidenceStatistics( final Phylogeny phy ) { + public static DescriptiveStatistics calculatBranchLengthStatistics( final Phylogeny phy ) { final DescriptiveStatistics stats = new BasicDescriptiveStatistics(); for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { final PhylogenyNode n = iter.next(); - if ( !n.isExternal() ) { + if ( !n.isRoot() && ( n.getDistanceToParent() >= 0.0 ) ) { + stats.addValue( n.getDistanceToParent() ); + } + } + return stats; + } + + public static List calculatConfidenceStatistics( final Phylogeny phy ) { + final List stats = new ArrayList(); + for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode n = iter.next(); + if ( !n.isExternal() && !n.isRoot() ) { if ( n.getBranchData().isHasConfidences() ) { - stats.addValue( n.getBranchData().getConfidence( 0 ).getValue() ); + for( int i = 0; i < n.getBranchData().getConfidences().size(); ++i ) { + final Confidence c = n.getBranchData().getConfidences().get( i ); + if ( ( i > ( stats.size() - 1 ) ) || ( stats.get( i ) == null ) ) { + stats.add( i, new BasicDescriptiveStatistics() ); + } + if ( !ForesterUtil.isEmpty( c.getType() ) ) { + if ( !ForesterUtil.isEmpty( stats.get( i ).getDescription() ) ) { + if ( !stats.get( i ).getDescription().equalsIgnoreCase( c.getType() ) ) { + throw new IllegalArgumentException( "support values in node [" + n.toString() + + "] appear inconsistently ordered" ); + } + } + stats.get( i ).setDescription( c.getType() ); + } + stats.get( i ).addValue( ( ( c != null ) && ( c.getValue() >= 0 ) ) ? c.getValue() : 0 ); + } } } } @@ -554,31 +814,33 @@ public class PhylogenyMethods { } public static void deleteExternalNodesNegativeSelection( final Set to_delete, final Phylogeny phy ) { - phy.hashIDs(); + phy.clearHashIdToNodeMap(); for( final Integer id : to_delete ) { phy.deleteSubtree( phy.getNode( id ), true ); } - phy.hashIDs(); + phy.clearHashIdToNodeMap(); + phy.externalNodesHaveChanged(); } public static void deleteExternalNodesNegativeSelection( final String[] node_names_to_delete, final Phylogeny p ) throws IllegalArgumentException { - for( int i = 0; i < node_names_to_delete.length; ++i ) { - if ( ForesterUtil.isEmpty( node_names_to_delete[ i ] ) ) { + for( final String element : node_names_to_delete ) { + if ( ForesterUtil.isEmpty( element ) ) { continue; } List nodes = null; - nodes = p.getNodes( node_names_to_delete[ i ] ); + nodes = p.getNodes( element ); final Iterator it = nodes.iterator(); while ( it.hasNext() ) { final PhylogenyNode n = it.next(); if ( !n.isExternal() ) { - throw new IllegalArgumentException( "attempt to delete non-external node \"" - + node_names_to_delete[ i ] + "\"" ); + throw new IllegalArgumentException( "attempt to delete non-external node \"" + element + "\"" ); } p.deleteSubtree( n, true ); } } + p.clearHashIdToNodeMap(); + p.externalNodesHaveChanged(); } public static void deleteExternalNodesPositiveSelection( final Set species_to_keep, final Phylogeny phy ) { @@ -595,9 +857,8 @@ public class PhylogenyMethods { throw new IllegalArgumentException( "node " + n.getId() + " has no taxonomic data" ); } } - phy.hashIDs(); + phy.clearHashIdToNodeMap(); phy.externalNodesHaveChanged(); - // deleteExternalNodesNegativeSelection( to_delete, phy ); } public static List deleteExternalNodesPositiveSelection( final String[] node_names_to_keep, @@ -791,12 +1052,12 @@ public class PhylogenyMethods { if ( !node.getNodeData().isHasTaxonomy() ) { return ""; } - if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) { - return node.getNodeData().getTaxonomy().getTaxonomyCode(); - } else if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) { return node.getNodeData().getTaxonomy().getScientificName(); } + if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) { + return node.getNodeData().getTaxonomy().getTaxonomyCode(); + } else { return node.getNodeData().getTaxonomy().getCommonName(); } @@ -814,13 +1075,14 @@ public class PhylogenyMethods { * @param n * external PhylogenyNode whose strictly speciation related Nodes * are to be returned - * @return Vector of references to all strictly speciation related Nodes of + * @return References to all strictly speciation related Nodes of * PhylogenyNode n of this Phylogeny, null if this Phylogeny is * empty or if n is internal */ public static List getSuperOrthologousNodes( final PhylogenyNode n ) { // FIXME - PhylogenyNode node = n, deepest = null; + PhylogenyNode node = n; + PhylogenyNode deepest = null; final List v = new ArrayList(); if ( !node.isExternal() ) { return null; @@ -897,9 +1159,9 @@ public class PhylogenyMethods { // FIXME test me PhylogenyNode node = n; if ( !node.isExternal() ) { - return null; + throw new IllegalArgumentException( "attempt to get ultra-paralogous nodes of internal node" ); } - while ( !node.isRoot() && node.getParent().isDuplication() && areAllChildrenDuplications( node.getParent() ) ) { + while ( !node.isRoot() && node.getParent().isDuplication() && isAllDecendentsAreDuplications( node.getParent() ) ) { node = node.getParent(); } final List nodes = node.getAllExternalDescendants(); @@ -907,42 +1169,6 @@ public class PhylogenyMethods { return nodes; } - public static String inferCommonPartOfScientificNameOfDescendants( final PhylogenyNode node ) { - final List descs = node.getDescendants(); - String sn = null; - for( final PhylogenyNode n : descs ) { - if ( !n.getNodeData().isHasTaxonomy() - || ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) { - return null; - } - else if ( sn == null ) { - sn = n.getNodeData().getTaxonomy().getScientificName().trim(); - } - else { - String sn_current = n.getNodeData().getTaxonomy().getScientificName().trim(); - if ( !sn.equals( sn_current ) ) { - boolean overlap = false; - while ( ( sn.indexOf( ' ' ) >= 0 ) || ( sn_current.indexOf( ' ' ) >= 0 ) ) { - if ( ForesterUtil.countChars( sn, ' ' ) > ForesterUtil.countChars( sn_current, ' ' ) ) { - sn = sn.substring( 0, sn.lastIndexOf( ' ' ) ).trim(); - } - else { - sn_current = sn_current.substring( 0, sn_current.lastIndexOf( ' ' ) ).trim(); - } - if ( sn.equals( sn_current ) ) { - overlap = true; - break; - } - } - if ( !overlap ) { - return null; - } - } - } - } - return sn; - } - public static boolean isHasExternalDescendant( final PhylogenyNode node ) { for( int i = 0; i < node.getNumberOfDescendants(); ++i ) { if ( node.getChildNode( i ).isExternal() ) { @@ -1064,8 +1290,9 @@ public class PhylogenyMethods { double blue = 0.0; int n = 0; if ( node.isInternal() ) { - for( final PhylogenyNodeIterator iterator = node.iterateChildNodesForward(); iterator.hasNext(); ) { - final PhylogenyNode child_node = iterator.next(); + //for( final PhylogenyNodeIterator iterator = node.iterateChildNodesForward(); iterator.hasNext(); ) { + for( int i = 0; i < node.getNumberOfDescendants(); ++i ) { + final PhylogenyNode child_node = node.getChildNode( i ); final Color child_color = getBranchColorValue( child_node ); if ( child_color != null ) { ++n; @@ -1088,6 +1315,8 @@ public class PhylogenyMethods { } if ( remove_me.isExternal() ) { phylogeny.deleteSubtree( remove_me, false ); + phylogeny.clearHashIdToNodeMap(); + phylogeny.externalNodesHaveChanged(); } else { final PhylogenyNode parent = remove_me.getParent(); @@ -1099,7 +1328,7 @@ public class PhylogenyMethods { desc.getDistanceToParent() ) ); } remove_me.setParent( null ); - phylogeny.setIdHash( null ); + phylogeny.clearHashIdToNodeMap(); phylogeny.externalNodesHaveChanged(); } } @@ -1107,7 +1336,8 @@ public class PhylogenyMethods { public static List searchData( final String query, final Phylogeny phy, final boolean case_sensitive, - final boolean partial ) { + final boolean partial, + final boolean search_domains ) { final List nodes = new ArrayList(); if ( phy.isEmpty() || ( query == null ) ) { return nodes; @@ -1167,7 +1397,7 @@ public class PhylogenyMethods { partial ) ) { match = true; } - if ( !match && node.getNodeData().isHasSequence() + if ( search_domains && !match && node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) { final DomainArchitecture da = node.getNodeData().getSequence().getDomainArchitecture(); I: for( int i = 0; i < da.getNumberOfDomains(); ++i ) { @@ -1203,7 +1433,8 @@ public class PhylogenyMethods { public static List searchDataLogicalAnd( final String[] queries, final Phylogeny phy, final boolean case_sensitive, - final boolean partial ) { + final boolean partial, + final boolean search_domains ) { final List nodes = new ArrayList(); if ( phy.isEmpty() || ( queries == null ) || ( queries.length < 1 ) ) { return nodes; @@ -1266,7 +1497,7 @@ public class PhylogenyMethods { partial ) ) { match = true; } - if ( !match && node.getNodeData().isHasSequence() + if ( search_domains && !match && node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) { final DomainArchitecture da = node.getNodeData().getSequence().getDomainArchitecture(); I: for( int i = 0; i < da.getNumberOfDomains(); ++i ) { @@ -1291,22 +1522,6 @@ public class PhylogenyMethods { break I; } } - // final String[] bcp_ary = node.getNodeData().getBinaryCharacters() - // .getPresentCharactersAsStringArray(); - // I: for( final String bc : bcp_ary ) { - // if ( match( bc, query, case_sensitive, partial ) ) { - // match = true; - // break I; - // } - // } - // final String[] bcg_ary = node.getNodeData().getBinaryCharacters() - // .getGainedCharactersAsStringArray(); - // I: for( final String bc : bcg_ary ) { - // if ( match( bc, query, case_sensitive, partial ) ) { - // match = true; - // break I; - // } - // } } if ( !match ) { all_matched = false; @@ -1380,8 +1595,10 @@ public class PhylogenyMethods { * * @param node * @param taxonomy_code + * @throws PhyloXmlDataFormatException */ - public static void setTaxonomyCode( final PhylogenyNode node, final String taxonomy_code ) { + public static void setTaxonomyCode( final PhylogenyNode node, final String taxonomy_code ) + throws PhyloXmlDataFormatException { if ( !node.getNodeData().isHasTaxonomy() ) { node.getNodeData().setTaxonomy( new Taxonomy() ); } @@ -1400,22 +1617,81 @@ public class PhylogenyMethods { */ public static int taxonomyBasedDeletionOfExternalNodes( final Phylogeny reference, final Phylogeny to_be_stripped ) { final Set ref_ext_taxo = new HashSet(); - final ArrayList nodes_to_delete = new ArrayList(); for( final PhylogenyNodeIterator it = reference.iteratorExternalForward(); it.hasNext(); ) { - ref_ext_taxo.add( getSpecies( it.next() ) ); + final PhylogenyNode n = it.next(); + 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() ); + } } + final ArrayList nodes_to_delete = new ArrayList(); for( final PhylogenyNodeIterator it = to_be_stripped.iteratorExternalForward(); it.hasNext(); ) { final PhylogenyNode n = it.next(); - if ( !ref_ext_taxo.contains( getSpecies( n ) ) ) { + if ( !n.getNodeData().isHasTaxonomy() ) { + nodes_to_delete.add( n ); + } + else if ( !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getScientificName() ) ) + && !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) { nodes_to_delete.add( n ); } } for( final PhylogenyNode phylogenyNode : nodes_to_delete ) { to_be_stripped.deleteSubtree( phylogenyNode, true ); } + to_be_stripped.clearHashIdToNodeMap(); + to_be_stripped.externalNodesHaveChanged(); return nodes_to_delete.size(); } + /** + * Arranges the order of childern for each node of this Phylogeny in such a + * way that either the branch with more children is on top (right) or on + * bottom (left), dependent on the value of boolean order. + * + * @param order + * decides in which direction to order + * @param pri + */ + public static void orderAppearance( final PhylogenyNode n, + final boolean order, + final boolean order_ext_alphabetically, + final DESCENDANT_SORT_PRIORITY pri ) { + if ( n.isExternal() ) { + return; + } + else { + PhylogenyNode temp = null; + if ( ( n.getNumberOfDescendants() == 2 ) + && ( n.getChildNode1().getNumberOfExternalNodes() != n.getChildNode2().getNumberOfExternalNodes() ) + && ( ( n.getChildNode1().getNumberOfExternalNodes() < n.getChildNode2().getNumberOfExternalNodes() ) == order ) ) { + temp = n.getChildNode1(); + n.setChild1( n.getChildNode2() ); + n.setChild2( temp ); + } + else if ( order_ext_alphabetically ) { + boolean all_ext = true; + for( final PhylogenyNode i : n.getDescendants() ) { + if ( !i.isExternal() ) { + all_ext = false; + break; + } + } + if ( all_ext ) { + PhylogenyMethods.sortNodeDescendents( n, pri ); + } + } + for( int i = 0; i < n.getNumberOfDescendants(); ++i ) { + orderAppearance( n.getChildNode( i ), order, order_ext_alphabetically, pri ); + } + } + } + public static enum PhylogenyNodeField { CLADE_NAME, TAXONOMY_CODE, @@ -1424,10 +1700,11 @@ public class PhylogenyMethods { SEQUENCE_SYMBOL, SEQUENCE_NAME, TAXONOMY_ID_UNIPROT_1, - TAXONOMY_ID_UNIPROT_2; + TAXONOMY_ID_UNIPROT_2, + TAXONOMY_ID; } - public static enum TAXONOMY_EXTRACTION { - NO, YES, PFAM_STYLE_ONLY; + public static enum DESCENDANT_SORT_PRIORITY { + TAXONOMY, SEQUENCE, NODE_NAME; } }