cleanup
[jalview.git] / forester / java / src / org / forester / surfacing / PrintableDomainSimilarity.java
1 // $Id:
2 //
3 // FORESTER -- software libraries and applications
4 // for evolutionary biology research and applications.
5 //
6 // Copyright (C) 2008-2009 Christian M. Zmasek
7 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26
27 package org.forester.surfacing;
28
29 import java.util.List;
30 import java.util.Map;
31 import java.util.SortedMap;
32 import java.util.SortedSet;
33 import java.util.TreeMap;
34 import java.util.TreeSet;
35
36 import org.forester.phylogeny.Phylogeny;
37 import org.forester.species.Species;
38 import org.forester.surfacing.DomainSimilarityCalculator.Detailedness;
39 import org.forester.util.ForesterUtil;
40
41 public class PrintableDomainSimilarity implements DomainSimilarity {
42
43     final public static String                              SPECIES_SEPARATOR = "  ";
44     final private static int                                EQUAL             = 0;
45     final private static String                             NO_SPECIES        = "     ";
46     final private CombinableDomains                         _combinable_domains;
47     private DomainSimilarityCalculator.Detailedness         _detailedness;
48     final private double                                    _max;
49     private final int                                       _max_difference;
50     private final int                                       _max_difference_in_counts;
51     final private double                                    _mean;
52     final private double                                    _min;
53     final private int                                       _n;
54     final private double                                    _sd;
55     final private SortedMap<Species, SpeciesSpecificDcData> _species_data;
56     private List<Species>                                   _species_order;
57     private final boolean                                   _treat_as_binary_comparison;
58
59     public PrintableDomainSimilarity( final CombinableDomains combinable_domains,
60                                       final double min,
61                                       final double max,
62                                       final double mean,
63                                       final double median,
64                                       final double sd,
65                                       final int n,
66                                       final int max_difference_in_counts,
67                                       final int max_difference,
68                                       final SortedMap<Species, SpeciesSpecificDcData> species_data,
69                                       final boolean sort_by_species_count_first,
70                                       final boolean treat_as_binary_comparison ) {
71         if ( combinable_domains == null ) {
72             throw new IllegalArgumentException( "attempt to use null combinable domains" );
73         }
74         if ( species_data == null ) {
75             throw new IllegalArgumentException( "attempt to use null species data" );
76         }
77         if ( species_data.size() < 1 ) {
78             throw new IllegalArgumentException( "attempt to use empty species data" );
79         }
80         if ( n < 0 ) {
81             throw new IllegalArgumentException( "attempt to use N less than 0" );
82         }
83         if ( ( species_data.size() > 1 ) && ( n < 1 ) ) {
84             throw new IllegalArgumentException( "attempt to use N less than 1" );
85         }
86         if ( sd < 0.0 ) {
87             throw new IllegalArgumentException( "attempt to use negative SD" );
88         }
89         if ( max < min ) {
90             throw new IllegalArgumentException( "attempt to use max smaller than min" );
91         }
92         init();
93         _combinable_domains = combinable_domains;
94         _min = min;
95         _max = max;
96         _mean = mean;
97         _sd = sd;
98         _n = n;
99         _max_difference_in_counts = max_difference_in_counts;
100         _max_difference = max_difference;
101         _species_data = species_data;
102         _treat_as_binary_comparison = treat_as_binary_comparison;
103         final int s = species_data.size();
104         if ( ( ( s * s ) - s ) != ( getN() * 2 ) ) {
105             throw new IllegalArgumentException( "illegal species count and n: species count:" + s + ", n:" + _n
106                     + " for domain " + combinable_domains.getKeyDomain() );
107         }
108         if ( s > 2 ) {
109             if ( getMaximalDifferenceInCounts() < 0 ) {
110                 throw new IllegalArgumentException( "attempt to use negative max difference in counts with more than two species" );
111             }
112             if ( getMaximalDifference() < 0 ) {
113                 throw new IllegalArgumentException( "attempt to use negative max difference with more than two species" );
114             }
115         }
116     }
117
118     public PrintableDomainSimilarity( final CombinableDomains combinable_domains,
119                                       final int max_difference_in_counts,
120                                       final int max_difference,
121                                       final SortedMap<Species, SpeciesSpecificDcData> species_data,
122                                       final boolean sort_by_species_count_first,
123                                       final boolean treat_as_binary_comparison ) {
124         if ( combinable_domains == null ) {
125             throw new IllegalArgumentException( "attempt to use null combinable domains" );
126         }
127         if ( species_data == null ) {
128             throw new IllegalArgumentException( "attempt to use null species data" );
129         }
130         if ( species_data.size() < 1 ) {
131             throw new IllegalArgumentException( "attempt to use empty species data" );
132         }
133         init();
134         _combinable_domains = combinable_domains;
135         _min = -1;
136         _max = -1;
137         _mean = -1;
138         _sd = -1;
139         _n = -1;
140         _max_difference_in_counts = max_difference_in_counts;
141         _max_difference = max_difference;
142         _species_data = species_data;
143         _treat_as_binary_comparison = treat_as_binary_comparison;
144         final int s = species_data.size();
145         if ( s > 2 ) {
146             if ( getMaximalDifferenceInCounts() < 0 ) {
147                 throw new IllegalArgumentException( "attempt to use negative max difference in counts with more than two species" );
148             }
149             if ( getMaximalDifference() < 0 ) {
150                 throw new IllegalArgumentException( "attempt to use negative max difference with more than two species" );
151             }
152         }
153     }
154
155     @Override
156     public int compareTo( final DomainSimilarity domain_similarity ) {
157         if ( this == domain_similarity ) {
158             return EQUAL;
159         }
160         else if ( domain_similarity == null ) {
161             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to null" );
162         }
163         else if ( domain_similarity.getClass() != this.getClass() ) {
164             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to "
165                     + domain_similarity.getClass() );
166         }
167         return compareByDomainId( domain_similarity );
168     }
169
170     @Override
171     public SortedSet<String> getCombinableDomainIds( final Species species_of_combinable_domain ) {
172         final SortedSet<String> sorted_ids = new TreeSet<String>();
173         if ( getSpeciesData().containsKey( species_of_combinable_domain ) ) {
174             for( final String id : getSpeciesData().get( species_of_combinable_domain )
175                     .getCombinableDomainIdToCountsMap().keySet() ) {
176                 sorted_ids.add( id );
177             }
178         }
179         return sorted_ids;
180     }
181
182     @Override
183     public String getDomainId() {
184         return getCombinableDomains().getKeyDomain();
185     }
186
187     @Override
188     public int getMaximalDifference() {
189         return _max_difference;
190     }
191
192     @Override
193     public int getMaximalDifferenceInCounts() {
194         return _max_difference_in_counts;
195     }
196
197     @Override
198     public double getMaximalSimilarityScore() {
199         return _max;
200     }
201
202     @Override
203     public double getMeanSimilarityScore() {
204         return _mean;
205     }
206
207     @Override
208     public double getMinimalSimilarityScore() {
209         return _min;
210     }
211
212     @Override
213     public int getN() {
214         return _n;
215     }
216
217     @Override
218     public SortedSet<Species> getSpecies() {
219         final SortedSet<Species> species = new TreeSet<Species>();
220         for( final Species s : getSpeciesData().keySet() ) {
221             species.add( s );
222         }
223         return species;
224     }
225
226     public List<Species> getSpeciesCustomOrder() {
227         return _species_order;
228     }
229
230     @Override
231     public SortedMap<Species, SpeciesSpecificDcData> getSpeciesData() {
232         return _species_data;
233     }
234
235     @Override
236     public double getStandardDeviationOfSimilarityScore() {
237         return _sd;
238     }
239
240     public void setDetailedness( final Detailedness detailedness ) {
241         _detailedness = detailedness;
242     }
243
244     public void setSpeciesOrder( final List<Species> species_order ) {
245         if ( !species_order.containsAll( getSpeciesData().keySet() ) ) {
246             throw new IllegalArgumentException( "list to order species must contain all species of multiple combinable domains similarity" );
247         }
248         _species_order = species_order;
249     }
250
251     @Override
252     public StringBuffer toStringBuffer( final PrintableDomainSimilarity.PRINT_OPTION print_option,
253                                         final Map<String, Integer> tax_code_to_id_map,
254                                         final Phylogeny phy ) {
255         switch ( print_option ) {
256             case SIMPLE_TAB_DELIMITED:
257                 return toStringBufferSimpleTabDelimited();
258             case HTML:
259                 return toStringBufferDetailedHTML( tax_code_to_id_map, phy );
260             default:
261                 throw new AssertionError( "Unknown print option: " + print_option );
262         }
263     }
264
265     private void addSpeciesSpecificDomainData( final StringBuffer sb,
266                                                final Species species,
267                                                final boolean html,
268                                                final Map<String, Integer> tax_code_to_id_map,
269                                                final Phylogeny phy ) {
270         if ( html ) {
271             addTaxWithLink( sb, species.getSpeciesId(), tax_code_to_id_map, phy );
272         }
273         else {
274             sb.append( species.getSpeciesId() );
275         }
276         if ( getDetaildness() != DomainSimilarityCalculator.Detailedness.BASIC ) {
277             if ( html ) {
278                 sb.append( ":" );
279             }
280             else {
281                 sb.append( "\t" );
282             }
283             sb.append( getSpeciesData().get( species ).toStringBuffer( getDetaildness(), html ) );
284         }
285         if ( html ) {
286             sb.append( "<br>" );
287         }
288         else {
289             sb.append( "\n\t" );
290         }
291     }
292
293     private void addTaxWithLink( final StringBuffer sb,
294                                  final String tax_code,
295                                  final Map<String, Integer> tax_code_to_id_map,
296                                  final Phylogeny phy ) {
297         String hex = null;
298         if ( ( phy != null ) && !phy.isEmpty() ) {
299             hex = SurfacingUtil.obtainHexColorStringDependingOnTaxonomyGroup( tax_code, phy );
300         }
301         sb.append( "<b>" );
302         if ( !ForesterUtil.isEmpty( tax_code )
303                 && ( ( tax_code_to_id_map != null ) && tax_code_to_id_map.containsKey( tax_code ) ) ) {
304             if ( !ForesterUtil.isEmpty( hex ) ) {
305                 sb.append( "<a href=\"" );
306                 sb.append( SurfacingConstants.UNIPROT_TAXONOMY_ID_LINK );
307                 sb.append( tax_code_to_id_map.get( tax_code ) );
308                 sb.append( "\" target=\"tw\"><span style=\"color:" );
309                 sb.append( hex );
310                 sb.append( "\">" );
311                 sb.append( tax_code );
312                 sb.append( "</span></a>" );
313             }
314             else {
315                 sb.append( "<a href=\"" );
316                 sb.append( SurfacingConstants.UNIPROT_TAXONOMY_ID_LINK );
317                 sb.append( tax_code_to_id_map.get( tax_code ) );
318                 sb.append( "\" target=\"tw\">" );
319                 sb.append( tax_code );
320                 sb.append( "</a>" );
321             }
322         }
323         else {
324             sb.append( tax_code );
325         }
326         sb.append( "</b>" );
327     }
328
329     private int compareByDomainId( final DomainSimilarity other ) {
330         return getDomainId().compareToIgnoreCase( other.getDomainId() );
331     }
332
333     private CombinableDomains getCombinableDomains() {
334         return _combinable_domains;
335     }
336
337     private DomainSimilarityCalculator.Detailedness getDetaildness() {
338         return _detailedness;
339     }
340
341     private StringBuffer getDomainDataInAlphabeticalOrder() {
342         final SortedMap<String, SortedSet<String>> m = new TreeMap<String, SortedSet<String>>();
343         final StringBuffer sb = new StringBuffer();
344         for( final Species species : getSpeciesData().keySet() ) {
345             for( final String combable_dom : getCombinableDomainIds( species ) ) {
346                 if ( !m.containsKey( combable_dom ) ) {
347                     m.put( combable_dom, new TreeSet<String>() );
348                 }
349                 m.get( combable_dom ).add( species.getSpeciesId() );
350             }
351         }
352         for( final Map.Entry<String, SortedSet<String>> e : m.entrySet() ) {
353             sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + e.getKey() + "\">" + e.getKey() + "</a>" );
354             sb.append( ": " );
355             sb.append( "<span style=\"font-size:7px\">" );
356             for( final String tax : e.getValue() ) {
357                 final String hex = SurfacingUtil.obtainHexColorStringDependingOnTaxonomyGroup( tax, null );
358                 if ( !ForesterUtil.isEmpty( hex ) ) {
359                     sb.append( "<span style=\"color:" );
360                     sb.append( hex );
361                     sb.append( "\">" );
362                     sb.append( tax );
363                     sb.append( "</span>" );
364                 }
365                 else {
366                     sb.append( tax );
367                 }
368                 sb.append( " " );
369             }
370             sb.append( "</span>" );
371             sb.append( "<br>\n" );
372         }
373         return sb;
374     }
375
376     private StringBuffer getSpeciesDataInAlphabeticalOrder( final boolean html,
377                                                             final Map<String, Integer> tax_code_to_id_map,
378                                                             final Phylogeny phy ) {
379         final StringBuffer sb = new StringBuffer();
380         for( final Species species : getSpeciesData().keySet() ) {
381             addSpeciesSpecificDomainData( sb, species, html, tax_code_to_id_map, phy );
382         }
383         return sb;
384     }
385
386     private StringBuffer getSpeciesDataInCustomOrder( final boolean html,
387                                                       final Map<String, Integer> tax_code_to_id_map,
388                                                       final Phylogeny phy ) {
389         final StringBuffer sb = new StringBuffer();
390         for( final Species order_species : getSpeciesCustomOrder() ) {
391             if ( getSpeciesData().keySet().contains( order_species ) ) {
392                 addSpeciesSpecificDomainData( sb, order_species, html, tax_code_to_id_map, phy );
393             }
394             else {
395                 sb.append( PrintableDomainSimilarity.NO_SPECIES );
396                 sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
397             }
398         }
399         return sb;
400     }
401
402     private void init() {
403         _detailedness = DomainSimilarityCalculator.Detailedness.PUNCTILIOUS;
404     }
405
406     private boolean isTreatAsBinaryComparison() {
407         return _treat_as_binary_comparison;
408     }
409
410     private StringBuffer toStringBufferDetailedHTML( final Map<String, Integer> tax_code_to_id_map, final Phylogeny phy ) {
411         final StringBuffer sb = new StringBuffer();
412         sb.append( "<tr>" );
413         sb.append( "<td>" );
414         sb.append( "<b>" );
415         sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + getDomainId() + "\" target=\"pfam_window\">"
416                 + getDomainId() + "</a>" );
417         sb.append( "</b>" );
418         sb.append( "<a name=\"" + getDomainId() + "\">" );
419         sb.append( "</td>" );
420         sb.append( "<td>" );
421         sb.append( "<a href=\"" + SurfacingConstants.GOOGLE_SCHOLAR_SEARCH + getDomainId()
422                 + "\" target=\"gs_window\">gs</a>" );
423         sb.append( "</td>" );
424         if ( getMaximalSimilarityScore() > 0 ) {
425             sb.append( "<td>" );
426             sb.append( ForesterUtil.round( getMeanSimilarityScore(), 3 ) );
427             sb.append( "</td>" );
428             if ( SurfacingConstants.PRINT_MORE_DOM_SIMILARITY_INFO ) {
429                 if ( !isTreatAsBinaryComparison() ) {
430                     sb.append( "<td>" );
431                     sb.append( "(" );
432                     sb.append( ForesterUtil.round( getStandardDeviationOfSimilarityScore(), 3 ) );
433                     sb.append( ")" );
434                     sb.append( "</td>" );
435                     sb.append( "<td>" );
436                     sb.append( "[" );
437                     sb.append( ForesterUtil.round( getMinimalSimilarityScore(), 3 ) );
438                     sb.append( "-" );
439                     sb.append( ForesterUtil.round( getMaximalSimilarityScore(), 3 ) );
440                     sb.append( "]" );
441                     sb.append( "</td>" );
442                 }
443             }
444         }
445         sb.append( "<td>" );
446         sb.append( getMaximalDifference() );
447         sb.append( "</td>" );
448         sb.append( "<td>" );
449         if ( isTreatAsBinaryComparison() ) {
450             sb.append( getMaximalDifferenceInCounts() );
451         }
452         else {
453             sb.append( Math.abs( getMaximalDifferenceInCounts() ) );
454         }
455         sb.append( "</td>" );
456         if ( !isTreatAsBinaryComparison() ) {
457             sb.append( "<td>" );
458             sb.append( "<b>" );
459             sb.append( getSpeciesData().size() );
460             sb.append( "</b>" );
461             sb.append( "</td>" );
462         }
463         if ( ( getSpeciesCustomOrder() == null ) || getSpeciesCustomOrder().isEmpty() ) {
464             sb.append( "<td>" );
465             sb.append( getSpeciesDataInAlphabeticalOrder( true, tax_code_to_id_map, phy ) );
466             sb.append( getDomainDataInAlphabeticalOrder() );
467             sb.append( "</td>" );
468         }
469         else {
470             sb.append( "<td>" );
471             sb.append( getSpeciesDataInCustomOrder( true, tax_code_to_id_map, phy ) );
472             sb.append( getDomainDataInAlphabeticalOrder() );
473             sb.append( "</td>" );
474         }
475         sb.append( "</tr>" );
476         return sb;
477     }
478
479     private StringBuffer toStringBufferSimpleTabDelimited() {
480         final StringBuffer sb = new StringBuffer();
481         sb.append( getDomainId() );
482         sb.append( "\t" );
483         sb.append( getSpeciesDataInAlphabeticalOrder( false, null, null ) );
484         sb.append( "\n" );
485         return sb;
486     }
487
488     public static enum PRINT_OPTION {
489         HTML, SIMPLE_TAB_DELIMITED;
490     }
491 }