Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.io

File SequenceAnnotationReport.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
19% of files have more coverage

Code metrics

92
153
12
1
491
351
72
0.47
12.75
12
6

Classes

Class Line # Actions
SequenceAnnotationReport 45 153 72 50
0.8054474680.5%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.io;
22   
23    import jalview.api.FeatureColourI;
24    import jalview.datamodel.DBRefEntry;
25    import jalview.datamodel.DBRefSource;
26    import jalview.datamodel.SequenceFeature;
27    import jalview.datamodel.SequenceI;
28    import jalview.util.MessageManager;
29    import jalview.util.StringUtils;
30    import jalview.util.UrlLink;
31    import jalview.viewmodel.seqfeatures.FeatureRendererModel;
32   
33    import java.util.Arrays;
34    import java.util.Collection;
35    import java.util.Comparator;
36    import java.util.LinkedHashMap;
37    import java.util.List;
38    import java.util.Map;
39   
40    /**
41    * generate HTML reports for a sequence
42    *
43    * @author jimp
44    */
 
45    public class SequenceAnnotationReport
46    {
47    private static final String COMMA = ",";
48   
49    private static final String ELLIPSIS = "...";
50   
51    private static final int MAX_REFS_PER_SOURCE = 4;
52   
53    private static final int MAX_SOURCES = 40;
54   
55    private static final String[][] PRIMARY_SOURCES = new String[][] {
56    DBRefSource.CODINGDBS, DBRefSource.DNACODINGDBS,
57    DBRefSource.PROTEINDBS };
58   
59    final String linkImageURL;
60   
61    /*
62    * Comparator to order DBRefEntry by Source + accession id (case-insensitive),
63    * with 'Primary' sources placed before others, and 'chromosome' first of all
64    */
65    private static Comparator<DBRefEntry> comparator = new Comparator<DBRefEntry>()
66    {
67   
 
68  145 toggle @Override
69    public int compare(DBRefEntry ref1, DBRefEntry ref2)
70    {
71  145 if (ref1.isChromosome())
72    {
73  0 return -1;
74    }
75  145 if (ref2.isChromosome())
76    {
77  0 return 1;
78    }
79  145 String s1 = ref1.getSource();
80  145 String s2 = ref2.getSource();
81  145 boolean s1Primary = isPrimarySource(s1);
82  145 boolean s2Primary = isPrimarySource(s2);
83  145 if (s1Primary && !s2Primary)
84    {
85  26 return -1;
86    }
87  119 if (!s1Primary && s2Primary)
88    {
89  1 return 1;
90    }
91  118 int comp = s1 == null ? -1 : (s2 == null ? 1 : s1
92    .compareToIgnoreCase(s2));
93  118 if (comp == 0)
94    {
95  5 String a1 = ref1.getAccessionId();
96  5 String a2 = ref2.getAccessionId();
97  5 comp = a1 == null ? -1 : (a2 == null ? 1 : a1
98    .compareToIgnoreCase(a2));
99    }
100  118 return comp;
101    }
102   
 
103  290 toggle private boolean isPrimarySource(String source)
104    {
105  290 for (String[] primary : PRIMARY_SOURCES)
106    {
107  870 for (String s : primary)
108    {
109  3369 if (source.equals(s))
110    {
111  37 return true;
112    }
113    }
114    }
115  253 return false;
116    }
117    };
118   
 
119  444 toggle public SequenceAnnotationReport(String linkURL)
120    {
121  444 this.linkImageURL = linkURL;
122    }
123   
124    /**
125    * Append text for the list of features to the tooltip
126    *
127    * @param sb
128    * @param rpos
129    * @param features
130    * @param minmax
131    */
 
132  0 toggle public void appendFeatures(final StringBuilder sb, int rpos,
133    List<SequenceFeature> features, FeatureRendererModel fr)
134    {
135  0 if (features != null)
136    {
137  0 for (SequenceFeature feature : features)
138    {
139  0 appendFeature(sb, rpos, fr, feature);
140    }
141    }
142    }
143   
144    /**
145    * Appends the feature at rpos to the given buffer
146    *
147    * @param sb
148    * @param rpos
149    * @param minmax
150    * @param feature
151    */
 
152  30 toggle void appendFeature(final StringBuilder sb, int rpos,
153    FeatureRendererModel fr, SequenceFeature feature)
154    {
155  30 if (feature.isContactFeature())
156    {
157  3 if (feature.getBegin() == rpos || feature.getEnd() == rpos)
158    {
159  2 if (sb.length() > 6)
160    {
161  1 sb.append("<br>");
162    }
163  2 sb.append(feature.getType()).append(" ").append(feature.getBegin())
164    .append(":").append(feature.getEnd());
165    }
166  3 return;
167    }
168   
169  27 if (sb.length() > 6)
170    {
171  15 sb.append("<br>");
172    }
173    // TODO: remove this hack to display link only features
174  27 boolean linkOnly = feature.getValue("linkonly") != null;
175  27 if (!linkOnly)
176    {
177  27 sb.append(feature.getType()).append(" ");
178  27 if (rpos != 0)
179    {
180    // we are marking a positional feature
181  13 sb.append(feature.begin);
182    }
183  27 if (feature.begin != feature.end)
184    {
185  13 sb.append(" ").append(feature.end);
186    }
187   
188  27 String description = feature.getDescription();
189  27 if (description != null && !description.equals(feature.getType()))
190    {
191  26 description = StringUtils.stripHtmlTags(description);
192  26 sb.append("; ").append(description);
193    }
194   
195  27 if (showScore(feature, fr))
196    {
197  3 sb.append(" Score=").append(String.valueOf(feature.getScore()));
198    }
199  27 String status = (String) feature.getValue("status");
200  27 if (status != null && status.length() > 0)
201    {
202  2 sb.append("; (").append(status).append(")");
203    }
204   
205    /*
206    * add attribute value if coloured by attribute
207    */
208  27 if (fr != null)
209    {
210  20 FeatureColourI fc = fr.getFeatureColours().get(feature.getType());
211  20 if (fc != null && fc.isColourByAttribute())
212    {
213  4 String[] attName = fc.getAttributeName();
214  4 String attVal = feature.getValueAsString(attName);
215  4 if (attVal != null)
216    {
217  3 sb.append("; ").append(String.join(":", attName)).append("=")
218    .append(attVal);
219    }
220    }
221    }
222    }
223    }
224   
225    /**
226    * Answers true if score should be shown, else false. Score is shown if it is
227    * not NaN, and the feature type has a non-trivial min-max score range
228    */
 
229  27 toggle boolean showScore(SequenceFeature feature, FeatureRendererModel fr)
230    {
231  27 if (Float.isNaN(feature.getScore()))
232    {
233  9 return false;
234    }
235  18 if (fr == null)
236    {
237  1 return true;
238    }
239  17 float[][] minMax = fr.getMinMax().get(feature.getType());
240   
241    /*
242    * minMax[0] is the [min, max] score range for positional features
243    */
244  17 if (minMax == null || minMax[0] == null || minMax[0][0] == minMax[0][1])
245    {
246  15 return false;
247    }
248  2 return true;
249    }
250   
251    /**
252    * Format and appends any hyperlinks for the sequence feature to the string
253    * buffer
254    *
255    * @param sb
256    * @param feature
257    */
 
258  0 toggle void appendLinks(final StringBuffer sb, SequenceFeature feature)
259    {
260  0 if (feature.links != null)
261    {
262  0 if (linkImageURL != null)
263    {
264  0 sb.append(" <img src=\"" + linkImageURL + "\">");
265    }
266    else
267    {
268  0 for (String urlstring : feature.links)
269    {
270  0 try
271    {
272  0 for (List<String> urllink : createLinksFrom(null, urlstring))
273    {
274  0 sb.append("<br/> <a href=\""
275    + urllink.get(3)
276    + "\" target=\""
277    + urllink.get(0)
278    + "\">"
279  0 + (urllink.get(0).toLowerCase()
280    .equals(urllink.get(1).toLowerCase()) ? urllink
281    .get(0) : (urllink.get(0) + ":" + urllink
282    .get(1))) + "</a></br>");
283    }
284    } catch (Exception x)
285    {
286  0 System.err.println("problem when creating links from "
287    + urlstring);
288  0 x.printStackTrace();
289    }
290    }
291    }
292   
293    }
294    }
295   
296    /**
297    *
298    * @param seq
299    * @param link
300    * @return Collection< List<String> > { List<String> { link target, link
301    * label, dynamic component inserted (if any), url }}
302    */
 
303  0 toggle Collection<List<String>> createLinksFrom(SequenceI seq, String link)
304    {
305  0 Map<String, List<String>> urlSets = new LinkedHashMap<>();
306  0 UrlLink urlLink = new UrlLink(link);
307  0 if (!urlLink.isValid())
308    {
309  0 System.err.println(urlLink.getInvalidMessage());
310  0 return null;
311    }
312   
313  0 urlLink.createLinksFromSeq(seq, urlSets);
314   
315  0 return urlSets.values();
316    }
317   
 
318  9 toggle public void createSequenceAnnotationReport(final StringBuilder tip,
319    SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
320    FeatureRendererModel fr)
321    {
322  9 createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
323    fr, false);
324    }
325   
326    /**
327    * Builds an html formatted report of sequence details and appends it to the
328    * provided buffer.
329    *
330    * @param sb
331    * buffer to append report to
332    * @param sequence
333    * the sequence the report is for
334    * @param showDbRefs
335    * whether to include database references for the sequence
336    * @param showNpFeats
337    * whether to include non-positional sequence features
338    * @param fr
339    * @param summary
340    * @return
341    */
 
