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             if ( html ) {
166                 sb.append( ":" );
167             }
168             else {
169                 sb.append( "\t" );
170             }
171             sb.append( getSpeciesData().get( species ).toStringBuffer( getDetaildness(), html ) );
172         }
173         if ( html ) {
174             sb.append( "<br>" );
175         }
176         else {
177             sb.append( "\n\t" );
178         }
179     }
180
181     private void addTaxWithLink( final StringBuffer sb,
182                                  final String tax_code,
183                                  final Map<String, Integer> tax_code_to_id_map ) {
184         sb.append( "<b>" );
185         if ( !ForesterUtil.isEmpty( tax_code )
186                 && ( ( tax_code_to_id_map != null ) && tax_code_to_id_map.containsKey( tax_code ) ) ) {
187             sb.append( "<a href=\"" + SurfacingConstants.UNIPROT_TAXONOMY_ID_LINK + tax_code_to_id_map.get( tax_code )
188                     + "\" target=\"taxonomy_window\">" + tax_code + "</a>" );
189         }
190         else {
191             sb.append( tax_code );
192         }
193         sb.append( "</b>" );
194     }
195
196     private int compareByDomainId( final DomainSimilarity other ) {
197         return getDomainId().compareToIgnoreCase( other.getDomainId() );
198     }
199
200     @Override
201     public int compareTo( final DomainSimilarity domain_similarity ) {
202         if ( this == domain_similarity ) {
203             return EQUAL;
204         }
205         else if ( domain_similarity == null ) {
206             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to null" );
207         }
208         else if ( domain_similarity.getClass() != this.getClass() ) {
209             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to "
210                     + domain_similarity.getClass() );
211         }
212         return compareByDomainId( domain_similarity );
213     }
214
215     @Override
216     public SortedSet<String> getCombinableDomainIds( final Species species_of_combinable_domain ) {
217         final SortedSet<String> sorted_ids = new TreeSet<String>();
218         if ( getSpeciesData().containsKey( species_of_combinable_domain ) ) {
219             for( final String id : getSpeciesData().get( species_of_combinable_domain )
220                     .getCombinableDomainIdToCountsMap().keySet() ) {
221                 sorted_ids.add( id );
222             }
223         }
224         return sorted_ids;
225     }
226
227     private CombinableDomains getCombinableDomains() {
228         return _combinable_domains;
229     }
230
231     private DomainSimilarityCalculator.Detailedness getDetaildness() {
232         return _detailedness;
233     }
234
235     @Override
236     public String getDomainId() {
237         return getCombinableDomains().getKeyDomain();
238     }
239
240     @Override
241     public int getMaximalDifference() {
242         return _max_difference;
243     }
244
245     @Override
246     public int getMaximalDifferenceInCounts() {
247         return _max_difference_in_counts;
248     }
249
250     @Override
251     public double getMaximalSimilarityScore() {
252         return _max;
253     }
254
255     @Override
256     public double getMeanSimilarityScore() {
257         return _mean;
258     }
259
260     @Override
261     public double getMinimalSimilarityScore() {
262         return _min;
263     }
264
265     @Override
266     public int getN() {
267         return _n;
268     }
269
270     @Override
271     public SortedSet<Species> getSpecies() {
272         final SortedSet<Species> species = new TreeSet<Species>();
273         for( final Species s : getSpeciesData().keySet() ) {
274             species.add( s );
275         }
276         return species;
277     }
278
279     public List<Species> getSpeciesCustomOrder() {
280         return _species_order;
281     }
282
283     @Override
284     public SortedMap<Species, SpeciesSpecificDcData> getSpeciesData() {
285         return _species_data;
286     }
287
288     private StringBuffer getSpeciesDataInAlphabeticalOrder( final boolean html,
289                                                             final Map<String, Integer> tax_code_to_id_map ) {
290         final StringBuffer sb = new StringBuffer();
291         for( final Species species : getSpeciesData().keySet() ) {
292             addSpeciesSpecificDomainData( sb, species, html, tax_code_to_id_map );
293         }
294         return sb;
295     }
296
297     private StringBuffer getDomainDataInAlphabeticalOrder() {
298         final SortedMap<String, SortedSet<String>> m = new TreeMap<String, SortedSet<String>>();
299         final StringBuffer sb = new StringBuffer();
300         for( final Species species : getSpeciesData().keySet() ) {
301             for( final String combable_dom : getCombinableDomainIds( species ) ) {
302                 if ( !m.containsKey( combable_dom ) ) {
303                     m.put( combable_dom, new TreeSet<String>() );
304                 }
305                 m.get( combable_dom ).add( species.getSpeciesId() );
306             }
307         }
308         for( final Map.Entry<String, SortedSet<String>> e : m.entrySet() ) {
309             sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + e.getKey() + "\">" + e.getKey() + "</a>" );
310             sb.append( ": " );
311             for( final String s : e.getValue() ) {
312                 sb.append( s );
313                 sb.append( " " );
314             }
315             sb.append( "<br>" );
316         }
317         return sb;
318     }
319
320     private StringBuffer getSpeciesDataInCustomOrder( final boolean html, final Map<String, Integer> tax_code_to_id_map ) {
321         final StringBuffer sb = new StringBuffer();
322         for( final Species order_species : getSpeciesCustomOrder() ) {
323             if ( getSpeciesData().keySet().contains( order_species ) ) {
324                 addSpeciesSpecificDomainData( sb, order_species, html, tax_code_to_id_map );
325             }
326             else {
327                 sb.append( PrintableDomainSimilarity.NO_SPECIES );
328                 sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
329             }
330         }
331         return sb;
332     }
333
334     @Override
335     public double getStandardDeviationOfSimilarityScore() {
336         return _sd;
337     }
338
339     private void init() {
340         _detailedness = DomainSimilarityCalculator.Detailedness.PUNCTILIOUS;
341     }
342
343     private boolean isTreatAsBinaryComparison() {
344         return _treat_as_binary_comparison;
345     }
346
347     public void setDetailedness( final Detailedness detailedness ) {
348         _detailedness = detailedness;
349     }
350
351     public void setSpeciesOrder( final List<Species> species_order ) {
352         if ( !species_order.containsAll( getSpeciesData().keySet() ) ) {
353             throw new IllegalArgumentException( "list to order species must contain all species of multiple combinable domains similarity" );
354         }
355         _species_order = species_order;
356     }
357
358     @Override
359     public StringBuffer toStringBuffer( final PrintableDomainSimilarity.PRINT_OPTION print_option,
360                                         final Map<String, Integer> tax_code_to_id_map ) {
361         switch ( print_option ) {
362             case SIMPLE_TAB_DELIMITED:
363                 return toStringBufferSimpleTabDelimited();
364             case HTML:
365                 return toStringBufferDetailedHTML( tax_code_to_id_map );
366             default:
367                 throw new AssertionError( "Unknown print option: " + print_option );
368         }
369     }
370
371     private StringBuffer toStringBufferDetailedHTML( final Map<String, Integer> tax_code_to_id_map ) {
372         final StringBuffer sb = new StringBuffer();
373         sb.append( "<tr>" );
374         sb.append( "<td>" );
375         sb.append( "<b>" );
376         sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + getDomainId() + "\" target=\"pfam_window\">"
377                 + getDomainId() + "</a>" );
378         sb.append( "</b>" );
379         sb.append( "<a name=\"" + getDomainId() + "\">" );
380         sb.append( "</td>" );
381         sb.append( "<td>" );
382         sb.append( "<a href=\"" + SurfacingConstants.GOOGLE_SCHOLAR_SEARCH + getDomainId()
383                 + "\" target=\"gs_window\">gs</a>" );
384         sb.append( "</td>" );
385         if ( getMaximalSimilarityScore() > 0 ) {
386             sb.append( "<td>" );
387             sb.append( ForesterUtil.round( getMeanSimilarityScore(), 3 ) );
388             sb.append( "</td>" );
389             if ( SurfacingConstants.PRINT_MORE_DOM_SIMILARITY_INFO ) {
390                 if ( !isTreatAsBinaryComparison() ) {
391                     sb.append( "<td>" );
392                     sb.append( "(" );
393                     sb.append( ForesterUtil.round( getStandardDeviationOfSimilarityScore(), 3 ) );
394                     sb.append( ")" );
395                     sb.append( "</td>" );
396                     sb.append( "<td>" );
397                     sb.append( "[" );
398                     sb.append( ForesterUtil.round( getMinimalSimilarityScore(), 3 ) );
399                     sb.append( "-" );
400                     sb.append( ForesterUtil.round( getMaximalSimilarityScore(), 3 ) );
401                     sb.append( "]" );
402                     sb.append( "</td>" );
403                 }
404             }
405         }
406         sb.append( "<td>" );
407         sb.append( getMaximalDifference() );
408         sb.append( "</td>" );
409         sb.append( "<td>" );
410         if ( isTreatAsBinaryComparison() ) {
411             sb.append( getMaximalDifferenceInCounts() );
412         }
413         else {
414             sb.append( Math.abs( getMaximalDifferenceInCounts() ) );
415         }
416         sb.append( "</td>" );
417         if ( !isTreatAsBinaryComparison() ) {
418             sb.append( "<td>" );
419             sb.append( "<b>" );
420             sb.append( getSpeciesData().size() );
421             sb.append( "</b>" );
422             sb.append( "</td>" );
423         }
424         if ( ( getSpeciesCustomOrder() == null ) || getSpeciesCustomOrder().isEmpty() ) {
425             sb.append( "<td>" );
426             sb.append( getSpeciesDataInAlphabeticalOrder( true, tax_code_to_id_map ) );
427             sb.append( getDomainDataInAlphabeticalOrder() );
428             sb.append( "</td>" );
429         }
430         else {
431             sb.append( "<td>" );
432             sb.append( getSpeciesDataInCustomOrder( true, tax_code_to_id_map ) );
433             sb.append( getDomainDataInAlphabeticalOrder() );
434             sb.append( "</td>" );
435         }
436         sb.append( "</tr>" );
437         return sb;
438     }
439
440     private StringBuffer toStringBufferSimpleTabDelimited() {
441         final StringBuffer sb = new StringBuffer();
442         sb.append( getDomainId() );
443         sb.append( "\t" );
444         sb.append( getSpeciesDataInAlphabeticalOrder( false, null ) );
445         sb.append( "\n" );
446         return sb;
447     }
448
449     public static enum PRINT_OPTION {
450         SIMPLE_TAB_DELIMITED, HTML;
451     }
452 }