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
1161 if ( query == null ) {
\r
1164 query = query.trim();
\r
1166 if ( ( query.length() > 2 ) && ( query.indexOf( ":" ) == 2 ) ) {
\r
1167 ndf = NDF.fromString( query );
\r
1168 if ( ndf != null ) {
\r
1169 query = query.substring( 3 );
\r
1172 boolean match = false;
\r
1173 if ( ForesterUtil.isEmpty( query ) ) {
\r
1176 if ( ( ( ndf == null ) || ( ndf == NDF.NodeName ) )
\r
1177 && match( node.getName(), query, case_sensitive, partial, false ) ) {
\r
1180 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCode ) )
\r
1181 && node.getNodeData().isHasTaxonomy()
\r
1182 && match( node.getNodeData().getTaxonomy().getTaxonomyCode(),
\r
1189 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyCommonName ) )
\r
1190 && node.getNodeData().isHasTaxonomy()
\r
1191 && match( node.getNodeData().getTaxonomy().getCommonName(),
\r
1198 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyScientificName ) )
\r
1199 && node.getNodeData().isHasTaxonomy()
\r
1200 && match( node.getNodeData().getTaxonomy().getScientificName(),
\r
1207 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomyIdentifier ) )
\r
1208 && node.getNodeData().isHasTaxonomy()
\r
1209 && ( node.getNodeData().getTaxonomy().getIdentifier() != null )
\r
1210 && match( node.getNodeData().getTaxonomy().getIdentifier().getValue(),
\r
1217 else if ( ( ( ndf == null ) || ( ndf == NDF.TaxonomySynonym ) ) && node.getNodeData().isHasTaxonomy()
\r
1218 && !node.getNodeData().getTaxonomy().getSynonyms().isEmpty() ) {
\r
1219 final List<String> syns = node.getNodeData().getTaxonomy().getSynonyms();
\r
1220 I: for( final String syn : syns ) {
\r
1221 if ( match( syn, query, case_sensitive, partial, false ) ) {
\r
1227 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceName ) ) && node.getNodeData().isHasSequence()
\r
1228 && match( node.getNodeData().getSequence().getName(), query, case_sensitive, partial, false ) ) {
\r
1232 && ( ( ndf == null ) || ( ndf == NDF.GeneName ) )
\r
1233 && node.getNodeData().isHasSequence()
\r
1234 && match( node.getNodeData().getSequence().getGeneName(), query, case_sensitive, partial, false ) ) {
\r
1237 if ( !match && ( ( ndf == null ) || ( ndf == NDF.SequenceSymbol ) )
\r
1238 && node.getNodeData().isHasSequence()
\r
1239 && match( node.getNodeData().getSequence().getSymbol(), query, case_sensitive, partial, false ) ) {
\r
1243 && ( ( ndf == null ) || ( ndf == NDF.SequenceAccession ) )
\r
1244 && node.getNodeData().isHasSequence()
\r
1245 && ( node.getNodeData().getSequence().getAccession() != null )
\r
1246 && match( node.getNodeData().getSequence().getAccession().getValue(),
\r
1253 if ( !match && ( ( ( ndf == null ) && search_domains ) || ( ndf == NDF.Domain ) )
\r
1254 && node.getNodeData().isHasSequence()
\r
1255 && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
\r
1256 final DomainArchitecture da = node.getNodeData().getSequence().getDomainArchitecture();
\r
1257 I: for( int i = 0; i < da.getNumberOfDomains(); ++i ) {
\r
1258 if ( ( da.getDomain( i ).getConfidence() <= domains_confidence_threshold )
\r
1259 && match( da.getDomain( i ).getName(), query, case_sensitive, partial, false ) ) {
\r
1265 if ( !match && ( ( ndf == null ) || ( ndf == NDF.Annotation ) ) && node.getNodeData().isHasSequence()
\r
1266 && ( node.getNodeData().getSequence().getAnnotations() != null ) ) {
\r
1267 for( final Annotation ann : node.getNodeData().getSequence().getAnnotations() ) {
\r
1268 if ( match( ann.getDesc(), query, case_sensitive, partial, false ) ) {
\r
1272 if ( match( ann.getRef(), query, case_sensitive, partial, false ) ) {
\r
1278 if ( !match && ( ( ndf == null ) || ( ndf == NDF.CrossRef ) ) && node.getNodeData().isHasSequence()
\r
1279 && ( node.getNodeData().getSequence().getCrossReferences() != null ) ) {
\r
1280 for( final Accession x : node.getNodeData().getSequence().getCrossReferences() ) {
\r
1281 if ( match( x.getComment(), query, case_sensitive, partial, false ) ) {
\r
1285 if ( match( x.getSource(), query, case_sensitive, partial, false ) ) {
\r
1289 if ( match( x.getValue(), query, case_sensitive, partial, false ) ) {
\r
1295 if ( !match && ( ( ndf == null ) || ( ndf == NDF.BinaryCharacter ) )
\r
1296 && ( node.getNodeData().getBinaryCharacters() != null ) ) {
\r
1297 Iterator<String> it = node.getNodeData().getBinaryCharacters().getPresentCharacters().iterator();
\r
1298 I: while ( it.hasNext() ) {
\r
1299 if ( match( it.next(), query, case_sensitive, partial, false ) ) {
\r
1304 it = node.getNodeData().getBinaryCharacters().getGainedCharacters().iterator();
\r
1305 I: while ( it.hasNext() ) {
\r
1306 if ( match( it.next(), query, case_sensitive, partial, false ) ) {
\r
1313 && ( ndf == NDF.MolecularSequence )
\r
1314 && node.getNodeData().isHasSequence()
\r
1315 && match( node.getNodeData().getSequence().getMolecularSequence(),
\r
1323 all_matched = false;
\r
1327 if ( all_matched ) {
\r
1328 nodes.add( node );
\r
1334 public static void setAllIndicatorsToZero( final Phylogeny phy ) {
\r
1335 for( final PhylogenyNodeIterator it = phy.iteratorPostorder(); it.hasNext(); ) {
\r
1336 it.next().setIndicator( ( byte ) 0 );
\r
1341 * Convenience method.
\r
1342 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1344 public static void setBootstrapConfidence( final PhylogenyNode node, final double bootstrap_confidence_value ) {
\r
1345 setConfidence( node, bootstrap_confidence_value, "bootstrap" );
\r
1348 public static void setBranchColorValue( final PhylogenyNode node, final Color color ) {
\r
1349 if ( node.getBranchData().getBranchColor() == null ) {
\r
1350 node.getBranchData().setBranchColor( new BranchColor() );
\r
1352 node.getBranchData().getBranchColor().setValue( color );
\r
1356 * Convenience method
\r
1358 public static void setBranchWidthValue( final PhylogenyNode node, final double branch_width_value ) {
\r
1359 node.getBranchData().setBranchWidth( new BranchWidth( branch_width_value ) );
\r
1363 * Convenience method.
\r
1364 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1366 public static void setConfidence( final PhylogenyNode node, final double confidence_value ) {
\r
1367 setConfidence( node, confidence_value, "" );
\r
1371 * Convenience method.
\r
1372 * Sets value for the first confidence value (created if not present, values overwritten otherwise).
\r
1374 public static void setConfidence( final PhylogenyNode node, final double confidence_value, final String type ) {
\r
1375 Confidence c = null;
\r
1376 if ( node.getBranchData().getNumberOfConfidences() > 0 ) {
\r
1377 c = node.getBranchData().getConfidence( 0 );
\r
1380 c = new Confidence();
\r
1381 node.getBranchData().addConfidence( c );
\r
1383 c.setType( type );
\r
1384 c.setValue( confidence_value );
\r
1387 public static void setScientificName( final PhylogenyNode node, final String scientific_name ) {
\r
1388 if ( !node.getNodeData().isHasTaxonomy() ) {
\r
1389 node.getNodeData().setTaxonomy( new Taxonomy() );
\r
1391 node.getNodeData().getTaxonomy().setScientificName( scientific_name );
\r
1395 * Convenience method to set the taxonomy code of a phylogeny node.
\r
1399 * @param taxonomy_code
\r
1400 * @throws PhyloXmlDataFormatException
\r
1402 public static void setTaxonomyCode( final PhylogenyNode node, final String taxonomy_code )
\r
1403 throws PhyloXmlDataFormatException {
\r
1404 if ( !node.getNodeData().isHasTaxonomy() ) {
\r
1405 node.getNodeData().setTaxonomy( new Taxonomy() );
\r
1407 node.getNodeData().getTaxonomy().setTaxonomyCode( taxonomy_code );
\r
1410 final static public void sortNodeDescendents( final PhylogenyNode node, final DESCENDANT_SORT_PRIORITY pri ) {
\r
1411 Comparator<PhylogenyNode> c;
\r
1414 c = new PhylogenyNodeSortSequencePriority();
\r
1417 c = new PhylogenyNodeSortNodeNamePriority();
\r
1420 c = new PhylogenyNodeSortTaxonomyPriority();
\r
1422 final List<PhylogenyNode> descs = node.getDescendants();
\r
1423 Collections.sort( descs, c );
\r
1425 for( final PhylogenyNode desc : descs ) {
\r
1426 node.setChildNode( i++, desc );
\r
1431 * Removes from Phylogeny to_be_stripped all external Nodes which are
\r
1432 * associated with a species NOT found in Phylogeny reference.
\r
1434 * @param reference
\r
1435 * a reference Phylogeny
\r
1436 * @param to_be_stripped
\r
1437 * Phylogeny to be stripped
\r
1438 * @return nodes removed from to_be_stripped
\r
1440 public static List<PhylogenyNode> taxonomyBasedDeletionOfExternalNodes( final Phylogeny reference,
\r
1441 final Phylogeny to_be_stripped ) {
\r
1442 final Set<String> ref_ext_taxo = new HashSet<String>();
\r
1443 for( final PhylogenyNodeIterator it = reference.iteratorExternalForward(); it.hasNext(); ) {
\r
1444 final PhylogenyNode n = it.next();
\r
1445 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1446 throw new IllegalArgumentException( "no taxonomic data in node: " + n );
\r
1448 if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
\r
1449 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getScientificName() );
\r
1451 if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
\r
1452 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1454 if ( ( n.getNodeData().getTaxonomy().getIdentifier() != null )
\r
1455 && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getIdentifier().getValue() ) ) {
\r
1456 ref_ext_taxo.add( n.getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() );
\r
1459 final ArrayList<PhylogenyNode> nodes_to_delete = new ArrayList<PhylogenyNode>();
\r
1460 for( final PhylogenyNodeIterator it = to_be_stripped.iteratorExternalForward(); it.hasNext(); ) {
\r
1461 final PhylogenyNode n = it.next();
\r
1462 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1463 nodes_to_delete.add( n );
\r
1465 else if ( !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getScientificName() ) )
\r
1466 && !( ref_ext_taxo.contains( n.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1467 && !( ( n.getNodeData().getTaxonomy().getIdentifier() != null ) && ref_ext_taxo.contains( n
\r
1468 .getNodeData().getTaxonomy().getIdentifier().getValuePlusProvider() ) ) ) {
\r
1469 nodes_to_delete.add( n );
\r
1472 for( final PhylogenyNode n : nodes_to_delete ) {
\r
1473 to_be_stripped.deleteSubtree( n, true );
\r
1475 to_be_stripped.clearHashIdToNodeMap();
\r
1476 to_be_stripped.externalNodesHaveChanged();
\r
1477 return nodes_to_delete;
\r
1480 final static public void transferInternalNamesToBootstrapSupport( final Phylogeny phy ) {
\r
1481 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1482 while ( it.hasNext() ) {
\r
1483 final PhylogenyNode n = it.next();
\r
1484 if ( !n.isExternal() && !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1485 double value = -1;
\r
1487 value = Double.parseDouble( n.getName() );
\r
1489 catch ( final NumberFormatException e ) {
\r
1490 throw new IllegalArgumentException( "failed to parse number from [" + n.getName() + "]: "
\r
1491 + e.getLocalizedMessage() );
\r
1493 if ( value >= 0.0 ) {
\r
1494 n.getBranchData().addConfidence( new Confidence( value, "bootstrap" ) );
\r
1501 final static public boolean isInternalNamesLookLikeConfidences( final Phylogeny phy ) {
\r
1502 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1503 while ( it.hasNext() ) {
\r
1504 final PhylogenyNode n = it.next();
\r
1505 if ( !n.isExternal() && !n.isRoot() ) {
\r
1506 if ( !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1507 double value = -1;
\r
1509 value = Double.parseDouble( n.getName() );
\r
1511 catch ( final NumberFormatException e ) {
\r
1514 if ( ( value < 0.0 ) || ( value > 100 ) ) {
\r
1523 final static public void transferInternalNodeNamesToConfidence( final Phylogeny phy, final String confidence_type ) {
\r
1524 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1525 while ( it.hasNext() ) {
\r
1526 transferInternalNodeNameToConfidence( confidence_type, it.next() );
\r
1530 private static void transferInternalNodeNameToConfidence( final String confidence_type, final PhylogenyNode n ) {
\r
1531 if ( !n.isExternal() && !n.getBranchData().isHasConfidences() ) {
\r
1532 if ( !ForesterUtil.isEmpty( n.getName() ) ) {
\r
1535 d = Double.parseDouble( n.getName() );
\r
1537 catch ( final Exception e ) {
\r
1541 n.getBranchData().addConfidence( new Confidence( d, confidence_type ) );
\r
1548 final static public void transferNodeNameToField( final Phylogeny phy,
\r
1549 final PhylogenyNodeField field,
\r
1550 final boolean external_only ) throws PhyloXmlDataFormatException {
\r
1551 final PhylogenyNodeIterator it = phy.iteratorPostorder();
\r
1552 while ( it.hasNext() ) {
\r
1553 final PhylogenyNode n = it.next();
\r
1554 if ( external_only && n.isInternal() ) {
\r
1557 final String name = n.getName().trim();
\r
1558 if ( !ForesterUtil.isEmpty( name ) ) {
\r
1559 switch ( field ) {
\r
1560 case TAXONOMY_CODE:
\r
1562 setTaxonomyCode( n, name );
\r
1564 case TAXONOMY_SCIENTIFIC_NAME:
\r
1566 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1567 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1569 n.getNodeData().getTaxonomy().setScientificName( name );
\r
1571 case TAXONOMY_COMMON_NAME:
\r
1573 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1574 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1576 n.getNodeData().getTaxonomy().setCommonName( name );
\r
1578 case SEQUENCE_SYMBOL:
\r
1580 if ( !n.getNodeData().isHasSequence() ) {
\r
1581 n.getNodeData().setSequence( new Sequence() );
\r
1583 n.getNodeData().getSequence().setSymbol( name );
\r
1585 case SEQUENCE_NAME:
\r
1587 if ( !n.getNodeData().isHasSequence() ) {
\r
1588 n.getNodeData().setSequence( new Sequence() );
\r
1590 n.getNodeData().getSequence().setName( name );
\r
1592 case TAXONOMY_ID_UNIPROT_1: {
\r
1593 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1594 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1597 final int i = name.indexOf( '_' );
\r
1599 id = name.substring( 0, i );
\r
1604 n.getNodeData().getTaxonomy()
\r
1605 .setIdentifier( new Identifier( id, PhyloXmlUtil.UNIPROT_TAX_PROVIDER ) );
\r
1608 case TAXONOMY_ID_UNIPROT_2: {
\r
1609 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1610 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1613 final int i = name.indexOf( '_' );
\r
1615 id = name.substring( i + 1, name.length() );
\r
1620 n.getNodeData().getTaxonomy()
\r
1621 .setIdentifier( new Identifier( id, PhyloXmlUtil.UNIPROT_TAX_PROVIDER ) );
\r
1624 case TAXONOMY_ID: {
\r
1625 if ( !n.getNodeData().isHasTaxonomy() ) {
\r
1626 n.getNodeData().setTaxonomy( new Taxonomy() );
\r
1628 n.getNodeData().getTaxonomy().setIdentifier( new Identifier( name ) );
\r
1636 static double addPhylogenyDistances( final double a, final double b ) {
\r
1637 if ( ( a >= 0.0 ) && ( b >= 0.0 ) ) {
\r
1640 else if ( a >= 0.0 ) {
\r
1643 else if ( b >= 0.0 ) {
\r
1646 return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
\r
1649 static double calculateDistanceToAncestor( final PhylogenyNode anc, PhylogenyNode desc ) {
\r
1651 boolean all_default = true;
\r
1652 while ( anc != desc ) {
\r
1653 if ( desc.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) {
\r
1654 d += desc.getDistanceToParent();
\r
1655 if ( all_default ) {
\r
1656 all_default = false;
\r
1659 desc = desc.getParent();
\r
1661 if ( all_default ) {
\r
1662 return PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT;
\r
1668 * Deep copies the phylogeny originating from this node.
\r
1670 static PhylogenyNode copySubTree( final PhylogenyNode source ) {
\r
1671 if ( source == null ) {
\r
1675 final PhylogenyNode newnode = source.copyNodeData();
\r
1676 if ( !source.isExternal() ) {
\r
1677 for( int i = 0; i < source.getNumberOfDescendants(); ++i ) {
\r
1678 newnode.setChildNode( i, PhylogenyMethods.copySubTree( source.getChildNode( i ) ) );
\r
1686 * Shallow copies the phylogeny originating from this node.
\r
1688 static PhylogenyNode copySubTreeShallow( final PhylogenyNode source ) {
\r
1689 if ( source == null ) {
\r
1693 final PhylogenyNode newnode = source.copyNodeDataShallow();
\r
1694 if ( !source.isExternal() ) {
\r
1695 for( int i = 0; i < source.getNumberOfDescendants(); ++i ) {
\r
1696 newnode.setChildNode( i, PhylogenyMethods.copySubTreeShallow( source.getChildNode( i ) ) );
\r
1703 private final static List<PhylogenyNode> divideIntoSubTreesHelper( final PhylogenyNode node,
\r
1704 final double min_distance_to_root ) {
\r
1705 final List<PhylogenyNode> l = new ArrayList<PhylogenyNode>();
\r
1706 final PhylogenyNode r = moveTowardsRoot( node, min_distance_to_root );
\r
1707 for( final PhylogenyNode ext : r.getAllExternalDescendants() ) {
\r
1708 if ( ext.getIndicator() != 0 ) {
\r
1709 throw new RuntimeException( "this should not have happened" );
\r
1711 ext.setIndicator( ( byte ) 1 );
\r
1718 * Calculates the distance between PhylogenyNodes n1 and n2.
\r
1719 * PRECONDITION: n1 is a descendant of n2.
\r
1722 * a descendant of n2
\r
1724 * @return distance between n1 and n2
\r
1726 private static double getDistance( PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1728 while ( n1 != n2 ) {
\r
1729 if ( n1.getDistanceToParent() > 0.0 ) {
\r
1730 d += n1.getDistanceToParent();
\r
1732 n1 = n1.getParent();
\r
1737 private static boolean match( final String s,
\r
1738 final String query,
\r
1739 final boolean case_sensitive,
\r
1740 final boolean partial,
\r
1741 final boolean regex ) {
\r
1742 if ( ForesterUtil.isEmpty( s ) || ForesterUtil.isEmpty( query ) ) {
\r
1745 String my_s = s.trim();
\r
1746 String my_query = query.trim();
\r
1747 if ( !case_sensitive && !regex ) {
\r
1748 my_s = my_s.toLowerCase();
\r
1749 my_query = my_query.toLowerCase();
\r
1754 if ( case_sensitive ) {
\r
1755 p = Pattern.compile( my_query );
\r
1758 p = Pattern.compile( my_query, Pattern.CASE_INSENSITIVE );
\r
1761 catch ( final PatternSyntaxException e ) {
\r
1764 if ( p != null ) {
\r
1765 return p.matcher( my_s ).find();
\r
1771 else if ( partial ) {
\r
1772 return my_s.indexOf( my_query ) >= 0;
\r
1777 p = Pattern.compile( "(\\b|_)" + Pattern.quote( my_query ) + "(\\b|_)" );
\r
1779 catch ( final PatternSyntaxException e ) {
\r
1782 if ( p != null ) {
\r
1783 return p.matcher( my_s ).find();
\r
1791 private final static PhylogenyNode moveTowardsRoot( final PhylogenyNode node, final double min_distance_to_root ) {
\r
1792 PhylogenyNode n = node;
\r
1793 PhylogenyNode prev = node;
\r
1794 while ( min_distance_to_root < n.calculateDistanceToRoot() ) {
\r
1796 n = n.getParent();
\r
1801 public static enum DESCENDANT_SORT_PRIORITY {
\r
1802 NODE_NAME, SEQUENCE, TAXONOMY;
\r
1805 public static enum PhylogenyNodeField {
\r
1810 TAXONOMY_COMMON_NAME,
\r
1812 TAXONOMY_ID_UNIPROT_1,
\r
1813 TAXONOMY_ID_UNIPROT_2,
\r
1814 TAXONOMY_SCIENTIFIC_NAME;
\r
1817 public static void addMolecularSeqsToTree( final Phylogeny phy, final Msa msa ) {
\r
1818 for( int s = 0; s < msa.getNumberOfSequences(); ++s ) {
\r
1819 final org.forester.sequence.MolecularSequence seq = msa.getSequence( s );
\r
1820 final PhylogenyNode node = phy.getNode( seq.getIdentifier() );
\r
1821 final org.forester.phylogeny.data.Sequence new_seq = new Sequence();
\r
1822 new_seq.setMolecularSequenceAligned( true );
\r
1823 new_seq.setMolecularSequence( seq.getMolecularSequenceAsString() );
\r
1824 new_seq.setName( seq.getIdentifier() );
\r
1826 new_seq.setType( PhyloXmlUtil.SEQ_TYPE_PROTEIN );
\r
1828 catch ( final PhyloXmlDataFormatException ignore ) {
\r
1831 node.getNodeData().addSequence( new_seq );
\r
1835 final private static class PhylogenyNodeSortTaxonomyPriority implements Comparator<PhylogenyNode> {
\r
1838 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1839 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1840 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1841 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1842 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1843 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1845 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1846 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1847 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1848 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1851 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1852 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1853 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1854 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1855 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1857 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1858 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1859 return n1.getNodeData().getSequence().getGeneName()
\r
1860 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1862 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1863 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1864 return n1.getNodeData().getSequence().getSymbol()
\r
1865 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r
1868 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1869 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1875 final private static class PhylogenyNodeSortSequencePriority implements Comparator<PhylogenyNode> {
\r
1878 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1879 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1880 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1881 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1882 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1883 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1885 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1886 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1887 return n1.getNodeData().getSequence().getGeneName()
\r
1888 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1890 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1891 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1892 return n1.getNodeData().getSequence().getSymbol()
\r
1893 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r
1896 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1897 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1898 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1899 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1900 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1902 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1903 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1904 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1905 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1908 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1909 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1915 final private static class PhylogenyNodeSortNodeNamePriority implements Comparator<PhylogenyNode> {
\r
1918 public int compare( final PhylogenyNode n1, final PhylogenyNode n2 ) {
\r
1919 if ( ( !ForesterUtil.isEmpty( n1.getName() ) ) && ( !ForesterUtil.isEmpty( n2.getName() ) ) ) {
\r
1920 return n1.getName().toLowerCase().compareTo( n2.getName().toLowerCase() );
\r
1922 if ( n1.getNodeData().isHasTaxonomy() && n2.getNodeData().isHasTaxonomy() ) {
\r
1923 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getScientificName() ) )
\r
1924 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getScientificName() ) ) ) {
\r
1925 return n1.getNodeData().getTaxonomy().getScientificName().toLowerCase()
\r
1926 .compareTo( n2.getNodeData().getTaxonomy().getScientificName().toLowerCase() );
\r
1928 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getTaxonomy().getTaxonomyCode() ) )
\r
1929 && ( !ForesterUtil.isEmpty( n2.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
\r
1930 return n1.getNodeData().getTaxonomy().getTaxonomyCode()
\r
1931 .compareTo( n2.getNodeData().getTaxonomy().getTaxonomyCode() );
\r
1934 if ( n1.getNodeData().isHasSequence() && n2.getNodeData().isHasSequence() ) {
\r
1935 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getName() ) )
\r
1936 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getName() ) ) ) {
\r
1937 return n1.getNodeData().getSequence().getName().toLowerCase()
\r
1938 .compareTo( n2.getNodeData().getSequence().getName().toLowerCase() );
\r
1940 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getGeneName() ) )
\r
1941 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getGeneName() ) ) ) {
\r
1942 return n1.getNodeData().getSequence().getGeneName()
\r
1943 .compareTo( n2.getNodeData().getSequence().getGeneName() );
\r
1945 if ( ( !ForesterUtil.isEmpty( n1.getNodeData().getSequence().getSymbol() ) )
\r
1946 && ( !ForesterUtil.isEmpty( n2.getNodeData().getSequence().getSymbol() ) ) ) {
\r
1947 return n1.getNodeData().getSequence().getSymbol()
\r
1948 .compareTo( n2.getNodeData().getSequence().getSymbol() );
\r