taxonomy code more stringent now
[jalview.git] / forester / java / src / org / forester / phylogeny / PhylogenyMethods.java
index 0d404e8..01a4ab6 100644 (file)
@@ -30,6 +30,8 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -38,6 +40,7 @@ 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;
@@ -45,6 +48,7 @@ import org.forester.phylogeny.data.BranchWidth;
 import org.forester.phylogeny.data.Confidence;
 import org.forester.phylogeny.data.DomainArchitecture;
 import org.forester.phylogeny.data.Identifier;
+import org.forester.phylogeny.data.PhylogenyDataUtil;
 import org.forester.phylogeny.data.Sequence;
 import org.forester.phylogeny.data.Taxonomy;
 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
@@ -188,11 +192,25 @@ public class PhylogenyMethods {
         return trees;
     }
 
+    public final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final List<File> files )
+            throws IOException {
+        final List<Phylogeny> tree_list = new ArrayList<Phylogeny>();
+        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() ) {
             final PhylogenyNode n = it.next();
-            if ( !n.isRoot() && !n.isExternal() && !n.getBranchData().isHasConfidences() ) {
+            if ( !n.isExternal() && !n.getBranchData().isHasConfidences() ) {
                 if ( !ForesterUtil.isEmpty( n.getName() ) ) {
                     double d = -1.0;
                     try {
@@ -231,25 +249,177 @@ public class PhylogenyMethods {
         }
     }
 
+    final static public void sortNodeDescendents( final PhylogenyNode node, final DESCENDANT_SORT_PRIORITY pri ) {
+        class PhylogenyNodeSortTaxonomyPriority implements Comparator<PhylogenyNode> {
+
+            @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<PhylogenyNode> {
+
+            @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<PhylogenyNode> {
+
+            @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<PhylogenyNode> c;
+        switch ( pri ) {
+            case SEQUENCE:
+                c = new PhylogenyNodeSortSequencePriority();
+                break;
+            case NODE_NAME:
+                c = new PhylogenyNodeSortNodeNamePriority();
+                break;
+            default:
+                c = new PhylogenyNodeSortTaxonomyPriority();
+        }
+        final List<PhylogenyNode> descs = node.getDescendants();
+        Collections.sort( descs, c );
+        int i = 0;
+        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;
@@ -313,6 +483,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;
+                    }
                 }
             }
         }
@@ -328,7 +505,7 @@ public class PhylogenyMethods {
         else if ( b >= 0.0 ) {
             return b;
         }
-        return PhylogenyNode.DISTANCE_DEFAULT;
+        return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
     }
 
     // Helper for getUltraParalogousNodes( PhylogenyNode ).
@@ -432,13 +609,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<DescriptiveStatistics> calculatConfidenceStatistics( final Phylogeny phy ) {
+        final List<DescriptiveStatistics> stats = new ArrayList<DescriptiveStatistics>();
+        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 );
+                    }
                 }
             }
         }
@@ -774,12 +977,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();
         }
@@ -1047,8 +1250,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;
@@ -1363,8 +1567,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() );
         }
@@ -1399,6 +1605,49 @@ public class PhylogenyMethods {
         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,
@@ -1407,10 +1656,15 @@ 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;
+    }
 }