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     private static final boolean                                         PRINT_MORE_INFO   = false;
46     final private double                                                 _min;
47     final private double                                                 _max;
48     final private double                                                 _mean;
49     final private double                                                 _sd;
50     final private int                                                    _n;
51     private final int                                                    _max_difference_in_counts;
52     private final int                                                    _max_difference;
53     final private CombinableDomains                                      _combinable_domains;
54     final private SortedMap<Species, SpeciesSpecificDomainSimilariyData> _species_data;
55     private List<Species>                                                _species_order;
56     private DomainSimilarityCalculator.Detailedness                      _detailedness;
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, SpeciesSpecificDomainSimilariyData> 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     private void addSpeciesSpecificDomainData( final StringBuffer sb,
119                                                final Species species,
120                                                final boolean html,
121                                                final Map<String, Integer> tax_code_to_id_map ) {
122         if ( html ) {
123             addTaxWithLink( sb, species.getSpeciesId(), tax_code_to_id_map );
124         }
125         else {
126             sb.append( species.getSpeciesId() );
127         }
128         if ( getDetaildness() != DomainSimilarityCalculator.Detailedness.BASIC ) {
129             sb.append( ":" );
130             sb.append( getSpeciesData().get( species ).toStringBuffer( getDetaildness(), html ) );
131         }
132         if ( html ) {
133             sb.append( "<br>" );
134         }
135         else {
136             sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
137         }
138     }
139
140     private void addTaxWithLink( final StringBuffer sb,
141                                  final String tax_code,
142                                  final Map<String, Integer> tax_code_to_id_map ) {
143         sb.append( "<b>" );
144         if ( !ForesterUtil.isEmpty( tax_code )
145                 && ( ( tax_code_to_id_map != null ) && tax_code_to_id_map.containsKey( tax_code ) ) ) {
146             sb.append( "<a href=\"" + SurfacingConstants.UNIPROT_TAXONOMY_ID_LINK + tax_code_to_id_map.get( tax_code )
147                     + "\" target=\"taxonomy_window\">" + tax_code + "</a>" );
148         }
149         else {
150             sb.append( tax_code );
151         }
152         sb.append( "</b>" );
153     }
154
155     private int compareByDomainId( final DomainSimilarity other ) {
156         return getDomainId().compareToIgnoreCase( other.getDomainId() );
157     }
158
159     @Override
160     public int compareTo( final DomainSimilarity domain_similarity ) {
161         if ( this == domain_similarity ) {
162             return EQUAL;
163         }
164         else if ( domain_similarity == null ) {
165             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to null" );
166         }
167         else if ( domain_similarity.getClass() != this.getClass() ) {
168             throw new IllegalArgumentException( "attempt to compare " + this.getClass() + " to "
169                     + domain_similarity.getClass() );
170         }
171         return compareByDomainId( domain_similarity );
172     }
173
174     @Override
175     public SortedSet<String> getCombinableDomainIds( final Species species_of_combinable_domain ) {
176         final SortedSet<String> sorted_ids = new TreeSet<String>();
177         if ( getSpeciesData().containsKey( species_of_combinable_domain ) ) {
178             for( final String id : getSpeciesData().get( species_of_combinable_domain )
179                     .getCombinableDomainIdToCountsMap().keySet() ) {
180                 sorted_ids.add( id );
181             }
182         }
183         return sorted_ids;
184     }
185
186     private CombinableDomains getCombinableDomains() {
187         return _combinable_domains;
188     }
189
190     private DomainSimilarityCalculator.Detailedness getDetaildness() {
191         return _detailedness;
192     }
193
194     @Override
195     public String getDomainId() {
196         return getCombinableDomains().getKeyDomain();
197     }
198
199     @Override
200     public int getMaximalDifference() {
201         return _max_difference;
202     }
203
204     @Override
205     public int getMaximalDifferenceInCounts() {
206         return _max_difference_in_counts;
207     }
208
209     @Override
210     public double getMaximalSimilarityScore() {
211         return _max;
212     }
213
214     @Override
215     public double getMeanSimilarityScore() {
216         return _mean;
217     }
218
219     @Override
220     public double getMinimalSimilarityScore() {
221         return _min;
222     }
223
224     @Override
225     public int getN() {
226         return _n;
227     }
228
229     @Override
230     public SortedSet<Species> getSpecies() {
231         final SortedSet<Species> species = new TreeSet<Species>();
232         for( final Species s : getSpeciesData().keySet() ) {
233             species.add( s );
234         }
235         return species;
236     }
237
238     public List<Species> getSpeciesCustomOrder() {
239         return _species_order;
240     }
241
242     @Override
243     public SortedMap<Species, SpeciesSpecificDomainSimilariyData> getSpeciesData() {
244         return _species_data;
245     }
246
247     private StringBuffer getSpeciesDataInAlphabeticalOrder( final boolean html,
248                                                             final Map<String, Integer> tax_code_to_id_map ) {
249         final StringBuffer sb = new StringBuffer();
250         for( final Species species : getSpeciesData().keySet() ) {
251             addSpeciesSpecificDomainData( sb, species, html, tax_code_to_id_map );
252         }
253         return sb;
254     }
255
256     private StringBuffer getDomainDataInAlphabeticalOrder() {
257         final SortedMap<String, SortedSet<String>> m = new TreeMap<String, SortedSet<String>>();
258         final StringBuffer sb = new StringBuffer();
259         for( final Species species : getSpeciesData().keySet() ) {
260             for( final String combable_dom : getCombinableDomainIds( species ) ) {
261                 if ( !m.containsKey( combable_dom ) ) {
262                     m.put( combable_dom, new TreeSet<String>() );
263                 }
264                 m.get( combable_dom ).add( species.getSpeciesId() );
265             }
266         }
267         for( final Map.Entry<String, SortedSet<String>> e : m.entrySet() ) {
268             sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + e.getKey() + "\">" + e.getKey() + "</a>" );
269             sb.append( ": " );
270             for( final String s : e.getValue() ) {
271                 sb.append( s );
272                 sb.append( " " );
273             }
274             sb.append( "<br>" );
275         }
276         return sb;
277     }
278
279     private StringBuffer getSpeciesDataInCustomOrder( final boolean html, final Map<String, Integer> tax_code_to_id_map ) {
280         final StringBuffer sb = new StringBuffer();
281         for( final Species order_species : getSpeciesCustomOrder() ) {
282             if ( getSpeciesData().keySet().contains( order_species ) ) {
283                 addSpeciesSpecificDomainData( sb, order_species, html, tax_code_to_id_map );
284             }
285             else {
286                 sb.append( PrintableDomainSimilarity.NO_SPECIES );
287                 sb.append( PrintableDomainSimilarity.SPECIES_SEPARATOR );
288             }
289         }
290         return sb;
291     }
292
293     @Override
294     public double getStandardDeviationOfSimilarityScore() {
295         return _sd;
296     }
297
298     private void init() {
299         _detailedness = DomainSimilarityCalculator.Detailedness.PUNCTILIOUS;
300     }
301
302     private boolean isTreatAsBinaryComparison() {
303         return _treat_as_binary_comparison;
304     }
305
306     public void setDetailedness( final Detailedness detailedness ) {
307         _detailedness = detailedness;
308     }
309
310     public void setSpeciesOrder( final List<Species> species_order ) {
311         if ( !species_order.containsAll( getSpeciesData().keySet() ) ) {
312             throw new IllegalArgumentException( "list to order species must contain all species of multiple combinable domains similarity" );
313         }
314         _species_order = species_order;
315     }
316
317     @Override
318     public StringBuffer toStringBuffer( final PrintableDomainSimilarity.PRINT_OPTION print_option,
319                                         final Map<String, Integer> tax_code_to_id_map ) {
320         switch ( print_option ) {
321             case SIMPLE_TAB_DELIMITED:
322                 return toStringBufferSimpleTabDelimited();
323             case HTML:
324                 return toStringBufferDetailedHTML( tax_code_to_id_map );
325             default:
326                 throw new AssertionError( "Unknown print option: " + print_option );
327         }
328     }
329
330     private StringBuffer toStringBufferDetailedHTML( final Map<String, Integer> tax_code_to_id_map ) {
331         final StringBuffer sb = new StringBuffer();
332         sb.append( "<tr>" );
333         sb.append( "<td>" );
334         sb.append( "<b>" );
335         sb.append( "<a href=\"" + SurfacingConstants.PFAM_FAMILY_ID_LINK + getDomainId() + "\" target=\"pfam_window\">"
336                 + getDomainId() + "</a>" );
337         sb.append( "</b>" );
338         sb.append( "<a name=\"" + getDomainId() + "\">" );
339         sb.append( "</td>" );
340         sb.append( "<td>" );
341         sb.append( "<a href=\"" + SurfacingConstants.GOOGLE_SCHOLAR_SEARCH + getDomainId()
342                 + "\" target=\"gs_window\">gs</a>" );
343         sb.append( "</td>" );
344         sb.append( "<td>" );
345         sb.append( ForesterUtil.round( getMeanSimilarityScore(), 3 ) );
346         sb.append( "</td>" );
347         if ( PRINT_MORE_INFO ) {
348             if ( !isTreatAsBinaryComparison() ) {
349                 sb.append( "<td>" );
350                 sb.append( "(" );
351                 sb.append( ForesterUtil.round( getStandardDeviationOfSimilarityScore(), 3 ) );
352                 sb.append( ")" );
353                 sb.append( "</td>" );
354                 sb.append( "<td>" );
355                 sb.append( "[" );
356                 sb.append( ForesterUtil.round( getMinimalSimilarityScore(), 3 ) );
357                 sb.append( "-" );
358                 sb.append( ForesterUtil.round( getMaximalSimilarityScore(), 3 ) );
359                 sb.append( "]" );
360                 sb.append( "</td>" );
361             }
362         }
363         sb.append( "<td>" );
364         sb.append( getMaximalDifference() );
365         sb.append( "</td>" );
366         sb.append( "<td>" );
367         if ( isTreatAsBinaryComparison() ) {
368             sb.append( getMaximalDifferenceInCounts() );
369         }
370         else {
371             sb.append( Math.abs( getMaximalDifferenceInCounts() ) );
372         }
373         sb.append( "</td>" );
374         if ( !isTreatAsBinaryComparison() ) {
375             sb.append( "<td>" );
376             sb.append( "<b>" );
377             sb.append( getSpeciesData().size() );
378             sb.append( "</b>" );
379             sb.append( "</td>" );
380         }
381         if ( ( getSpeciesCustomOrder() == null ) || getSpeciesCustomOrder().isEmpty() ) {
382             sb.append( "<td>" );
383             sb.append( getSpeciesDataInAlphabeticalOrder( true, tax_code_to_id_map ) );
384             sb.append( getDomainDataInAlphabeticalOrder() );
385             sb.append( "</td>" );
386         }
387         else {
388             sb.append( "<td>" );
389             sb.append( getSpeciesDataInCustomOrder( true, tax_code_to_id_map ) );
390             sb.append( getDomainDataInAlphabeticalOrder() );
391             sb.append( "</td>" );
392         }
393         sb.append( "</tr>" );
394         return sb;
395     }
396
397     private StringBuffer toStringBufferSimpleTabDelimited() {
398         final StringBuffer sb = new StringBuffer();
399         sb.append( getDomainId() );
400         return sb;
401     }
402
403     public static enum PRINT_OPTION {
404         SIMPLE_TAB_DELIMITED, HTML;
405     }
406 }