2 // FORESTER -- software libraries and applications
\r
3 // for evolutionary biology research and applications.
\r
5 // Copyright (C) 2008-2009 Christian M. Zmasek
\r
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
\r
7 // All rights reserved
\r
9 // This library is free software; you can redistribute it and/or
\r
10 // modify it under the terms of the GNU Lesser General Public
\r
11 // License as published by the Free Software Foundation; either
\r
12 // version 2.1 of the License, or (at your option) any later version.
\r
14 // This library is distributed in the hope that it will be useful,
\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
17 // Lesser General Public License for more details.
\r
19 // You should have received a copy of the GNU Lesser General Public
\r
20 // License along with this library; if not, write to the Free Software
\r
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
23 // Contact: phylosoft @ gmail . com
\r
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
\r
26 package org.forester.phylogeny;
\r
28 import java.awt.Color;
\r
29 import java.io.File;
\r
30 import java.io.IOException;
\r
31 import java.util.ArrayList;
\r
32 import java.util.Arrays;
\r
33 import java.util.Collections;
\r
34 import java.util.Comparator;
\r
35 import java.util.HashMap;
\r
36 import java.util.HashSet;
\r
37 import java.util.Iterator;
\r
38 import java.util.List;
\r
39 import java.util.Map;
\r
40 import java.util.Set;
\r
41 import java.util.regex.Matcher;
\r
42 import java.util.regex.Pattern;
\r
43 import java.util.regex.PatternSyntaxException;
\r
45 import org.forester.io.parsers.FastaParser;
\r
46 import org.forester.io.parsers.PhylogenyParser;
\r
47 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
\r
48 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
\r
49 import org.forester.io.parsers.util.PhylogenyParserException;
\r
50 import org.forester.msa.Msa;
\r
51 import org.forester.phylogeny.data.Accession;
\r
52 import org.forester.phylogeny.data.Annotation;
\r
53 import org.forester.phylogeny.data.BranchColor;
\r
54 import org.forester.phylogeny.data.BranchWidth;
\r
55 import org.forester.phylogeny.data.Confidence;
\r
56 import org.forester.phylogeny.data.DomainArchitecture;
\r
57 import org.forester.phylogeny.data.Event;
\r
58 import org.forester.phylogeny.data.Identifier;
\r
59 import org.forester.phylogeny.data.PhylogenyDataUtil;
\r
60 import org.forester.phylogeny.data.Sequence;
\r
61 import org.forester.phylogeny.data.Taxonomy;
\r
62 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
\r
63 import org.forester.phylogeny.factories.PhylogenyFactory;
\r
64 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
\r
65 import org.forester.util.BasicDescriptiveStatistics;
\r
66 import org.forester.util.DescriptiveStatistics;
\r
67 import org.forester.util.ForesterUtil;
\r
69 public class PhylogenyMethods {
\r
71 private PhylogenyMethods() {
\r
72 // Hidden constructor.
\r
76 public Object clone() throws CloneNotSupportedException {
\r
77 throw new CloneNotSupportedException();
\r
80 public static boolean extractFastaInformation( final Phylogeny phy ) {
\r
81 boolean could_extract = false;
\r
82 for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
\r
83 final PhylogenyNode node = iter.next();
\r
84 if ( !ForesterUtil.isEmpty( node.getName() ) ) {
\r
85 final Matcher name_m = FastaParser.FASTA_DESC_LINE.matcher( node.getName() );
\r
86 if ( name_m.lookingAt() ) {
\r
87 could_extract = true;
\r
88 final String acc_source = name_m.group( 1 );
\r
89 final String acc = name_m.group( 2 );
\r
90 final String seq_name = name_m.group( 3 );
\r
91 final String tax_sn = name_m.group( 4 );
\r
92 if ( !ForesterUtil.isEmpty( acc_source ) && !ForesterUtil.isEmpty( acc ) ) {
\r
93 ForesterUtil.ensurePresenceOfSequence( node );
\r
94 node.getNodeData().getSequence( 0 ).setAccession( new Accession( acc, acc_source ) );
\r
96 if ( !ForesterUtil.isEmpty( seq_name ) ) {
\r
97 ForesterUtil.ensurePresenceOfSequence( node );
\r
98 node.getNodeData().getSequence( 0 ).setName( seq_name );
\r
100 if ( !ForesterUtil.isEmpty( tax_sn ) ) {
\r
101 ForesterUtil.ensurePresenceOfTaxonomy( node );
\r
102 node.getNodeData().getTaxonomy( 0 ).setScientificName( tax_sn );
\r
107 return could_extract;
\r
110 public static DescriptiveStatistics calculatBranchLengthStatistics( final Phylogeny phy ) {
\r
111 final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
\r
112 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
113 final PhylogenyNode n = iter.next();
\r
114 if ( !n.isRoot() && ( n.getDistanceToParent() >= 0.0 ) ) {
\r
115 stats.addValue( n.getDistanceToParent() );
\r
121 public static List<DescriptiveStatistics> calculatConfidenceStatistics( final Phylogeny phy ) {
\r
122 final List<DescriptiveStatistics> stats = new ArrayList<DescriptiveStatistics>();
\r
123 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
124 final PhylogenyNode n = iter.next();
\r
125 if ( !n.isExternal() && !n.isRoot() ) {
\r
126 if ( n.getBranchData().isHasConfidences() ) {
\r
127 for( int i = 0; i < n.getBranchData().getConfidences().size(); ++i ) {
\r
128 final Confidence c = n.getBranchData().getConfidences().get( i );
\r
129 if ( ( i > ( stats.size() - 1 ) ) || ( stats.get( i ) == null ) ) {
\r
130 stats.add( i, new BasicDescriptiveStatistics() );
\r
132 if ( !ForesterUtil.isEmpty( c.getType() ) ) {
\r
133 if ( !ForesterUtil.isEmpty( stats.get( i ).getDescription() ) ) {
\r
134 if ( !stats.get( i ).getDescription().equalsIgnoreCase( c.getType() ) ) {
\r
135 throw new IllegalArgumentException( "support values in node [" + n.toString()
\r
136 + "] appear inconsistently ordered" );
\r
139 stats.get( i ).setDescription( c.getType() );
\r
141 stats.get( i ).addValue( ( ( c != null ) && ( c.getValue() >= 0 ) ) ? c.getValue() : 0 );
\r
150 * Calculates the distance between PhylogenyNodes node1 and node2.
\r
155 * @return distance between node1 and node2
\r
157 public static double calculateDistance( final PhylogenyNode node1, final PhylogenyNode node2 ) {
\r
158 final PhylogenyNode lca = calculateLCA( node1, node2 );
\r
159 final PhylogenyNode n1 = node1;
\r
160 final PhylogenyNode n2 = node2;
\r
161 return ( PhylogenyMethods.getDistance( n1, lca ) + PhylogenyMethods.getDistance( n2, lca ) );
\r
165 * Returns the LCA of PhylogenyNodes node1 and node2.
\r
170 * @return LCA of node1 and node2
\r
172 public final static PhylogenyNode calculateLCA( PhylogenyNode node1, PhylogenyNode node2 ) {
\r
173 if ( node1 == null ) {
\r
174 throw new IllegalArgumentException( "first argument (node) is null" );
\r
176 if ( node2 == null ) {
\r
177 throw new IllegalArgumentException( "second argument (node) is null" );
\r
179 if ( node1 == node2 ) {
\r
182 if ( ( node1.getParent() == node2.getParent() ) ) {
\r
183 return node1.getParent();
\r
185 int depth1 = node1.calculateDepth();
\r
186 int depth2 = node2.calculateDepth();
\r
187 while ( ( depth1 > -1 ) && ( depth2 > -1 ) ) {
\r
188 if ( depth1 > depth2 ) {
\r
189 node1 = node1.getParent();
\r
192 else if ( depth2 > depth1 ) {
\r
193 node2 = node2.getParent();
\r
197 if ( node1 == node2 ) {
\r
200 node1 = node1.getParent();
\r
201 node2 = node2.getParent();
\r
206 throw new IllegalArgumentException( "illegal attempt to calculate LCA of two nodes which do not share a common root" );
\r
210 * Returns the LCA of PhylogenyNodes node1 and node2.
\r
211 * Precondition: ids are in pre-order (or level-order).
\r
216 * @return LCA of node1 and node2
\r
218 public final static PhylogenyNode calculateLCAonTreeWithIdsInPreOrder( PhylogenyNode node1, PhylogenyNode node2 ) {
\r
219 if ( node1 == null ) {
\r
220 throw new IllegalArgumentException( "first argument (node) is null" );
\r
222 if ( node2 == null ) {
\r
223 throw new IllegalArgumentException( "second argument (node) is null" );
\r
225 while ( node1 != node2 ) {
\r
226 if ( node1.getId() > node2.getId() ) {
\r
227 node1 = node1.getParent();
\r
230 node2 = node2.getParent();
\r
236 public static short calculateMaxBranchesToLeaf( final PhylogenyNode node ) {
\r
237 if ( node.isExternal() ) {
\r
241 for( PhylogenyNode d : node.getAllExternalDescendants() ) {
\r
243 while ( d != node ) {
\r
244 if ( d.isCollapse() ) {
\r
252 if ( max < steps ) {
\r
259 public static int calculateMaxDepth( final Phylogeny phy ) {
\r
261 for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
\r
262 final PhylogenyNode node = iter.next();
\r
263 final int steps = node.calculateDepth();
\r
264 if ( steps > max ) {
\r
271 public static double calculateMaxDistanceToRoot( final Phylogeny phy ) {
\r
273 for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
\r
274 final PhylogenyNode node = iter.next();
\r
275 final double d = node.calculateDistanceToRoot();
\r
283 public static PhylogenyNode calculateNodeWithMaxDistanceToRoot( final Phylogeny phy ) {
\r
285 PhylogenyNode max_node = phy.getFirstExternalNode();
\r
286 for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
\r
287 final PhylogenyNode node = iter.next();
\r
288 final double d = node.calculateDistanceToRoot();
\r
297 public static int calculateNumberOfExternalNodesWithoutTaxonomy( final PhylogenyNode node ) {
\r
298 final List<PhylogenyNode> descs = node.getAllExternalDescendants();
\r
300 for( final PhylogenyNode n : descs ) {
\r
301 if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) {
\r
308 public static DescriptiveStatistics calculatNumberOfDescendantsPerNodeStatistics( final Phylogeny phy ) {
\r
309 final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
\r
310 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
311 final PhylogenyNode n = iter.next();
\r
312 if ( !n.isExternal() ) {
\r
313 stats.addValue( n.getNumberOfDescendants() );
\r
319 public final static void collapseSubtreeStructure( final PhylogenyNode n ) {
\r
320 final List<PhylogenyNode> eds = n.getAllExternalDescendants();
\r
321 final List<Double> d = new ArrayList<Double>();
\r
322 for( final PhylogenyNode ed : eds ) {
\r
323 d.add( calculateDistanceToAncestor( n, ed ) );
\r
325 for( int i = 0; i < eds.size(); ++i ) {
\r
326 n.setChildNode( i, eds.get( i ) );
\r
327 eds.get( i ).setDistanceToParent( d.get( i ) );
\r
331 public static int countNumberOfOneDescendantNodes( final Phylogeny phy ) {
\r
333 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
334 final PhylogenyNode n = iter.next();
\r
335 if ( !n.isExternal() && ( n.getNumberOfDescendants() == 1 ) ) {
\r
342 public static int countNumberOfPolytomies( final Phylogeny phy ) {
\r
344 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
345 final PhylogenyNode n = iter.next();
\r
346 if ( !n.isExternal() && ( n.getNumberOfDescendants() > 2 ) ) {
\r
353 public static final HashMap<String, PhylogenyNode> createNameToExtNodeMap( final Phylogeny phy ) {
\r
354 final HashMap<String, PhylogenyNode> nodes = new HashMap<String, PhylogenyNode>();
\r
355 final List<PhylogenyNode> ext = phy.getExternalNodes();
\r
356 for( final PhylogenyNode n : ext ) {
\r
357 nodes.put( n.getName(), n );
\r
362 public static void deleteExternalNodesNegativeSelection( final Set<Long> to_delete, final Phylogeny phy ) {
\r
363 for( final Long id : to_delete ) {
\r
364 phy.deleteSubtree( phy.getNode( id ), true );
\r
366 phy.clearHashIdToNodeMap();
\r
367 phy.externalNodesHaveChanged();
\r
370 public static void deleteExternalNodesNegativeSelection( final String[] node_names_to_delete, final Phylogeny p )
\r
371 throws IllegalArgumentException {
\r
372 for( final String element : node_names_to_delete ) {
\r
373 if ( ForesterUtil.isEmpty( element ) ) {
\r
376 List<PhylogenyNode> nodes = null;
\r
377 nodes = p.getNodes( element );
\r
378 final Iterator<PhylogenyNode> it = nodes.iterator();
\r
379 while ( it.hasNext() ) {
\r
380 final PhylogenyNode n = it.next();
\r
381 if ( !n.isExternal() ) {
\r
382 throw new IllegalArgumentException( "attempt to delete non-external node \"" + element + "\"" );
\r
384 p.deleteSubtree( n, true );
\r
387 p.clearHashIdToNodeMap();
\r
388 p.externalNodesHaveChanged();
\r
391 public static List<String> deleteExternalNodesPositiveSelection( final String[] node_names_to_keep,
\r
392 final Phylogeny p ) {
\r
393 final PhylogenyNodeIterator it = p.iteratorExternalForward();
\r
394 final String[] to_delete = new String[ p.getNumberOfExternalNodes() ];
\r
396 Arrays.sort( node_names_to_keep );
\r
397 while ( it.hasNext() ) {
\r
398 final String curent_name = it.next().getName();
\r
399 if ( Arrays.binarySearch( node_names_to_keep, curent_name ) < 0 ) {
\r
400 to_delete[ i++ ] = curent_name;
\r
403 PhylogenyMethods.deleteExternalNodesNegativeSelection( to_delete, p );
\r
404 final List<String> deleted = new ArrayList<String>();
\r
405 for( final String n : to_delete ) {
\r
406 if ( !ForesterUtil.isEmpty( n ) ) {
\r
413 public static void deleteExternalNodesPositiveSelectionT( final List<Taxonomy> species_to_keep, final Phylogeny phy ) {
\r
414 final Set<Long> to_delete = new HashSet<Long>();
\r
415 for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
\r
416 final PhylogenyNode n = it.next();
\r
417 if ( n.getNodeData().isHasTaxonomy() ) {
\r
418 if ( !species_to_keep.contains( n.getNodeData().getTaxonomy() ) ) {
\r
419 to_delete.add( n.getId() );
\r
423 throw new IllegalArgumentException( "node " + n.getId() + " has no taxonomic data" );
\r
426 deleteExternalNodesNegativeSelection( to_delete, phy );
\r
429 final public static void deleteInternalNodesWithOnlyOneDescendent( final Phylogeny phy ) {
\r
430 final ArrayList<PhylogenyNode> to_delete = new ArrayList<PhylogenyNode>();
\r
431 for( final PhylogenyNodeIterator iter = phy.iteratorPostorder(); iter.hasNext(); ) {
\r
432 final PhylogenyNode n = iter.next();
\r
433 if ( ( !n.isExternal() ) && ( n.getNumberOfDescendants() == 1 ) ) {
\r
434 to_delete.add( n );
\r
437 for( final PhylogenyNode d : to_delete ) {
\r
438 PhylogenyMethods.removeNode( d, phy );
\r
440 phy.clearHashIdToNodeMap();
\r
441 phy.externalNodesHaveChanged();
\r
444 final public static void deleteNonOrthologousExternalNodes( final Phylogeny phy, final PhylogenyNode n ) {
\r
445 if ( n.isInternal() ) {
\r
446 throw new IllegalArgumentException( "node is not external" );
\r
448 final ArrayList<PhylogenyNode> to_delete = new ArrayList<PhylogenyNode>();
\r
449 for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
\r
450 final PhylogenyNode i = it.next();
\r
451 if ( !PhylogenyMethods.getEventAtLCA( n, i ).isSpeciation() ) {
\r
452 to_delete.add( i );
\r
455 for( final PhylogenyNode d : to_delete ) {
\r
456 phy.deleteSubtree( d, true );
\r
458 phy.clearHashIdToNodeMap();
\r
459 phy.externalNodesHaveChanged();
\r
462 public final static List<List<PhylogenyNode>> divideIntoSubTrees( final Phylogeny phy,
\r
463 final double min_distance_to_root ) {
\r
464 if ( min_distance_to_root <= 0 ) {
\r
465 throw new IllegalArgumentException( "attempt to use min distance to root of: " + min_distance_to_root );
\r
467 final List<List<PhylogenyNode>> l = new ArrayList<List<PhylogenyNode>>();
\r
468 setAllIndicatorsToZero( phy );
\r
469 for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
\r
470 final PhylogenyNode n = it.next();
\r
471 if ( n.getIndicator() != 0 ) {
\r
474 l.add( divideIntoSubTreesHelper( n, min_distance_to_root ) );
\r
475 if ( l.isEmpty() ) {
\r
476 throw new RuntimeException( "this should not have happened" );
\r
482 public static List<PhylogenyNode> getAllDescendants( final PhylogenyNode node ) {
\r
483 final List<PhylogenyNode> descs = new ArrayList<PhylogenyNode>();
\r
484 final Set<Long> encountered = new HashSet<Long>();
\r
485 if ( !node.isExternal() ) {
\r
486 final List<PhylogenyNode> exts = node.getAllExternalDescendants();
\r
487 for( PhylogenyNode current : exts ) {
\r
488 descs.add( current );
\r
489 while ( current != node ) {
\r
490 current = current.getParent();
\r
491 if ( encountered.contains( current.getId() ) ) {
\r
494 descs.add( current );
\r
495 encountered.add( current.getId() );
\r
504 * Convenience method
\r
509 public static Color getBranchColorValue( final PhylogenyNode node ) {
\r
510 if ( node.getBranchData().getBranchColor() == null ) {
\r
513 return node.getBranchData().getBranchColor().getValue();
\r
517 * Convenience method
\r
519 public static double getBranchWidthValue( final PhylogenyNode node ) {
\r
520 if ( !node.getBranchData().isHasBranchWidth() ) {
\r
521 return BranchWidth.BRANCH_WIDTH_DEFAULT_VALUE;
\r
523 return node.getBranchData().getBranchWidth().getValue();
\r
527 * Convenience method
\r
529 public static double getConfidenceValue( final PhylogenyNode node ) {
\r
530 if ( !node.getBranchData().isHasConfidences() ) {
\r
531 return Confidence.CONFIDENCE_DEFAULT_VALUE;
\r
533 return node.getBranchData().getConfidence( 0 ).getValue();
\r
537 * Convenience method
\r
539 public static double[] getConfidenceValuesAsArray( final PhylogenyNode node ) {
\r
540 if ( !node.getBranchData().isHasConfidences() ) {
\r
541 return new double[ 0 ];
\r
543 final double[] values = new double[ node.getBranchData().getConfidences().size() ];
\r
545 for( final Confidence c : node.getBranchData().getConfidences() ) {
\r
546 values[ i++ ] = c.getValue();
\r
551 final public static Event getEventAtLCA( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
552 return calculateLCA( n1, n2 ).getNodeData().getEvent();
\r
556 * Returns taxonomy t if all external descendants have
\r
557 * the same taxonomy t, null otherwise.
\r
560 public static Taxonomy getExternalDescendantsTaxonomy( final PhylogenyNode node ) {
\r
561 final List<PhylogenyNode> descs = node.getAllExternalDescendants();
\r
562 Taxonomy tax = null;
\r
563 for( final PhylogenyNode n : descs ) {
\r
564 if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) {
\r
567 else if ( tax == null ) {
\r
568 tax = n.getNodeData().getTaxonomy();
\r
570 else if ( n.getNodeData().getTaxonomy().isEmpty() || !tax.isEqual( n.getNodeData().getTaxonomy() ) ) {
\r
577 public static PhylogenyNode getFurthestDescendant( final PhylogenyNode node ) {
\r
578 final List<PhylogenyNode> children = node.getAllExternalDescendants();
\r
579 PhylogenyNode farthest = null;
\r
580 double longest = -Double.MAX_VALUE;
\r
581 for( final PhylogenyNode child : children ) {
\r
582 if ( PhylogenyMethods.getDistance( child, node ) > longest ) {
\r
584 longest = PhylogenyMethods.getDistance( child, node );
\r
590 // public static PhylogenyMethods getInstance() {
\r
591 // if ( PhylogenyMethods._instance == null ) {
\r
592 // PhylogenyMethods._instance = new PhylogenyMethods();
\r
594 // return PhylogenyMethods._instance;
\r
597 * Returns the largest confidence value found on phy.
\r
599 static public double getMaximumConfidenceValue( final Phylogeny phy ) {
\r
600 double max = -Double.MAX_VALUE;
\r
601 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
602 final double s = PhylogenyMethods.getConfidenceValue( iter.next() );
\r
603 if ( ( s != Confidence.CONFIDENCE_DEFAULT_VALUE ) && ( s > max ) ) {
\r
610 static public int getMinimumDescendentsPerInternalNodes( final Phylogeny phy ) {
\r
611 int min = Integer.MAX_VALUE;
\r
614 for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) {
\r
616 if ( n.isInternal() ) {
\r
617 d = n.getNumberOfDescendants();
\r
627 * Convenience method for display purposes.
\r
628 * Not intended for algorithms.
\r
630 public static String getSpecies( final PhylogenyNode node ) {
\r
631 if ( !node.getNodeData().isHasTaxonomy() ) {
\r
634 else if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) {
\r
635 return node.getNodeData().getTaxonomy().getScientificName();
\r
637 if ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
\r
638 return node.getNodeData().getTaxonomy().getTaxonomyCode();
\r
641 return node.getNodeData().getTaxonomy().getCommonName();
\r
646 * Convenience method for display purposes.
\r
647 * Not intended for algorithms.
\r
649 public static String getTaxonomyIdentifier( final PhylogenyNode node ) {
\r
650 if ( !node.getNodeData().isHasTaxonomy() || ( node.getNodeData().getTaxonomy().getIdentifier() == null ) ) {
\r
653 return node.getNodeData().getTaxonomy().getIdentifier().getValue();
\r
656 public final static boolean isAllDecendentsAreDuplications( final PhylogenyNode n ) {
\r
657 if ( n.isExternal() ) {
\r
661 if ( n.isDuplication() ) {
\r
662 for( final PhylogenyNode desc : n.getDescendants() ) {
\r
663 if ( !isAllDecendentsAreDuplications( desc ) ) {
\r
675 public static boolean isHasExternalDescendant( final PhylogenyNode node ) {
\r
676 for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
\r
677 if ( node.getChildNode( i ).isExternal() ) {
\r
685 * This is case insensitive.
\r
688 public synchronized static boolean isTaxonomyHasIdentifierOfGivenProvider( final Taxonomy tax,
\r
689 final String[] providers ) {
\r
690 if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() ) ) {
\r
691 final String my_tax_prov = tax.getIdentifier().getProvider();
\r
692 for( final String provider : providers ) {
\r
693 if ( provider.equalsIgnoreCase( my_tax_prov ) ) {
\r
704 public static void midpointRoot( final Phylogeny phylogeny ) {
\r
705 if ( ( phylogeny.getNumberOfExternalNodes() < 2 ) || ( calculateMaxDistanceToRoot( phylogeny ) <= 0 ) ) {
\r
709 final int total_nodes = phylogeny.getNodeCount();
\r
711 if ( ++counter > total_nodes ) {
\r
712 throw new RuntimeException( "this should not have happened: midpoint rooting does not converge" );
\r
714 PhylogenyNode a = null;
\r
717 for( int i = 0; i < phylogeny.getRoot().getNumberOfDescendants(); ++i ) {
\r
718 final PhylogenyNode f = getFurthestDescendant( phylogeny.getRoot().getChildNode( i ) );
\r
719 final double df = getDistance( f, phylogeny.getRoot() );
\r
726 else if ( df > db ) {
\r
731 final double diff = da - db;
\r
732 if ( diff < 0.000001 ) {
\r
735 double x = da - ( diff / 2.0 );
\r
736 while ( ( x > a.getDistanceToParent() ) && !a.isRoot() ) {
\r
737 x -= ( a.getDistanceToParent() > 0 ? a.getDistanceToParent() : 0 );
\r
740 phylogeny.reRoot( a, x );
\r
742 phylogeny.recalculateNumberOfExternalDescendants( true );
\r
745 public static void normalizeBootstrapValues( final Phylogeny phylogeny,
\r
746 final double max_bootstrap_value,
\r
747 final double max_normalized_value ) {
\r
748 for( final PhylogenyNodeIterator iter = phylogeny.iteratorPreorder(); iter.hasNext(); ) {
\r
749 final PhylogenyNode node = iter.next();
\r
750 if ( node.isInternal() ) {
\r
751 final double confidence = getConfidenceValue( node );
\r
752 if ( confidence != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
\r
753 if ( confidence >= max_bootstrap_value ) {
\r
754 setBootstrapConfidence( node, max_normalized_value );
\r
757 setBootstrapConfidence( node, ( confidence * max_normalized_value ) / max_bootstrap_value );
\r
764 public static List<PhylogenyNode> obtainAllNodesAsList( final Phylogeny phy ) {
\r
765 final List<PhylogenyNode> nodes = new ArrayList<PhylogenyNode>();
\r
766 if ( phy.isEmpty() ) {
\r
769 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
770 nodes.add( iter.next() );
\r
776 * Returns a map of distinct taxonomies of
\r
777 * all external nodes of node.
\r
778 * If at least one of the external nodes has no taxonomy,
\r
779 * null is returned.
\r
782 public static Map<Taxonomy, Integer> obtainDistinctTaxonomyCounts( final PhylogenyNode node ) {
\r
783 final List<PhylogenyNode> descs = node.getAllExternalDescendants();
\r
784 final Map<Taxonomy, Integer> tax_map = new HashMap<Taxonomy, Integer>();
\r
785 for( final PhylogenyNode n : descs ) {
\r
786 if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) {
\r
789 final Taxonomy t = n.getNodeData().getTaxonomy();
\r
790 if ( tax_map.containsKey( t ) ) {
\r
791 tax_map.put( t, tax_map.get( t ) + 1 );
\r
794 tax_map.put( t, 1 );
\r
801 * Arranges the order of childern for each node of this Phylogeny in such a
\r
802 * way that either the branch with more children is on top (right) or on
\r
803 * bottom (left), dependent on the value of boolean order.
\r
806 * decides in which direction to order
\r
809 public static void orderAppearance( final PhylogenyNode n,
\r
810 final boolean order,
\r
811 final boolean order_ext_alphabetically,
\r
812 final DESCENDANT_SORT_PRIORITY pri ) {
\r
813 if ( n.isExternal() ) {
\r
817 PhylogenyNode temp = null;
\r
818 if ( ( n.getNumberOfDescendants() == 2 )
\r
819 && ( n.getChildNode1().getNumberOfExternalNodes() != n.getChildNode2().getNumberOfExternalNodes() )
\r
820 && ( ( n.getChildNode1().getNumberOfExternalNodes() < n.getChildNode2().getNumberOfExternalNodes() ) == order ) ) {
\r
821 temp = n.getChildNode1();
\r
822 n.setChild1( n.getChildNode2() );
\r
823 n.setChild2( temp );
\r
825 else if ( order_ext_alphabetically ) {
\r
826 boolean all_ext = true;
\r
827 for( final PhylogenyNode i : n.getDescendants() ) {
\r
828 if ( !i.isExternal() ) {
\r
834 PhylogenyMethods.sortNodeDescendents( n, pri );
\r
837 for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
\r
838 orderAppearance( n.getChildNode( i ), order, order_ext_alphabetically, pri );
\r
843 public static void postorderBranchColorAveragingExternalNodeBased( final Phylogeny p ) {
\r
844 for( final PhylogenyNodeIterator iter = p.iteratorPostorder(); iter.hasNext(); ) {
\r
845 final PhylogenyNode node = iter.next();
\r
847 double green = 0.0;
\r
850 if ( node.isInternal() ) {
\r
851 //for( final PhylogenyNodeIterator iterator = node.iterateChildNodesForward(); iterator.hasNext(); ) {
\r
852 for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
\r
853 final PhylogenyNode child_node = node.getChildNode( i );
\r
854 final Color child_color = getBranchColorValue( child_node );
\r
855 if ( child_color != null ) {
\r
857 red += child_color.getRed();
\r
858 green += child_color.getGreen();
\r
859 blue += child_color.getBlue();
\r
862 setBranchColorValue( node,
\r
863 new Color( ForesterUtil.roundToInt( red / n ),
\r
864 ForesterUtil.roundToInt( green / n ),
\r
865 ForesterUtil.roundToInt( blue / n ) ) );
\r
870 public static final void preOrderReId( final Phylogeny phy ) {
\r
871 if ( phy.isEmpty() ) {
\r
874 phy.setIdToNodeMap( null );
\r
875 long i = PhylogenyNode.getNodeCount();
\r
876 for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) {
\r
877 it.next().setId( i++ );
\r
879 PhylogenyNode.setNodeCount( i );
\r
882 public final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final File file ) throws IOException {
\r
883 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
\r
884 final Phylogeny[] trees = factory.create( file, parser );
\r
885 if ( ( trees == null ) || ( trees.length == 0 ) ) {
\r
886 throw new PhylogenyParserException( "Unable to parse phylogeny from file: " + file );
\r
891 public final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final List<File> files )
\r
892 throws IOException {
\r
893 final List<Phylogeny> tree_list = new ArrayList<Phylogeny>();
\r
894 for( final File file : files ) {
\r
895 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
\r
896 final Phylogeny[] trees = factory.create( file, parser );
\r
897 if ( ( trees == null ) || ( trees.length == 0 ) ) {
\r
898 throw new PhylogenyParserException( "Unable to parse phylogeny from file: " + file );
\r
900 tree_list.addAll( Arrays.asList( trees ) );
\r
902 return tree_list.toArray( new Phylogeny[ tree_list.size() ] );
\r
905 public static void removeNode( final PhylogenyNode remove_me, final Phylogeny phylogeny ) {
\r
906 if ( remove_me.isRoot() ) {
\r
907 if ( remove_me.getNumberOfDescendants() == 1 ) {
\r
908 final PhylogenyNode desc = remove_me.getDescendants().get( 0 );
\r
909 desc.setDistanceToParent( addPhylogenyDistances( remove_me.getDistanceToParent(),
\r
910 desc.getDistanceToParent() ) );
\r
911 desc.setParent( null );
\r
912 phylogeny.setRoot( desc );
\r
913 phylogeny.clearHashIdToNodeMap();
\r
916 throw new IllegalArgumentException( "attempt to remove a root node with more than one descendants" );
\r
919 else if ( remove_me.isExternal() ) {
\r
920 phylogeny.deleteSubtree( remove_me, false );
\r
921 phylogeny.clearHashIdToNodeMap();
\r
922 phylogeny.externalNodesHaveChanged();
\r
925 final PhylogenyNode parent = remove_me.getParent();
\r
926 final List<PhylogenyNode> descs = remove_me.getDescendants();
\r
927 parent.removeChildNode( remove_me );
\r
928 for( final PhylogenyNode desc : descs ) {
\r
929 parent.addAsChild( desc );
\r
930 desc.setDistanceToParent( addPhylogenyDistances( remove_me.getDistanceToParent(),
\r
931 desc.getDistanceToParent() ) );
\r
933 remove_me.setParent( null );
\r
934 phylogeny.clearHashIdToNodeMap();
\r
935 phylogeny.externalNodesHaveChanged();
\r
939 private static enum NDF {
\r
941 TaxonomyCode( "TC" ),
\r
942 TaxonomyCommonName( "CN" ),
\r
943 TaxonomyScientificName( "TS" ),
\r
944 TaxonomyIdentifier( "TI" ),
\r
945 TaxonomySynonym( "SY" ),
\r
946 SequenceName( "SN" ),
\r
948 SequenceSymbol( "SS" ),
\r
949 SequenceAccession( "SA" ),
\r
951 Annotation( "AN" ),
\r
953 BinaryCharacter( "BC" ),
\r
954 MolecularSequence( "MS" );
\r
956 private final String _text;
\r
958 NDF( final String text ) {
\r
962 public static NDF fromString( final String text ) {
\r
963 for( final NDF n : NDF.values() ) {
\r
964 if ( text.startsWith( n._text ) ) {
\r
972 public static List<PhylogenyNode> searchData( final String query,
\r
973 final Phylogeny phy,
\r
974 final boolean case_sensitive,
\r
975 final boolean partial,
\r
976 final boolean regex,
\r
977 final boolean search_domains,
\r
978 final double domains_confidence_threshold ) {
\r
979 final List<PhylogenyNode> nodes = new ArrayList<PhylogenyNode>();
\r
980 if ( phy.isEmpty() || ( query == null ) ) {
\r
983 if ( ForesterUtil.isEmpty( query ) ) {
\r
986 String my_query = query;
\r
988 if ( ( my_query.length() > 2 ) && ( my_query.indexOf( ":" ) == 2 ) ) {
\r
989 ndf = NDF.fromString( my_query );
\r
990 if ( ndf != null ) {
\r
991 my_query = my_query.substring( 3 );
\r
994 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
995 final PhylogenyNode node = iter.next();
\r
996 boolean match = false;
\r
997 if ( ( ( ndf == null ) || ( ndf == NDF.NodeName ) )
\r
998 && match( node.getName(), my_query, case_sensitive, partial, regex ) ) {
\r
1001 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCode ) )
\r
1002 && node.getNodeData().isHasTaxonomy()
\r
1003 && match( node.getNodeData().getTaxonomy().getTaxonomyCode(),
\r
1010 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCommonName ) )
\r
1011 && node.getNodeData().isHasTaxonomy()
\r
1012 && match( node.getNodeData().getTaxonomy().getCommonName(),
\r
1019 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyScientificName ) )
\r
1020 && node.getNodeData().isHasTaxonomy()
\r
1021 && match( node.getNodeData().getTaxonomy().getScientificName(),
\r
1028 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyIdentifier ) )
\r
1029 && node.getNodeData().isHasTaxonomy()
\r
1030 && ( node.getNodeData().getTaxonomy().getIdentifier() != null )
\r
1031 && match( node.getNodeData().getTaxonomy().getIdentifier().getValue(),
\r
1038 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomySynonym ) ) && node.getNodeData().isHasTaxonomy()
\r
1039 && !node.getNodeData().getTaxonomy().getSynonyms().isEmpty() ) {
\r
1040 final List<String> syns = node.getNodeData().getTaxonomy().getSynonyms();
\r
1041 I: for( final String syn : syns ) {
\r
1042 if ( match( syn, my_query, case_sensitive, partial, regex ) ) {
\r
1048 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceName ) ) && node.getNodeData().isHasSequence()
\r
1049 && match( node.getNodeData().getSequence().getName(), my_query, case_sensitive, partial, regex ) ) {
\r
1052 if ( !match && ( ( ndf == null ) || ( ndf == NDF.GeneName ) ) && node.getNodeData().isHasSequence()
\r
1053 && match( node.getNodeData().getSequence().getGeneName(), my_query, case_sensitive, partial, regex ) ) {
\r
1056 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceSymbol ) ) && node.getNodeData().isHasSequence()
\r
1057 && match( node.getNodeData().getSequence().getSymbol(), my_query, case_sensitive, partial, regex ) ) {
\r
1061 && ( ( ndf == null ) || ( ndf == NDF.SequenceAccession ) )
\r
1062 && node.getNodeData().isHasSequence()
\r
1063 && ( node.getNodeData().getSequence().getAccession() != null )
\r
1064 && match( node.getNodeData().getSequence().getAccession().getValue(),
\r
1071 if ( !match && ( ( ( ndf == null ) && search_domains ) || ( ndf == NDF.Domain ) )
\r
1072 && node.getNodeData().isHasSequence()
\r
1073 && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
\r
1074 final DomainArchitecture da = node.getNodeData().getSequence().getDomainArchitecture();
\r
1075 I: for( int i = 0; i < da.getNumberOfDomains(); ++i ) {
\r
1076 if ( ( da.getDomain( i ).getConfidence() <= domains_confidence_threshold )
\r
1077 && ( match( da.getDomain( i ).getName(), my_query, case_sensitive, partial, regex ) ) ) {
\r
1083 if ( !match && ( ( ndf == null ) || ( ndf == NDF.Annotation ) ) && node.getNodeData().isHasSequence()
\r
1084 && ( node.getNodeData().getSequence().getAnnotations() != null ) ) {
\r
1085 for( final Annotation ann : node.getNodeData().getSequence().getAnnotations() ) {
\r
1086 if ( match( ann.getDesc(), my_query, case_sensitive, partial, regex ) ) {
\r
1090 if ( match( ann.getRef(), my_query, case_sensitive, partial, regex ) ) {
\r
1096 if ( !match && ( ( ndf == null ) || ( ndf == NDF.CrossRef ) ) && node.getNodeData().isHasSequence()
\r
1097 && ( node.getNodeData().getSequence().getCrossReferences() != null ) ) {
\r
1098 for( final Accession x : node.getNodeData().getSequence().getCrossReferences() ) {
\r
1099 if ( match( x.getComment(), my_query, case_sensitive, partial, regex ) ) {
\r
1103 if ( match( x.getSource(), my_query, case_sensitive, partial, regex ) ) {
\r
1107 if ( match( x.getValue(), my_query, case_sensitive, partial, regex ) ) {
\r
1113 if ( !match && ( ( ndf == null ) || ( ndf == NDF.BinaryCharacter ) )
\r
1114 && ( node.getNodeData().getBinaryCharacters() != null ) ) {
\r
1115 Iterator<String> it = node.getNodeData().getBinaryCharacters().getPresentCharacters().iterator();
\r
1116 I: while ( it.hasNext() ) {
\r
1117 if ( match( it.next(), my_query, case_sensitive, partial, regex ) ) {
\r
1122 it = node.getNodeData().getBinaryCharacters().getGainedCharacters().iterator();
\r
1123 I: while ( it.hasNext() ) {
\r
1124 if ( match( it.next(), my_query, case_sensitive, partial, regex ) ) {
\r
1131 && ( ndf == NDF.MolecularSequence )
\r
1132 && node.getNodeData().isHasSequence()
\r
1133 && match( node.getNodeData().getSequence().getMolecularSequence(),
\r
1141 nodes.add( node );
\r
1147 public static List<PhylogenyNode> searchDataLogicalAnd( final String[] queries,
\r
1148 final Phylogeny phy,
\r
1149 final boolean case_sensitive,
\r
1150 final boolean partial,
\r
1151 final boolean search_domains,
\r
1152 final double domains_confidence_threshold ) {
\r
1153 final List<PhylogenyNode> nodes = new ArrayList<PhylogenyNode>();
\r
1154 if ( phy.isEmpty() || ( queries == null ) || ( queries.length < 1 ) ) {
\r
1157 for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
\r
1158 final PhylogenyNode node = iter.next();
\r
1159 boolean all_matched = true;
\r
1160 for( String query : queries ) {
\r
1162 if ( ( query.length() > 2 ) && ( query.indexOf( ":" ) == 2 ) ) {
\r
1163 ndf = NDF.fromString( query );
\r
1164 if ( ndf != null ) {
\r
1165 query = query.substring( 3 );
\r
1168 boolean match = false;
\r
1169 if ( ForesterUtil.isEmpty( query ) ) {
\r
1172 if ( ( ( ndf == null ) || ( ndf == NDF.NodeName ) )
\r
1173 && match( node.getName(), query, case_sensitive, partial, false ) ) {
\r
1176 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCode ) )
\r
1177 && node.getNodeData().isHasTaxonomy()
\r
1178 && match( node.getNodeData().getTaxonomy().getTaxonomyCode(),
\r
1185 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCommonName ) )
\r
1186 && node.getNodeData().isHasTaxonomy()
\r
1187 && match( node.getNodeData().getTaxonomy().getCommonName(),
\r
1194 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyScientificName ) )
\r
1195 && node.getNodeData().isHasTaxonomy()
\r
1196 && match( node.getNodeData().getTaxonomy().getScientificName(),
\r
1203 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyIdentifier ) )
\r
1204 && node.getNodeData().isHasTaxonomy()
\r
1205 && ( node.getNodeData().getTaxonomy().getIdentifier() != null )
\r
1206 && match( node.getNodeData().getTaxonomy().getIdentifier().getValue(),
\r
1213 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomySynonym ) ) && node.getNodeData().isHasTaxonomy()
\r
1214 && !node.getNodeData().getTaxonomy().getSynonyms().isEmpty() ) {
\r
1215 final List<String> syns = node.getNodeData().getTaxonomy().getSynonyms();
\r
1216 I: for( final String syn : syns ) {
\r
1217 if ( match( syn, query, case_sensitive, partial, false ) ) {
\r
1223 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceName ) ) && node.getNodeData().isHasSequence()
\r
1224 && match( node.getNodeData().getSequence().getName(), query, case_sensitive, partial, false ) ) {
\r
1228 && ( ( ndf == null ) || ( ndf == NDF.GeneName ) )
\r
1229 && node.getNodeData().isHasSequence()
\r
1230 && match( node.getNodeData().getSequence().getGeneName(), query, case_sensitive, partial, false ) ) {
\r
1233 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceSymbol ) )
\r
1234 && node.getNodeData().isHasSequence()
\r
1235 && match( node.getNodeData().getSequence().getSymbol(), query, case_sensitive, partial, false ) ) {
\r
1239 && ( ( ndf == null ) || ( ndf == NDF.SequenceAccession ) )
\r
1240 && node.getNodeData().isHasSequence()
\r
1241 && ( node.getNodeData().getSequence().getAccession() != null )
\r
1242 && match( node.getNodeData().getSequence().getAccession().getValue(),
\r
1249 if ( !match && ( ( ( ndf == null ) && search_domains ) || ( ndf == NDF.Domain ) )
\r
1250 && node.getNodeData().isHasSequence()
\r
1251 && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
\r
1252 final DomainArchitecture da = node.getNodeData().getSequence().getDomainArchitecture();
\r
1253 I: for( int i = 0; i < da.getNumberOfDomains(); ++i ) {
\r
1254 if ( ( da.getDomain( i ).getConfidence() <= domains_confidence_threshold )
\r
1255 && match( da.getDomain( i ).getName(), query, case_sensitive, partial, false ) ) {
\r
1261 if ( !match && ( ( ndf == null ) || ( ndf == NDF.Annotation ) ) && node.getNodeData().isHasSequence()
\r
1262 && ( node.getNodeData().getSequence().getAnnotations() != null ) ) {
\r
1263 for( final Annotation ann : node.getNodeData().getSequence().getAnnotations() ) {
\r
1264 if ( match( ann.getDesc(), query, case_sensitive, partial, false ) ) {
\r
1268 if ( match( ann.getRef(), query, case_sensitive, partial, false ) ) {
\r
1274 if ( !match && ( ( ndf == null ) || ( ndf == NDF.CrossRef ) ) && node.getNodeData().isHasSequence()
\r
1275 && ( node.getNodeData().getSequence().getCrossReferences() != null ) ) {
\r
1276 for( final Accession x : node.getNodeData().getSequence().getCrossReferences() ) {
\r
1277 if ( match( x.getComment(), query, case_sensitive, partial, false ) ) {
\r
1281 if ( match( x.getSource(), query, case_sensitive, partial, false ) ) {
\r
1285 if ( match( x.getValue(), query, case_sensitive, partial, false ) ) {
\r
1291 if ( !match && ( ( ndf == null ) || ( ndf == NDF.BinaryCharacter ) )
\r
1292 && ( node.getNodeData().getBinaryCharacters() != null ) ) {
\r
1293 Iterator<String> it = node.getNodeData().getBinaryCharacters().getPresentCharacters().iterator();
\r
1294 I: while ( it.hasNext() ) {
\r
1295 if ( match( it.next(), query, case_sensitive, partial, false ) ) {
\r
1300 it = node.getNodeData().getBinaryCharacters().getGainedCharacters().iterator();
\r
1301 I: while ( it.hasNext() ) {
\r
1302 if ( match( it.next(), query, case_sensitive, partial, false ) ) {
\r
1309 && ( ndf == NDF.MolecularSequence )
\r
1310 && node.getNodeData().isHasSequence()
\r
1311 && match( node.getNodeData().getSequence().getMolecularSequence(),
\r
1319 all_matched = false;
\r
1323 if ( all_matched ) {
\r
1324 nodes.add( node );
\r
1330 public static void setAllIndicatorsToZero( final Phylogeny phy ) {
\r
1331 for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) {
\r
1332 it.next().setIndicator( ( byte ) 0 );
\r
1337 * Convenience method.
\r
1338 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1340 public static void setBootstrapConfidence( final PhylogenyNode node, final double bootstrap_confidence_value ) {
\r
1341 setConfidence( node, bootstrap_confidence_value, "bootstrap" );
\r
1344 public static void setBranchColorValue( final PhylogenyNode node, final Color color ) {
\r
1345 if ( node.getBranchData().getBranchColor() == null ) {
\r
1346 node.getBranchData().setBranchColor( new BranchColor() );
\r
1348 node.getBranchData().getBranchColor().setValue( color );
\r
1352 * Convenience method
\r
1354 public static void setBranchWidthValue( final PhylogenyNode node, final double branch_width_value ) {
\r
1355 node.getBranchData().setBranchWidth( new BranchWidth( branch_width_value ) );
\r
1359 * Convenience method.
\r
1360 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1362 public static void setConfidence( final PhylogenyNode node, final double confidence_value ) {
\r
1363 setConfidence( node, confidence_value, "" );
\r
1367 * Convenience method.
\r
1368 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1370 public static void setConfidence( final PhylogenyNode node, final double confidence_value, final String type ) {
\r
1371 Confidence c = null;
\r
1372 if ( node.getBranchData().getNumberOfConfidences() > 0 ) {
\r
1373 c = node.getBranchData().getConfidence( 0 );
\r
1376 c = new Confidence();
\r
1377 node.getBranchData().addConfidence( c );
\r
1379 c.setType( type );
\r
1380 c.setValue( confidence_value );
\r
1383 public static void setScientificName( final PhylogenyNode node, final String scientific_name ) {
\r
1384 if ( !node.getNodeData().isHasTaxonomy() ) {
\r
1385 node.getNodeData().setTaxonomy( new Taxonomy() );
\r
1387 node.getNodeData().getTaxonomy().setScientificName( scientific_name );
\r
1391 * Convenience method to set the taxonomy code of a phylogeny node.
\r
1395 * @param taxonomy_code
\r
1396 * @throws PhyloXmlDataFormatException
\r
1398 public static void setTaxonomyCode( final PhylogenyNode node, final String taxonomy_code )
\r
1399 throws PhyloXmlDataFormatException {
\r
1400 if ( !node.getNodeData().isHasTaxonomy() ) {
\r
1401 node.getNodeData().setTaxonomy( new Taxonomy() );
\r
1403 node.getNodeData().getTaxonomy().setTaxonomyCode( taxonomy_code );
\r
1406 final static public void sortNodeDescendents( final PhylogenyNode node, final DESCENDANT_SORT_PRIORITY pri ) {
\r
1407 Comparator<PhylogenyNode> c;
\r
1410 c = new PhylogenyNodeSortSequencePriority();
\r
1413 c = new PhylogenyNodeSortNodeNamePriority();
\r
1416 c = new PhylogenyNodeSortTaxonomyPriority();
\r
1418 final List<PhylogenyNode> descs = node.getDescendants();
\r
1419 Collections.sort( descs, c );
\r
1421 for( final PhylogenyNode desc : descs ) {
\r
1422 node.setChildNode( i++, desc );
\r
1427 * Removes from Phylogeny to_be_stripped all external Nodes which are
\r
1428 * associated with a species NOT found in Phylogeny reference.
\r
1430 * @param reference
\r
1431 * a reference Phylogeny
\r
1432 * @param to_be_stripped
\r
1433 * Phylogeny to be stripped
\r
1434 * @return nodes removed from to_be_stripped
\r
1436 public static List<PhylogenyNode> taxonomyBasedDeletionOfExternalNodes( final Phylogeny reference,
\r
1437 final Phylogeny to_be_stripped ) {
\r
1438 final Set<String> ref_ext_taxo = new HashSet<String>();
\r
1439 for( final PhylogenyNodeIterator it = reference.iteratorExternalForward(); it.hasNext(); ) {
\r
1440 final PhylogenyNode n = it.next();
\r
1441 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1442 throw new IllegalArgumentException( "no taxonomic data in node: " + n );
\r
1444 if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
\r
1445 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getScientificName() );
\r
1447 if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
\r
1448 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1450 if ( ( n.getNodeData().getTaxonomy().getIdentifier() != null )
\r
1451 && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getIdentifier().getValue() ) ) {
\r
1452 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() );
\r
1455 final ArrayList<PhylogenyNode> nodes_to_delete = new ArrayList<PhylogenyNode>();
\r
1456 for( final PhylogenyNodeIterator it = to_be_stripped.iteratorExternalForward(); it.hasNext(); ) {
\r
1457 final PhylogenyNode n = it.next();
\r
1458 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1459 nodes_to_delete.add( n );
\r
1461 else if ( !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getScientificName() ) )
\r
1462 && !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1463 && !( ( n.getNodeData().getTaxonomy().getIdentifier() != null ) && ref_ext_taxo.contains( n
\r
1464 .getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() ) ) ) {
\r
1465 nodes_to_delete.add( n );
\r
1468 for( final PhylogenyNode n : nodes_to_delete ) {
\r
1469 to_be_stripped.deleteSubtree( n, true );
\r
1471 to_be_stripped.clearHashIdToNodeMap();
\r
1472 to_be_stripped.externalNodesHaveChanged();
\r
1473 return nodes_to_delete;
\r
1476 final static public void transferInternalNamesToBootstrapSupport( final Phylogeny phy ) {
\r
1477 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1478 while ( it.hasNext() ) {
\r
1479 final PhylogenyNode n = it.next();
\r
1480 if ( !n.isExternal() && !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1481 double value = -1;
\r
1483 value = Double.parseDouble( n.getName() );
\r
1485 catch ( final NumberFormatException e ) {
\r
1486 throw new IllegalArgumentException( "failed to parse number from [" + n.getName() + "]: "
\r
1487 + e.getLocalizedMessage() );
\r
1489 if ( value >= 0.0 ) {
\r
1490 n.getBranchData().addConfidence( new Confidence( value, "bootstrap" ) );
\r
1497 final static public boolean isInternalNamesLookLikeConfidences( final Phylogeny phy ) {
\r
1498 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1499 while ( it.hasNext() ) {
\r
1500 final PhylogenyNode n = it.next();
\r
1501 if ( !n.isExternal() && !n.isRoot() ) {
\r
1502 if ( !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1503 double value = -1;
\r
1505 value = Double.parseDouble( n.getName() );
\r
1507 catch ( final NumberFormatException e ) {
\r
1510 if ( ( value < 0.0 ) || ( value > 100 ) ) {
\r
1519 final static public void transferInternalNodeNamesToConfidence( final Phylogeny phy, final String confidence_type ) {
\r
1520 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1521 while ( it.hasNext() ) {
\r
1522 transferInternalNodeNameToConfidence( confidence_type, it.next() );
\r
1526 private static void transferInternalNodeNameToConfidence( final String confidence_type, final PhylogenyNode n ) {
\r
1527 if ( !n.isExternal() && !n.getBranchData().isHasConfidences() ) {
\r
1528 if ( !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1531 d = Double.parseDouble( n.getName() );
\r
1533 catch ( final Exception e ) {
\r
1537 n.getBranchData().addConfidence( new Confidence( d, confidence_type ) );
\r
1544 final static public void transferNodeNameToField( final Phylogeny phy,
\r
1545 final PhylogenyNodeField field,
\r
1546 final boolean external_only ) throws PhyloXmlDataFormatException {
\r
1547 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1548 while ( it.hasNext() ) {
\r
1549 final PhylogenyNode n = it.next();
\r
1550 if ( external_only && n.isInternal() ) {
\r
1553 final String name = n.getName().trim();
\r
1554 if ( !ForesterUtil.isEmpty( name ) ) {
\r
1555 switch ( field ) {
\r
1556 case TAXONOMY_CODE:
\r
1558 setTaxonomyCode( n, name );
\r
1560 case TAXONOMY_SCIENTIFIC_NAME:
\r
1562 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1563 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1565 n.getNodeData().getTaxonomy().setScientificName( name );
\r
1567 case TAXONOMY_COMMON_NAME:
\r
1569 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1570 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1572 n.getNodeData().getTaxonomy().setCommonName( name );
\r
1574 case SEQUENCE_SYMBOL:
\r
1576 if ( !n.getNodeData().isHasSequence() ) {
\r
1577 n.getNodeData().setSequence( new Sequence() );
\r
1579 n.getNodeData().getSequence().setSymbol( name );
\r
1581 case SEQUENCE_NAME:
\r
1583 if ( !n.getNodeData().isHasSequence() ) {
\r
1584 n.getNodeData().setSequence( new Sequence() );
\r
1586 n.getNodeData().getSequence().setName( name );
\r
1588 case TAXONOMY_ID_UNIPROT_1: {
\r
1589 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1590 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1593 final int i = name.indexOf( '_' );
\r
1595 id = name.substring( 0, i );
\r
1600 n.getNodeData().getTaxonomy()
\r
1601 .setIdentifier( new Identifier( id, PhyloXmlUtil.UNIPROT_TAX_PROVIDER ) );
\r
1604 case TAXONOMY_ID_UNIPROT_2: {
\r
1605 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1606 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1609 final int i = name.indexOf( '_' );
\r
1611 id = name.substring( i + 1, name.length() );
\r
1616 n.getNodeData().getTaxonomy()
\r
1617 .setIdentifier( new Identifier( id, PhyloXmlUtil.UNIPROT_TAX_PROVIDER ) );
\r
1620 case TAXONOMY_ID: {
\r
1621 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1622 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1624 n.getNodeData().getTaxonomy().setIdentifier( new Identifier( name ) );
\r
1632 static double addPhylogenyDistances( final double a, final double b ) {
\r
1633 if ( ( a >= 0.0 ) && ( b >= 0.0 ) ) {
\r
1636 else if ( a >= 0.0 ) {
\r
1639 else if ( b >= 0.0 ) {
\r
1642 return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
\r
1645 static double calculateDistanceToAncestor( final PhylogenyNode anc, PhylogenyNode desc ) {
\r
1647 boolean all_default = true;
\r
1648 while ( anc != desc ) {
\r
1649 if ( desc.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
\r
1650 d += desc.getDistanceToParent();
\r
1651 if ( all_default ) {
\r
1652 all_default = false;
\r
1655 desc = desc.getParent();
\r
1657 if ( all_default ) {
\r
1658 return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
\r
1664 * Deep copies the phylogeny originating from this node.
\r
1666 static PhylogenyNode copySubTree( final PhylogenyNode source ) {
\r
1667 if ( source == null ) {
\r
1671 final PhylogenyNode newnode = source.copyNodeData();
\r
1672 if ( !source.isExternal() ) {
\r
1673 for( int i = 0; i < source.getNumberOfDescendants(); ++i ) {
\r
1674 newnode.setChildNode( i, PhylogenyMethods.copySubTree( source.getChildNode( i ) ) );
\r
1682 * Shallow copies the phylogeny originating from this node.
\r
1684 static PhylogenyNode copySubTreeShallow( final PhylogenyNode source ) {
\r
1685 if ( source == null ) {
\r
1689 final PhylogenyNode newnode = source.copyNodeDataShallow();
\r
1690 if ( !source.isExternal() ) {
\r
1691 for( int i = 0; i < source.getNumberOfDescendants(); ++i ) {
\r
1692 newnode.setChildNode( i, PhylogenyMethods.copySubTreeShallow( source.getChildNode( i ) ) );
\r
1699 private final static List<PhylogenyNode> divideIntoSubTreesHelper( final PhylogenyNode node,
\r
1700 final double min_distance_to_root ) {
\r
1701 final List<PhylogenyNode> l = new ArrayList<PhylogenyNode>();
\r
1702 final PhylogenyNode r = moveTowardsRoot( node, min_distance_to_root );
\r
1703 for( final PhylogenyNode ext : r.getAllExternalDescendants() ) {
\r
1704 if ( ext.getIndicator() != 0 ) {
\r
1705 throw new RuntimeException( "this should not have happened" );
\r
1707 ext.setIndicator( ( byte ) 1 );
\r
1714 * Calculates the distance between PhylogenyNodes n1 and n2.
\r
1715 * PRECONDITION: n1 is a descendant of n2.
\r
1718 * a descendant of n2
\r
1720 * @return distance between n1 and n2
\r
1722 private static double getDistance( PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1724 while ( n1 != n2 ) {
\r
1725 if ( n1.getDistanceToParent() > 0.0 ) {
\r
1726 d += n1.getDistanceToParent();
\r
1728 n1 = n1.getParent();
\r
1733 private static boolean match( final String s,
\r
1734 final String query,
\r
1735 final boolean case_sensitive,
\r
1736 final boolean partial,
\r
1737 final boolean regex ) {
\r
1738 if ( ForesterUtil.isEmpty( s ) || ForesterUtil.isEmpty( query ) ) {
\r
1741 String my_s = s.trim();
\r
1742 String my_query = query.trim();
\r
1743 if ( !case_sensitive && !regex ) {
\r
1744 my_s = my_s.toLowerCase();
\r
1745 my_query = my_query.toLowerCase();
\r
1750 if ( case_sensitive ) {
\r
1751 p = Pattern.compile( my_query );
\r
1754 p = Pattern.compile( my_query, Pattern.CASE_INSENSITIVE );
\r
1757 catch ( final PatternSyntaxException e ) {
\r
1760 if ( p != null ) {
\r
1761 return p.matcher( my_s ).find();
\r
1767 else if ( partial ) {
\r
1768 return my_s.indexOf( my_query ) >= 0;
\r
1773 p = Pattern.compile( "(\\b|_)" + Pattern.quote( my_query ) + "(\\b|_)" );
\r
1775 catch ( final PatternSyntaxException e ) {
\r
1778 if ( p != null ) {
\r
1779 return p.matcher( my_s ).find();
\r
1787 private final static PhylogenyNode moveTowardsRoot( final PhylogenyNode node, final double min_distance_to_root ) {
\r
1788 PhylogenyNode n = node;
\r
1789 PhylogenyNode prev = node;
\r
1790 while ( min_distance_to_root < n.calculateDistanceToRoot() ) {
\r
1792 n = n.getParent();
\r
1797 public static enum DESCENDANT_SORT_PRIORITY {
\r
1798 NODE_NAME, SEQUENCE, TAXONOMY;
\r
1801 public static enum PhylogenyNodeField {
\r
1806 TAXONOMY_COMMON_NAME,
\r
1808 TAXONOMY_ID_UNIPROT_1,
\r
1809 TAXONOMY_ID_UNIPROT_2,
\r
1810 TAXONOMY_SCIENTIFIC_NAME;
\r
1813 public static void addMolecularSeqsToTree( final Phylogeny phy, final Msa msa ) {
\r
1814 for( int s = 0; s < msa.getNumberOfSequences(); ++s ) {
\r
1815 final org.forester.sequence.MolecularSequence seq = msa.getSequence( s );
\r
1816 final PhylogenyNode node = phy.getNode( seq.getIdentifier() );
\r
1817 final org.forester.phylogeny.data.Sequence new_seq = new Sequence();
\r
1818 new_seq.setMolecularSequenceAligned( true );
\r
1819 new_seq.setMolecularSequence( seq.getMolecularSequenceAsString() );
\r
1820 new_seq.setName( seq.getIdentifier() );
\r
1822 new_seq.setType( PhyloXmlUtil.SEQ_TYPE_PROTEIN );
\r
1824 catch ( final PhyloXmlDataFormatException ignore ) {
\r
1827 node.getNodeData().addSequence( new_seq );
\r
1831 final private static class PhylogenyNodeSortTaxonomyPriority implements Comparator<PhylogenyNode> {
\r
1834 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1835 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1836 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1837 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1838 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1839 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1841 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1842 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1843 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1844 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1847 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1848 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1849 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1850 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1851 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1853 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1854 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1855 return n1.getNodeData().getSequence().getGeneName()
\r
1856 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1858 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1859 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1860 return n1.getNodeData().getSequence().getSymbol()
\r
1861 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r
1864 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1865 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1871 final private static class PhylogenyNodeSortSequencePriority implements Comparator<PhylogenyNode> {
\r
1874 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1875 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1876 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1877 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1878 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1879 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1881 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1882 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1883 return n1.getNodeData().getSequence().getGeneName()
\r
1884 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1886 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1887 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1888 return n1.getNodeData().getSequence().getSymbol()
\r
1889 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r
1892 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1893 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1894 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1895 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1896 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1898 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1899 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1900 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1901 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1904 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1905 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1911 final private static class PhylogenyNodeSortNodeNamePriority implements Comparator<PhylogenyNode> {
\r
1914 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1915 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1916 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1918 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1919 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1920 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1921 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1922 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1924 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1925 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1926 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1927 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1930 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1931 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1932 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1933 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1934 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1936 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1937 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1938 return n1.getNodeData().getSequence().getGeneName()
\r
1939 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1941 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1942 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1943 return n1.getNodeData().getSequence().getSymbol()
\r
1944 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r