342  10 toggle int createSequenceAnnotationReport(final StringBuilder sb,
343    SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
344    FeatureRendererModel fr, boolean summary)
345    {
346  10 String tmp;
347  10 sb.append("<i>");
348   
349  10 int maxWidth = 0;
350  10 if (sequence.getDescription() != null)
351    {
352  9 tmp = sequence.getDescription();
353  9 sb.append("<br>").append(tmp);
354  9 maxWidth = Math.max(maxWidth, tmp.length());
355    }
356  10 SequenceI ds = sequence;
357  10 while (ds.getDatasetSequence() != null)
358    {
359  0 ds = ds.getDatasetSequence();
360    }
361   
362  10 if (showDbRefs)
363    {
364  9 maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary));
365    }
366   
367    /*
368    * add non-positional features if wanted
369    */
370  10 if (showNpFeats)
371    {
372  8 for (SequenceFeature sf : sequence.getFeatures()
373    .getNonPositionalFeatures())
374    {
375  14 int sz = -sb.length();
376  14 appendFeature(sb, 0, fr, sf);
377  14 sz += sb.length();
378  14 maxWidth = Math.max(maxWidth, sz);
379    }
380    }
381  10 sb.append("</i>");
382  10 return maxWidth;
383    }
384   
385    /**
386    * A helper method that appends any DBRefs, returning the maximum line length
387    * added
388    *
389    * @param sb
390    * @param ds
391    * @param summary
392    * @return
393    */
 
