inprogress
[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.species.Species;
37 import org.forester.surfacing.DomainSimilarityCalculator.Detailedness;
38 import org.forester.util.ForesterUtil;
39
40 public class PrintableDomainSimilarity implements DomainSimilarity {
41
42     final public static String                              SPECIES_SEPARATOR = "  ";
43     final private static int                                EQUAL             = 0;
44     final private static String                             NO_SPECIES        = "     ";
45     final private double                                    _min;
46     final private double                                    _max;
47     final private double                                    _mean;
48     final private double                                    _sd;
49     final private int                                       _n;
50     private final int                                       _max_difference_in_counts;
51     private final int                                       _max_difference;
52     final private CombinableDomains                         _combinable_domains;
53     final private SortedMap<Species, SpeciesSpecificDcData> _species_data;
54     private List<Species>                                   _species_order;
55     private DomainSimilarityCalculator.Detailedness         _detailedness;
56     private final boolean                                   _treat_as_binary_comparison;
57
58     public PrintableDomainSimilarity( final CombinableDomains combinable_domains,
59                                       final double min,
60                                       final double max,
61                                       final double mean,
62                                       final double median,
63                                       final double sd,
64                                       final int n,
65                                       final int max_difference_in_counts,
66                                       final int max_difference,
67                                       final SortedMap<Species, SpeciesSpecificDcData> species_data,
68                                       final boolean sort_by_species_count_first,
69                                       final boolean treat_as_binary_comparison ) {
70         if ( combinable_domains == null ) {
71             throw new IllegalArgumentException( "attempt to use null combinable domains" );
72         }
73         if ( species_data == null ) {
74             throw new IllegalArgumentException( "attempt to use null species data" );
75         }
76         if ( species_data.size() < 1 ) {
77             throw new IllegalArgumentException( "attempt to use empty species data" );
78         }
79         if ( n < 0 ) {
80             throw new IllegalArgumentException( "attempt to use N less than 0" );
81         }
82         if ( ( species_data.size() > 1 ) && ( n < 1 ) ) {
83             throw new IllegalArgumentException( "attempt to use N less than 1" );
84         }
85         if ( sd < 0.0 ) {
86             throw new IllegalArgumentException( "attempt to use negative SD" );
87         }
88         if ( max < min ) {
89             throw new IllegalArgumentException( "attempt to use max smaller than min" );
90         }
91         init();
92         _combinable_domains = combinable_domains;
93         _min = min;
94         _max = max;
95         _mean = mean;
96         _sd = sd;
97         _n = n;
98         _max_difference_in_counts = max_difference_in_counts;
99         _max_difference = max_difference;
100         _species_data = species_data;
101         _treat_as_binary_comparison = treat_as_binary_comparison;
102         final int s = species_data.size();
103         if ( ( ( s * s ) - s ) != ( getN() * 2 ) ) {
104             throw new IllegalArgumentException( "illegal species count and n: species count:" + s + ", n:" + _n
105                     + " for domain " + combinable_domains.getKeyDomain() );
106         }
107         if ( s > 2 ) {
108             if ( getMaximalDifferenceInCounts() < 0 ) {
109                 throw new IllegalArgumentException( "attempt to use negative max difference in counts with more than two species" );
110             }
111             if ( getMaximalDifference() < 0 ) {
112                 throw new IllegalArgumentException( "attempt to use negative max difference with more than two species" );
113             }
114         }
115     }
116
117     public PrintableDomainSimilarity( final CombinableDomains combinable_domains,
118                                       final int max_difference_in_counts,
119                                       final int max_difference,
120                                       final SortedMap<Species, SpeciesSpecificDcData> species_data,
121                                       final boolean sort_by_species_count_first,
122                                       final boolean treat_as_binary_comparison ) {
123         if ( combinable_domains == null ) {
124             throw new IllegalArgumentException( "attempt to use null combinable domains" );
125         }
126         if ( species_data == null ) {
127             throw new IllegalArgumentException( "attempt to use null species data" );
128         }
129         if ( species_data.size() < 1 ) {
130             throw new IllegalArgumentException( "attempt to use empty species data" );
131         }
132         init();
133         _combinable_domains = combinable_domains;
134         _min = -1;
135         _max = -1;
136         _mean = -1;
137         _sd = -1;
138         _n = -1;
139         _max_difference_in_counts = max_difference_in_counts;
140         _max_difference = max_difference;
141         _species_data = species_data;
142         _treat_as_binary_comparison = treat_as_binary_comparison;
143         final int s = species_data.size();
144         if ( s > 2 ) {
145             if ( getMaximalDifferenceInCounts() < 0 ) {
146                 throw new IllegalArgumentException( "attempt to use negative max difference in counts with more than two species" );
147             }
148             if ( getMaximalDifference() < 0 ) {
149                 throw new IllegalArgumentException( "attempt to use negative max difference with more than two species" );
150             }
151         }
152     }
153
154     private void addSpeciesSpecificDomainData( final StringBuffer sb,
155                                                final Species species,
156                                                final boolean html,
157                                                final Map<String, Integer> tax_code_to_id_map ) {
158         if ( html ) {
159             addTaxWithLink( sb, species.getSpeciesId(), tax_code_to_id_map );
160         }
161         else {
162             sb.append( species.getSpeciesId() );
163         }
164         if ( getDetaildness() != DomainSimilarityCalculator.Detailedness.BASIC ) {
165             sb.append( ":" );
166             sb.append( getSpeciesData().get( species ).toStringBuffer( getDetaildness(), html ) );
167         }
168         if ( html ) {
169             sb.append( "<br>" );
170         }
171         else {
172             sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
173         }
174     }
175
176     private void addTaxWithLink( final StringBuffer sb,
177                                  final String tax_code,
178                                  final Map<String, Integer> tax_code_to_id_map ) {
179         sb.append( "<b>" );
180         if ( !ForesterUtil.isEmpty( tax_code )
181                 && ( ( tax_code_to_id_map != null ) && tax_code_to_id_map.containsKey( tax_code ) ) ) {
182             sb.append( "<a href=\"" + SurfacingConstants.UNIPROT_TAXONOMY_ID_LINK + tax_code_to_id_map.get( tax_code )
183                     + "\" target=\"taxonomy_window\">" + tax_code + "</a>" );
184         }
185         else {
186             sb.append( tax_code );
187         }
188         sb.append( "</b>" );
189     }
190
191     private int compareByDomainId( final DomainSimilarity other ) {
192         return getDomainId().compareToIgnoreCase( other.getDomainId() );
193     }
194
195     @Override
196     public int compareTo( final DomainSimilarity domain_similarity ) {
197         if ( this == domain_similarity ) {
198             return EQUAL;
199         }
200         else if ( domain_similarity == null ) {
201             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to null" );
202         }
203         else if ( domain_similarity.getClass() != this.getClass() ) {
204             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to "
205                     + domain_similarity.getClass() );
206         }
207         return compareByDomainId( domain_similarity );
208     }
209
210     @Override
211     public SortedSet<String> getCombinableDomainIds( final Species species_of_combinable_domain ) {
212         final SortedSet<String> sorted_ids = new TreeSet<String>();
213         if ( getSpeciesData().containsKey( species_of_combinable_domain ) ) {
214             for( final String id : getSpeciesData().get( species_of_combinable_domain )
215                     .getCombinableDomainIdToCountsMap().keySet() ) {
216                 sorted_ids.add( id );
217             }
218         }
219         return sorted_ids;
220     }
221
222     private CombinableDomains getCombinableDomains() {
223         return _combinable_domains;
224     }
225
226     private DomainSimilarityCalculator.Detailedness getDetaildness() {
227         return _detailedness;
228     }
229
230     @Override
231     public String getDomainId() {
232         return getCombinableDomains().getKeyDomain();
233     }
234
235     @Override
236     public int getMaximalDifference() {
237         return _max_difference;
238     }
239
240     @Override
241     public int getMaximalDifferenceInCounts() {
242         return _max_difference_in_counts;
243     }
244
245     @Override
246     public double getMaximalSimilarityScore() {
247         return _max;
248     }
249
250     @Override
251     public double getMeanSimilarityScore() {
252         return _mean;
253     }
254
255     @Override
256     public double getMinimalSimilarityScore() {
257         return _min;
258     }
259
260     @Override
261     public int getN() {
262         return _n;
263     }
264
265     @Override
266     public SortedSet<Species> getSpecies() {
267         final SortedSet<Species> species = new TreeSet<Species>();
268         for( final Species s : getSpeciesData().keySet() ) {
269             species.add( s );
270         }
271         return species;
272     }
273
274     public List<Species> getSpeciesCustomOrder() {
275         return _species_order;
276     }
277
278     @Override
279     public SortedMap<Species, SpeciesSpecificDcData> getSpeciesData() {
280         return _species_data;
281     }
282
283     private StringBuffer getSpeciesDataInAlphabeticalOrder( final boolean html,
284                                                             final Map<String, Integer> tax_code_to_id_map ) {
285         final StringBuffer sb = new StringBuffer();
286         for( final Species species : getSpeciesData().keySet() ) {
287             addSpeciesSpecificDomainData( sb, species, html, tax_code_to_id_map );
288         }
289         return sb;
290     }
291
292     private StringBuffer getDomainDataInAlphabeticalOrder() {
293         final SortedMap<String, SortedSet<String>> m = new TreeMap<String, SortedSet<String>>();
294         final StringBuffer sb = new StringBuffer();
295         for( final Species species : getSpeciesData().keySet() ) {
296             for( final String combable_dom : getCombinableDomainIds( species ) ) {
297                 if ( !m.containsKey( combable_dom ) ) {
298                     m.put( combable_dom, new TreeSet<String>() );
299                 }
300                 m.get( combable_dom ).add( species.getSpeciesId() );
301             }
302         }
303         for( final Map.Entry<String, SortedSet<String>> e : m.entrySet() ) {
304             sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + e.getKey() + "\">" + e.getKey() + "</a>" );
305             sb.append( ": " );
306             for( final String s : e.getValue() ) {
307                 sb.append( s );
308                 sb.append( " " );
309             }
310             sb.append( "<br>" );
311         }
312         return sb;
313     }
314
315     private StringBuffer getSpeciesDataInCustomOrder( final boolean html, final Map<String, Integer> tax_code_to_id_map ) {
316         final StringBuffer sb = new StringBuffer();
317         for( final Species order_species : getSpeciesCustomOrder() ) {
318             if ( getSpeciesData().keySet().contains( order_species ) ) {
319                 addSpeciesSpecificDomainData( sb, order_species, html, tax_code_to_id_map );
320             }
321             else {
322                 sb.append( PrintableDomainSimilarity.NO_SPECIES );
323                 sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
324             }
325         }
326         return sb;
327     }
328
329     @Override
330     public double getStandardDeviationOfSimilarityScore() {
331         return _sd;
332     }
333
334     private void init() {
335         _detailedness = DomainSimilarityCalculator.Detailedness.PUNCTILIOUS;
336     }
337
338     private boolean isTreatAsBinaryComparison() {
339         return _treat_as_binary_comparison;
340     }
341
342     public void setDetailedness( final Detailedness detailedness ) {
343         _detailedness = detailedness;
344     }
345
346     public void setSpeciesOrder( final List<Species> species_order ) {
347         if ( !species_order.containsAll( getSpeciesData().keySet() ) ) {
348             throw new IllegalArgumentException( "list to order species must contain all species of multiple combinable domains similarity" );
349         }
350         _species_order = species_order;
351     }
352
353     @Override
354     public StringBuffer toStringBuffer( final PrintableDomainSimilarity.PRINT_OPTION print_option,
355                                         final Map<String, Integer> tax_code_to_id_map ) {
356         switch ( print_option ) {
357             case SIMPLE_TAB_DELIMITED:
358                 return toStringBufferSimpleTabDelimited();
359             case HTML:
360                 return toStringBufferDetailedHTML( tax_code_to_id_map );
361             default:
362                 throw new AssertionError( "Unknown print option: " + print_option );
363         }
364     }
365
366     private StringBuffer toStringBufferDetailedHTML( final Map<String, Integer> tax_code_to_id_map ) {
367         final StringBuffer sb = new StringBuffer();
368         sb.append( "<tr>" );
369         sb.append( "<td>" );
370         sb.append( "<b>" );
371         sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + getDomainId() + "\" target=\"pfam_window\">"
372                 + getDomainId() + "</a>" );
373         sb.append( "</b>" );
374         sb.append( "<a name=\"" + getDomainId() + "\">" );
375         sb.append( "</td>" );
376         sb.append( "<td>" );
377         sb.append( "<a href=\"" + SurfacingConstants.GOOGLE_SCHOLAR_SEARCH + getDomainId()
378                 + "\" target=\"gs_window\">gs</a>" );
379         sb.append( "</td>" );
380         if ( getMaximalSimilarityScore() > 0 ) {
381             sb.append( "<td>" );
382             sb.append( ForesterUtil.round( getMeanSimilarityScore(), 3 ) );
383             sb.append( "</td>" );
384             if ( SurfacingConstants.PRINT_MORE_DOM_SIMILARITY_INFO ) {
385                 if ( !isTreatAsBinaryComparison() ) {
386                     sb.append( "<td>" );
387                     sb.append( "(" );
388                     sb.append( ForesterUtil.round( getStandardDeviationOfSimilarityScore(), 3 ) );
389                     sb.append( ")" );
390                     sb.append( "</td>" );
391                     sb.append( "<td>" );
392                     sb.append( "[" );
393                     sb.append( ForesterUtil.round( getMinimalSimilarityScore(), 3 ) );
394                     sb.append( "-" );
395                     sb.append( ForesterUtil.round( getMaximalSimilarityScore(), 3 ) );
396                     sb.append( "]" );
397                     sb.append( "</td>" );
398                 }
399             }
400         }
401         sb.append( "<td>" );
402         sb.append( getMaximalDifference() );
403         sb.append( "</td>" );
404         sb.append( "<td>" );
405         if ( isTreatAsBinaryComparison() ) {
406             sb.append( getMaximalDifferenceInCounts() );
407         }
408         else {
409             sb.append( Math.abs( getMaximalDifferenceInCounts() ) );
410         }
411         sb.append( "</td>" );
412         if ( !isTreatAsBinaryComparison() ) {
413             sb.append( "<td>" );
414             sb.append( "<b>" );
415             sb.append( getSpeciesData().size() );
416             sb.append( "</b>" );
417             sb.append( "</td>" );
418         }
419         if ( ( getSpeciesCustomOrder() == null ) || getSpeciesCustomOrder().isEmpty() ) {
420             sb.append( "<td>" );
421             sb.append( getSpeciesDataInAlphabeticalOrder( true, tax_code_to_id_map ) );
422             sb.append( getDomainDataInAlphabeticalOrder() );
423             sb.append( "</td>" );
424         }
425         else {
426             sb.append( "<td>" );
427             sb.append( getSpeciesDataInCustomOrder( true, tax_code_to_id_map ) );
428             sb.append( getDomainDataInAlphabeticalOrder() );
429             sb.append( "</td>" );
430         }
431         sb.append( "</tr>" );
432         return sb;
433     }
434
435     private StringBuffer toStringBufferSimpleTabDelimited() {
436         final StringBuffer sb = new StringBuffer();
437         sb.append( getDomainId() );
438         return sb;
439     }
440
441     public static enum PRINT_OPTION {
442         SIMPLE_TAB_DELIMITED, HTML;
443     }
444 }