082efa9719ebce6bda3bd6e9085cc21ef0eaadc1
[jalview.git] / forester / java / src / org / forester / archaeopteryx / TreePanelUtil.java
1
2 package org.forester.archaeopteryx;
3
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.io.UnsupportedEncodingException;
7 import java.net.URLEncoder;
8 import java.util.ArrayList;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Map.Entry;
14 import java.util.Set;
15 import java.util.SortedMap;
16 import java.util.SortedSet;
17 import java.util.TreeMap;
18
19 import javax.swing.JOptionPane;
20
21 import org.forester.analysis.TaxonomyDataManager;
22 import org.forester.phylogeny.Phylogeny;
23 import org.forester.phylogeny.PhylogenyMethods;
24 import org.forester.phylogeny.PhylogenyNode;
25 import org.forester.phylogeny.data.Annotation;
26 import org.forester.phylogeny.data.BranchColor;
27 import org.forester.phylogeny.data.Sequence;
28 import org.forester.phylogeny.data.Taxonomy;
29 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
30 import org.forester.phylogeny.iterators.PreorderTreeIterator;
31 import org.forester.util.ForesterConstants;
32 import org.forester.util.ForesterUtil;
33 import org.forester.util.SequenceIdParser;
34 import org.forester.ws.seqdb.UniProtTaxonomy;
35
36 public class TreePanelUtil {
37
38     public final static String createUriForSeqWeb( final PhylogenyNode node,
39                                                    final Configuration conf,
40                                                    final TreePanel tp ) {
41         String uri_str = null;
42         final String upkb = ForesterUtil.extractUniProtKbProteinSeqIdentifier( node );
43         if ( !ForesterUtil.isEmpty( upkb ) ) {
44             try {
45                 uri_str = ForesterUtil.UNIPROT_KB + URLEncoder.encode( upkb, ForesterConstants.UTF8 );
46             }
47             catch ( final UnsupportedEncodingException e ) {
48                 AptxUtil.showErrorMessage( tp, e.toString() );
49                 e.printStackTrace();
50             }
51         }
52         if ( ForesterUtil.isEmpty( uri_str ) ) {
53             final String v = ForesterUtil.extractGenbankAccessor( node );
54             if ( !ForesterUtil.isEmpty( v ) ) {
55                 try {
56                     if ( SequenceIdParser.isProtein( v ) ) {
57                         uri_str = ForesterUtil.NCBI_PROTEIN + URLEncoder.encode( v, ForesterConstants.UTF8 );
58                     }
59                     else {
60                         uri_str = ForesterUtil.NCBI_NUCCORE + URLEncoder.encode( v, ForesterConstants.UTF8 );
61                     }
62                 }
63                 catch ( final UnsupportedEncodingException e ) {
64                     AptxUtil.showErrorMessage( tp, e.toString() );
65                     e.printStackTrace();
66                 }
67             }
68         }
69         if ( ForesterUtil.isEmpty( uri_str ) ) {
70             final String v = ForesterUtil.extractRefSeqAccessorAccessor( node );
71             if ( !ForesterUtil.isEmpty( v ) ) {
72                 try {
73                     if ( SequenceIdParser.isProtein( v ) ) {
74                         uri_str = ForesterUtil.NCBI_PROTEIN + URLEncoder.encode( v, ForesterConstants.UTF8 );
75                     }
76                     else {
77                         uri_str = ForesterUtil.NCBI_NUCCORE + URLEncoder.encode( v, ForesterConstants.UTF8 );
78                     }
79                 }
80                 catch ( final UnsupportedEncodingException e ) {
81                     AptxUtil.showErrorMessage( tp, e.toString() );
82                     e.printStackTrace();
83                 }
84             }
85         }
86         if ( ForesterUtil.isEmpty( uri_str ) ) {
87             final String v = ForesterUtil.extractGInumber( node );
88             if ( !ForesterUtil.isEmpty( v ) ) {
89                 try {
90                     uri_str = ForesterUtil.NCBI_GI + URLEncoder.encode( v, ForesterConstants.UTF8 );
91                 }
92                 catch ( final UnsupportedEncodingException e ) {
93                     AptxUtil.showErrorMessage( tp, e.toString() );
94                     e.printStackTrace();
95                 }
96             }
97         }
98         return uri_str;
99     }
100
101     /**
102      * Returns the set of distinct taxonomies of
103      * all external nodes of node.
104      * If at least one the external nodes has no taxonomy,
105      * null is returned.
106      * 
107      */
108     public static Set<Taxonomy> obtainDistinctTaxonomies( final PhylogenyNode node ) {
109         final List<PhylogenyNode> descs = node.getAllExternalDescendants();
110         final Set<Taxonomy> tax_set = new HashSet<Taxonomy>();
111         for( final PhylogenyNode n : descs ) {
112             if ( !n.getNodeData().isHasTaxonomy() || n.getNodeData().getTaxonomy().isEmpty() ) {
113                 return null;
114             }
115             tax_set.add( n.getNodeData().getTaxonomy() );
116         }
117         return tax_set;
118     }
119
120     public final static void showExtDescNodeDataUserSelectedHelper( final ControlPanel cp,
121                                                                     final PhylogenyNode node,
122                                                                     final List<String> data ) {
123         final StringBuilder sb = new StringBuilder();
124         if ( cp.isShowNodeNames() && !ForesterUtil.isEmpty( node.getName() ) ) {
125             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getName(), sb );
126         }
127         if ( cp.isShowGeneNames() && node.getNodeData().isHasSequence()
128                 && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) {
129             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getSequence().getName(), sb );
130         }
131         if ( cp.isShowGeneSymbols() && node.getNodeData().isHasSequence()
132                 && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) {
133             TreePanelUtil
134                     .showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getSequence().getSymbol(), sb );
135         }
136         if ( cp.isShowSequenceAcc() && node.getNodeData().isHasSequence()
137                 && ( node.getNodeData().getSequence().getAccession() != null )
138                 && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().toString() ) ) {
139             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getSequence().getAccession()
140                     .toString(), sb );
141         }
142         if ( cp.isShowTaxonomyCode() && node.getNodeData().isHasTaxonomy()
143                 && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
144             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getTaxonomy()
145                     .getTaxonomyCode(), sb );
146         }
147         if ( cp.isShowTaxonomyScientificNames() && node.getNodeData().isHasTaxonomy()
148                 && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) {
149             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getTaxonomy()
150                     .getScientificName(), sb );
151         }
152         if ( cp.isShowTaxonomyCommonNames() && node.getNodeData().isHasTaxonomy()
153                 && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) {
154             TreePanelUtil
155                     .showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getTaxonomy().getCommonName(), sb );
156         }
157         if ( ( cp.isShowGeneNames() || cp.isShowGeneSymbols() || cp.isShowSequenceAcc() )
158                 && node.getNodeData().isHasSequence()
159                 && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getMolecularSequence() ) ) {
160             TreePanelUtil.showExtDescNodeDataUserSelectedHelperHelper( node.getNodeData().getSequence()
161                     .getMolecularSequence(), sb );
162         }
163         final String s = sb.toString().trim();
164         if ( !ForesterUtil.isEmpty( s ) ) {
165             data.add( s );
166         }
167     }
168
169     public final static void showExtDescNodeDataUserSelectedHelperHelper( final String s, final StringBuilder sb ) {
170         if ( sb.length() > 0 ) {
171             sb.append( "\t" );
172         }
173         sb.append( s );
174     }
175
176     final public static void showInformationMessage( final Component parent, final String title, final String msg ) {
177         JOptionPane.showMessageDialog( parent, msg, title, JOptionPane.INFORMATION_MESSAGE );
178     }
179
180     final static Color calculateColorFromString( final String str, final boolean is_taxonomy ) {
181         final String my_str = str.toUpperCase();
182         char first = my_str.charAt( 0 );
183         char second = ' ';
184         char third = ' ';
185         if ( my_str.length() > 1 ) {
186             if ( is_taxonomy ) {
187                 second = my_str.charAt( 1 );
188             }
189             else {
190                 second = my_str.charAt( my_str.length() - 1 );
191             }
192             if ( is_taxonomy ) {
193                 if ( my_str.length() > 2 ) {
194                     if ( my_str.indexOf( " " ) > 0 ) {
195                         third = my_str.charAt( my_str.indexOf( " " ) + 1 );
196                     }
197                     else {
198                         third = my_str.charAt( 2 );
199                     }
200                 }
201             }
202             else if ( my_str.length() > 2 ) {
203                 third = my_str.charAt( ( my_str.length() - 1 ) / 2 );
204             }
205         }
206         first = TreePanelUtil.normalizeCharForRGB( first );
207         second = TreePanelUtil.normalizeCharForRGB( second );
208         third = TreePanelUtil.normalizeCharForRGB( third );
209         if ( ( first > 235 ) && ( second > 235 ) && ( third > 235 ) ) {
210             first = 0;
211         }
212         else if ( ( first < 60 ) && ( second < 60 ) && ( third < 60 ) ) {
213             second = 255;
214         }
215         return new Color( first, second, third );
216     }
217
218     final static void collapseSpeciesSpecificSubtrees( final Phylogeny phy ) {
219         boolean inferred = false;
220         for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) {
221             final PhylogenyNode n = it.next();
222             if ( !n.isExternal() && !n.isCollapse() && ( n.getNumberOfDescendants() > 1 ) ) {
223                 final Set<Taxonomy> taxs = TreePanelUtil.obtainDistinctTaxonomies( n );
224                 if ( ( taxs != null ) && ( taxs.size() == 1 ) ) {
225                     TreePanelUtil.collapseSubtree( n, true );
226                     if ( !n.getNodeData().isHasTaxonomy() ) {
227                         n.getNodeData().setTaxonomy( ( Taxonomy ) n.getAllExternalDescendants().get( 0 ).getNodeData()
228                                 .getTaxonomy().copy() );
229                     }
230                     inferred = true;
231                 }
232                 else {
233                     n.setCollapse( false );
234                 }
235             }
236         }
237         if ( inferred ) {
238             phy.setRerootable( false );
239         }
240     }
241
242     final static void collapseSubtree( final PhylogenyNode node, final boolean collapse ) {
243         node.setCollapse( collapse );
244         if ( node.isExternal() ) {
245             return;
246         }
247         final PhylogenyNodeIterator it = new PreorderTreeIterator( node );
248         while ( it.hasNext() ) {
249             it.next().setCollapse( collapse );
250         }
251     }
252
253     static void colorizeSubtree( final PhylogenyNode node, final BranchColor c ) {
254         node.getBranchData().setBranchColor( c );
255         final List<PhylogenyNode> descs = PhylogenyMethods.getAllDescendants( node );
256         for( final PhylogenyNode desc : descs ) {
257             desc.getBranchData().setBranchColor( c );
258         }
259     }
260
261     final static void colorPhylogenyAccordingToConfidenceValues( final Phylogeny tree, final TreePanel tree_panel ) {
262         double max_conf = 0.0;
263         for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
264             final PhylogenyNode n = it.next();
265             n.getBranchData().setBranchColor( null );
266             if ( n.getBranchData().isHasConfidences() ) {
267                 final double conf = PhylogenyMethods.getConfidenceValue( n );
268                 if ( conf > max_conf ) {
269                     max_conf = conf;
270                 }
271             }
272         }
273         if ( max_conf > 0.0 ) {
274             final Color bg = tree_panel.getTreeColorSet().getBackgroundColor();
275             final Color br = tree_panel.getTreeColorSet().getBranchColor();
276             for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
277                 final PhylogenyNode n = it.next();
278                 if ( n.getBranchData().isHasConfidences() ) {
279                     final double conf = PhylogenyMethods.getConfidenceValue( n );
280                     final BranchColor c = new BranchColor( ForesterUtil.calcColor( conf, 0.0, max_conf, bg, br ) );
281                     TreePanelUtil.colorizeSubtree( n, c );
282                 }
283             }
284         }
285     }
286
287     final static void colorPhylogenyAccordingToExternalTaxonomy( final Phylogeny tree, final TreePanel tree_panel ) {
288         for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
289             it.next().getBranchData().setBranchColor( null );
290         }
291         for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
292             final PhylogenyNode n = it.next();
293             if ( !n.getBranchData().isHasBranchColor() ) {
294                 final Taxonomy tax = PhylogenyMethods.getExternalDescendantsTaxonomy( n );
295                 if ( tax != null ) {
296                     n.getBranchData().setBranchColor( new BranchColor( tree_panel.calculateTaxonomyBasedColor( tax ) ) );
297                     final List<PhylogenyNode> descs = PhylogenyMethods.getAllDescendants( n );
298                     for( final PhylogenyNode desc : descs ) {
299                         desc.getBranchData()
300                                 .setBranchColor( new BranchColor( tree_panel.calculateTaxonomyBasedColor( tax ) ) );
301                     }
302                 }
303             }
304         }
305     }
306
307     final static int colorPhylogenyAccordingToRanks( final Phylogeny tree, final String rank, final TreePanel tree_panel ) {
308         final Map<String, Color> true_lineage_to_color_map = new HashMap<String, Color>();
309         int colorizations = 0;
310         for( final PhylogenyNodeIterator it = tree.iteratorPostorder(); it.hasNext(); ) {
311             final PhylogenyNode n = it.next();
312             if ( n.getNodeData().isHasTaxonomy()
313                     && ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() )
314                             || !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getCommonName() ) || !ForesterUtil
315                             .isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
316                 if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getRank() )
317                         && n.getNodeData().getTaxonomy().getRank().equalsIgnoreCase( rank ) ) {
318                     final BranchColor c = new BranchColor( tree_panel.calculateTaxonomyBasedColor( n.getNodeData()
319                             .getTaxonomy() ) );
320                     TreePanelUtil.colorizeSubtree( n, c );
321                     ++colorizations;
322                     if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
323                         true_lineage_to_color_map.put( n.getNodeData().getTaxonomy().getScientificName(), c.getValue() );
324                     }
325                 }
326             }
327         }
328         for( final PhylogenyNodeIterator it = tree.iteratorPostorder(); it.hasNext(); ) {
329             final PhylogenyNode node = it.next();
330             if ( ( node.getBranchData().getBranchColor() == null ) && node.getNodeData().isHasTaxonomy()
331                     && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getLineage() ) ) {
332                 boolean success = false;
333                 if ( !true_lineage_to_color_map.isEmpty() ) {
334                     for( final String lin : node.getNodeData().getTaxonomy().getLineage() ) {
335                         if ( true_lineage_to_color_map.containsKey( lin ) ) {
336                             TreePanelUtil
337                                     .colorizeSubtree( node, new BranchColor( true_lineage_to_color_map.get( lin ) ) );
338                             ++colorizations;
339                             success = true;
340                             break;
341                         }
342                     }
343                 }
344                 if ( !success ) {
345                     final Map<String, String> lineage_to_rank_map = MainPanel.getLineageToRankMap();
346                     for( final String lin : node.getNodeData().getTaxonomy().getLineage() ) {
347                         final Taxonomy temp_tax = new Taxonomy();
348                         temp_tax.setScientificName( lin );
349                         if ( lineage_to_rank_map.containsKey( lin )
350                                 && !ForesterUtil.isEmpty( lineage_to_rank_map.get( lin ) )
351                                 && lineage_to_rank_map.get( lin ).equalsIgnoreCase( rank ) ) {
352                             final BranchColor c = new BranchColor( tree_panel.calculateTaxonomyBasedColor( temp_tax ) );
353                             TreePanelUtil.colorizeSubtree( node, c );
354                             ++colorizations;
355                             true_lineage_to_color_map.put( lin, c.getValue() );
356                             break;
357                         }
358                         else {
359                             UniProtTaxonomy up = null;
360                             try {
361                                 up = TaxonomyDataManager.obtainUniProtTaxonomy( temp_tax, null, null );
362                             }
363                             catch ( final Exception e ) {
364                                 e.printStackTrace();
365                             }
366                             if ( ( up != null ) && !ForesterUtil.isEmpty( up.getRank() ) ) {
367                                 lineage_to_rank_map.put( lin, up.getRank() );
368                                 if ( up.getRank().equalsIgnoreCase( rank ) ) {
369                                     final BranchColor c = new BranchColor( tree_panel.calculateTaxonomyBasedColor( temp_tax ) );
370                                     TreePanelUtil.colorizeSubtree( node, c );
371                                     ++colorizations;
372                                     true_lineage_to_color_map.put( lin, c.getValue() );
373                                     break;
374                                 }
375                             }
376                         }
377                     }
378                 }
379             }
380         }
381         return colorizations;
382     }
383
384     final static String createAnnotationString( final SortedSet<Annotation> annotations, final boolean show_ref_sources ) {
385         final SortedMap<String, List<Annotation>> m = new TreeMap<String, List<Annotation>>();
386         for( final Annotation an : annotations ) {
387             final String ref_source = ForesterUtil.isEmpty( an.getRefSource() ) ? "?" : an.getRefSource();
388             if ( !m.containsKey( ref_source ) ) {
389                 m.put( ref_source, new ArrayList<Annotation>() );
390             }
391             m.get( ref_source ).add( an );
392         }
393         final StringBuilder sb = new StringBuilder();
394         for( final Entry<String, List<Annotation>> e : m.entrySet() ) {
395             final String ref_source = e.getKey();
396             final List<Annotation> ans = e.getValue();
397             if ( m.size() > 1 ) {
398                 sb.append( "[" );
399             }
400             if ( show_ref_sources && !ref_source.equals( "?" ) ) {
401                 sb.append( ref_source );
402                 sb.append( ": " );
403             }
404             for( int i = 0; i < ans.size(); ++i ) {
405                 final Annotation an = ans.get( i );
406                 if ( !ForesterUtil.isEmpty( an.getRefValue() ) ) {
407                     sb.append( an.getRefValue() );
408                     sb.append( " " );
409                 }
410                 if ( !ForesterUtil.isEmpty( an.getDesc() ) ) {
411                     sb.append( an.getDesc() );
412                 }
413                 if ( sb.charAt( sb.length() - 1 ) == ' ' ) {
414                     sb.deleteCharAt( sb.length() - 1 );
415                 }
416                 if ( i < ans.size() - 1 ) {
417                     sb.append( ", " );
418                 }
419             }
420             if ( m.size() > 1 ) {
421                 sb.append( "] " );
422             }
423         }
424         return sb.toString();
425     }
426
427     final static String getPartAfterColon( final String s ) {
428         final int i = s.indexOf( ':' );
429         if ( ( i < 1 ) || ( i == ( s.length() - 1 ) ) ) {
430             return s;
431         }
432         return s.substring( i + 1, s.length() );
433     }
434
435     final static boolean isHasAssignedEvent( final PhylogenyNode node ) {
436         if ( !node.getNodeData().isHasEvent() ) {
437             return false;
438         }
439         if ( ( node.getNodeData().getEvent() ).isUnassigned() ) {
440             return false;
441         }
442         return true;
443     }
444
445     final static boolean isSequenceEmpty( final Sequence seq ) {
446         return ( seq.getAccession() == null ) && ForesterUtil.isEmpty( seq.getName() )
447                 && ForesterUtil.isEmpty( seq.getSymbol() );
448     }
449
450     final static boolean isTaxonomyEmpty( final Taxonomy tax ) {
451         return ( ( tax.getIdentifier() == null ) && ForesterUtil.isEmpty( tax.getTaxonomyCode() )
452                 && ForesterUtil.isEmpty( tax.getCommonName() ) && ForesterUtil.isEmpty( tax.getScientificName() ) && tax
453                 .getSynonyms().isEmpty() );
454     }
455
456     final static char normalizeCharForRGB( char c ) {
457         c -= 65;
458         c *= 10.2;
459         c = c > 255 ? 255 : c;
460         c = c < 0 ? 0 : c;
461         return c;
462     }
463
464     final static Phylogeny subTree( final PhylogenyNode new_root, final Phylogeny source_phy ) {
465         final Phylogeny new_phy = new Phylogeny();
466         new_phy.setRooted( true );
467         new_phy.setName( source_phy.getName() );
468         new_phy.setDescription( source_phy.getDescription() );
469         new_phy.setType( source_phy.getType() );
470         new_phy.setDistanceUnit( source_phy.getDistanceUnit() );
471         new_phy.setConfidence( source_phy.getConfidence() );
472         new_phy.setIdentifier( source_phy.getIdentifier() );
473         new_phy.setRoot( new_root.copyNodeDataShallow() );
474         int i = 0;
475         for( final PhylogenyNode n : new_root.getDescendants() ) {
476             new_phy.getRoot().setChildNode( i++, n );
477         }
478         return new_phy;
479     }
480 }