394  9 toggle protected int appendDbRefs(final StringBuilder sb, SequenceI ds,
395    boolean summary)
396    {
397  9 DBRefEntry[] dbrefs = ds.getDBRefs();
398  9 if (dbrefs == null)
399    {
400  6 return 0;
401    }
402   
403    // note this sorts the refs held on the sequence!
404  3 Arrays.sort(dbrefs, comparator);
405  3 boolean ellipsis = false;
406  3 String source = null;
407  3 String lastSource = null;
408  3 int countForSource = 0;
409  3 int sourceCount = 0;
410  3 boolean moreSources = false;
411  3 int maxLineLength = 0;
412  3 int lineLength = 0;
413   
414  3 for (DBRefEntry ref : dbrefs)
415    {
416  49 source = ref.getSource();
417  49 if (source == null)
418    {
419    // shouldn't happen
420  0 continue;
421    }
422  49 boolean sourceChanged = !source.equals(lastSource);
423  49 if (sourceChanged)
424    {
425  45 lineLength = 0;
426  45 countForSource = 0;
427  45 sourceCount++;
428    }
429  49 if (sourceCount > MAX_SOURCES && summary)
430    {
431  1 ellipsis = true;
432  1 moreSources = true;
433  1 break;
434    }
435  48 lastSource = source;
436  48 countForSource++;
437  48 if (countForSource == 1 || !summary)
438    {
439  44 sb.append("<br>");
440    }
441  48 if (countForSource <= MAX_REFS_PER_SOURCE || !summary)
442    {
443  47 String accessionId = ref.getAccessionId();
444  47 lineLength += accessionId.length() + 1;
445  47 if (countForSource > 1 && summary)
446    {
447  3 sb.append(", ").append(accessionId);
448  3 lineLength++;
449    }
450    else
451    {
452  44 sb.append(source).append(" ").append(accessionId);
453  44 lineLength += source.length();
454    }
455  47 maxLineLength = Math.max(maxLineLength, lineLength);
456    }
457  48 if (countForSource == MAX_REFS_PER_SOURCE && summary)
458    {
459  1 sb.append(COMMA).append(ELLIPSIS);
460  1 ellipsis = true;
461    }
462    }
463  3 if (moreSources)
464    {
465  1 sb.append("<br>").append(source).append(COMMA).append(ELLIPSIS);
466    }
467  3 if (ellipsis)
468    {
469  1 sb.append("<br>(");
470  1 sb.append(MessageManager.getString("label.output_seq_details"));
471  1 sb.append(")");
472    }
473   
474  3 return maxLineLength;
475    }
476   
 
477  0 toggle public void createTooltipAnnotationReport(final StringBuilder tip,
478    SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
479    FeatureRendererModel fr)
480    {
481  0 int maxWidth = createSequenceAnnotationReport(tip, sequence,
482    showDbRefs, showNpFeats, fr, true);
483   
484  0 if (maxWidth > 60)
485    {
486    // ? not sure this serves any useful purpose
487    // tip.insert(0, "<table width=350 border=0><tr><td>");
488    // tip.append("</td></tr></table>");
489    }
490    }
491    }