Clover icon

jalviewX

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

File AnnotationColourGradient.java

 

Coverage histogram

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

Code metrics

62
118
21
1
486
336
80
0.68
5.62
21
3.81

Classes

Class Line # Actions
AnnotationColourGradient 37 118 80 47
0.7661691376.6%
 

Contributing tests

This file is covered by 8 tests. .

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.schemes;
22   
23    import jalview.datamodel.AlignmentAnnotation;
24    import jalview.datamodel.AlignmentI;
25    import jalview.datamodel.AnnotatedCollectionI;
26    import jalview.datamodel.Annotation;
27    import jalview.datamodel.GraphLine;
28    import jalview.datamodel.SequenceCollectionI;
29    import jalview.datamodel.SequenceI;
30    import jalview.renderer.AnnotationRenderer;
31    import jalview.util.Comparison;
32   
33    import java.awt.Color;
34    import java.util.IdentityHashMap;
35    import java.util.Map;
36   
 
37    public class AnnotationColourGradient extends FollowerColourScheme
38    {
39    public static final int NO_THRESHOLD = -1;
40   
41    public static final int BELOW_THRESHOLD = 0;
42   
43    public static final int ABOVE_THRESHOLD = 1;
44   
45    private final AlignmentAnnotation annotation;
46   
47    private final int aboveAnnotationThreshold;
48   
49    public boolean thresholdIsMinMax = false;
50   
51    private GraphLine annotationThreshold;
52   
53    private int redMin;
54   
55    private int greenMin;
56   
57    private int blueMin;
58   
59    private int redRange;
60   
61    private int greenRange;
62   
63    private int blueRange;
64   
65    private boolean predefinedColours = false;
66   
67    private boolean seqAssociated = false;
68   
69    /**
70    * false if the scheme was constructed without a minColour and maxColour used
71    * to decide if existing colours should be taken from annotation elements when
72    * they exist
73    */
74    private boolean noGradient = false;
75   
76    private IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
77   
 
78  4 toggle @Override
79    public ColourSchemeI getInstance(AnnotatedCollectionI sg,
80    Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
81    {
82  4 AnnotationColourGradient acg = new AnnotationColourGradient(annotation,
83    getColourScheme(), aboveAnnotationThreshold);
84  4 acg.thresholdIsMinMax = thresholdIsMinMax;
85  4 acg.annotationThreshold = (annotationThreshold == null) ? null
86    : new GraphLine(annotationThreshold);
87  4 acg.redMin = redMin;
88  4 acg.greenMin = greenMin;
89  4 acg.blueMin = blueMin;
90  4 acg.redRange = redRange;
91  4 acg.greenRange = greenRange;
92  4 acg.blueRange = blueRange;
93  4 acg.predefinedColours = predefinedColours;
94  4 acg.seqAssociated = seqAssociated;
95  4 acg.noGradient = noGradient;
96  4 return acg;
97    }
98   
99    /**
100    * Creates a new AnnotationColourGradient object.
101    */
 
102  6 toggle public AnnotationColourGradient(AlignmentAnnotation annotation,
103    ColourSchemeI originalColour, int aboveThreshold)
104    {
105  6 if (originalColour instanceof AnnotationColourGradient)
106    {
107  0 setColourScheme(((AnnotationColourGradient) originalColour)
108    .getColourScheme());
109    }
110    else
111    {
112  6 setColourScheme(originalColour);
113    }
114   
115  6 this.annotation = annotation;
116   
117  6 aboveAnnotationThreshold = aboveThreshold;
118   
119  6 if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null)
120    {
121  4 annotationThreshold = annotation.threshold;
122    }
123    // clear values so we don't get weird black bands...
124  6 redMin = 254;
125  6 greenMin = 254;
126  6 blueMin = 254;
127  6 redRange = 0;
128  6 greenRange = 0;
129  6 blueRange = 0;
130   
131  6 noGradient = true;
132  6 checkLimits();
133    }
134   
135    /**
136    * Creates a new AnnotationColourGradient object.
137    */
 
138  9 toggle public AnnotationColourGradient(AlignmentAnnotation annotation,
139    Color minColour, Color maxColour, int aboveThreshold)
140    {
141  9 this.annotation = annotation;
142   
143  9 aboveAnnotationThreshold = aboveThreshold;
144   
145  9 if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null)
146    {
147  6 annotationThreshold = annotation.threshold;
148    }
149   
150  9 redMin = minColour.getRed();
151  9 greenMin = minColour.getGreen();
152  9 blueMin = minColour.getBlue();
153   
154  9 redRange = maxColour.getRed() - redMin;
155  9 greenRange = maxColour.getGreen() - greenMin;
156  9 blueRange = maxColour.getBlue() - blueMin;
157   
158  9 noGradient = false;
159  9 checkLimits();
160    }
161   
 
162  15 toggle private void checkLimits()
163    {
164  15 aamax = annotation.graphMax;
165  15 aamin = annotation.graphMin;
166  15 if (annotation.isRNA())
167    {
168    // reset colour palette
169  0 ColourSchemeProperty.resetRnaHelicesShading();
170  0 ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax);
171    }
172    }
173   
 
174  10 toggle @Override
175    public void alignmentChanged(AnnotatedCollectionI alignment,
176    Map<SequenceI, SequenceCollectionI> hiddenReps)
177    {
178  10 super.alignmentChanged(alignment, hiddenReps);
179   
180  10 if (seqAssociated && annotation.getCalcId() != null)
181    {
182  10 if (seqannot != null)
183    {
184  6 seqannot.clear();
185    }
186    else
187    {
188  4 seqannot = new IdentityHashMap<SequenceI, AlignmentAnnotation>();
189    }
190    // resolve the context containing all the annotation for the sequence
191  10 AnnotatedCollectionI alcontext = alignment instanceof AlignmentI
192    ? alignment
193    : alignment.getContext();
194  10 boolean f = true, rna = false;
195  10 for (AlignmentAnnotation alan : alcontext
196    .findAnnotation(annotation.getCalcId()))
197    {
198  340 if (alan.sequenceRef != null
199    && (alan.label != null && annotation != null
200    && alan.label.equals(annotation.label)))
201    {
202  150 if (!rna && alan.isRNA())
203    {
204  0 rna = true;
205    }
206  150 seqannot.put(alan.sequenceRef, alan);
207  150 if (f || alan.graphMax > aamax)
208    {
209  30 aamax = alan.graphMax;
210    }
211  150 if (f || alan.graphMin < aamin)
212    {
213  10 aamin = alan.graphMin;
214    }
215  150 f = false;
216    }
217    }
218  10 if (rna)
219    {
220  0 ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax);
221    }
222    }
223    }
224   
225    float aamin = 0f, aamax = 0f;
226   
 
227  2 toggle public AlignmentAnnotation getAnnotation()
228    {
229  2 return annotation;
230    }
231   
 
232  2 toggle public int getAboveThreshold()
233    {
234  2 return aboveAnnotationThreshold;
235    }
236   
 
237  2 toggle public float getAnnotationThreshold()
238    {
239  2 if (annotationThreshold == null)
240    {
241  0 return 0;
242    }
243    else
244    {
245  2 return annotationThreshold.value;
246    }
247    }
248   
 
249  2 toggle public Color getMinColour()
250    {
251  2 return new Color(redMin, greenMin, blueMin);
252    }
253   
 
254  2 toggle public Color getMaxColour()
255    {
256  2 return new Color(redMin + redRange, greenMin + greenRange,
257    blueMin + blueRange);
258    }
259   
260    /**
261    * DOCUMENT ME!
262    *
263    * @param n
264    * DOCUMENT ME!
265    *
266    * @return DOCUMENT ME!
267    */
 
268  0 toggle @Override
269    public Color findColour(char c)
270    {
271  0 return Color.red;
272    }
273   
274    /**
275    * Returns the colour for a given character and position in a sequence
276    *
277    * @param c
278    * the residue character
279    * @param j
280    * the aligned position
281    * @param seq
282    * the sequence
283    * @return
284    */
 
285  406 toggle @Override
286    public Color findColour(char c, int j, SequenceI seq)
287    {
288    /*
289    * locate the annotation we are configured to colour by
290    */
291  406 AlignmentAnnotation ann = (seqAssociated && seqannot != null
292    ? seqannot.get(seq)
293    : this.annotation);
294   
295    /*
296    * if gap or no annotation at position, no colour (White)
297    */
298  406 if (ann == null || ann.annotations == null
299    || j >= ann.annotations.length || ann.annotations[j] == null
300    || Comparison.isGap(c))
301    {
302  77 return Color.white;
303    }
304   
305  329 Annotation aj = ann.annotations[j];
306    // 'use original colours' => colourScheme != null
307    // -> look up colour to be used
308    // predefined colours => preconfigured shading
309    // -> only use original colours reference if thresholding enabled &
310    // minmax exists
311    // annotation.hasIcons => null or black colours replaced with glyph
312    // colours
313    // -> reuse original colours if present
314    // -> if thresholding enabled then return colour on non-whitespace glyph
315   
316    /*
317    * if threshold applies, and annotation fails the test - no colour (white)
318    */
319  329 if (annotationThreshold != null)
320    {
321  307 if ((aboveAnnotationThreshold == ABOVE_THRESHOLD
322    && aj.value < annotationThreshold.value)
323    || (aboveAnnotationThreshold == BELOW_THRESHOLD
324    && aj.value > annotationThreshold.value))
325    {
326  255 return Color.white;
327    }
328    }
329   
330    /*
331    * If 'use original colours' then return the colour of the annotation
332    * at the aligned position - computed using the background colour scheme
333    */
334  74 if (predefinedColours && aj.colour != null
335    && !aj.colour.equals(Color.black))
336    {
337  10 return aj.colour;
338    }
339   
340  64 Color result = Color.white;
341  64 if (ann.hasIcons && ann.graph == AlignmentAnnotation.NO_GRAPH)
342    {
343    /*
344    * secondary structure symbol colouring
345    */
346  0 if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
347    && aj.secondaryStructure != '-')
348    {
349  0 if (getColourScheme() != null)
350    {
351  0 result = getColourScheme().findColour(c, j, seq, null, 0f);
352    }
353    else
354    {
355  0 if (ann.isRNA())
356    {
357  0 result = ColourSchemeProperty.rnaHelices[(int) aj.value];
358    }
359    else
360    {
361  0 result = ann.annotations[j].secondaryStructure == 'H'
362    ? AnnotationRenderer.HELIX_COLOUR
363  0 : ann.annotations[j].secondaryStructure == 'E'
364    ? AnnotationRenderer.SHEET_COLOUR
365    : AnnotationRenderer.STEM_COLOUR;
366    }
367    }
368    }
369    else
370    {
371  0 return Color.white;
372    }
373    }
374  64 else if (noGradient)
375    {
376  0 if (getColourScheme() != null)
377    {
378  0 result = getColourScheme().findColour(c, j, seq, null, 0f);
379    }
380    else
381    {
382  0 if (aj.colour != null)
383    {
384  0 result = aj.colour;
385    }
386    }
387    }
388    else
389    {
390  64 result = shadeCalculation(ann, j);
391    }
392   
393  64 return result;
394    }
395   
396    /**
397    * Returns a graduated colour for the annotation at the given column. If there
398    * is a threshold value, and it is used as the top/bottom of the colour range,
399    * and the value satisfies the threshold condition, then a colour
400    * proportionate to the range from the threshold is calculated. For all other
401    * cases, a colour proportionate to the annotation's min-max range is
402    * calulated. Note that thresholding is _not_ done here (a colour is computed
403    * even if threshold is not passed).
404    *
405    * @param ann
406    * @param col
407    * @return
408    */
 
409  119 toggle Color shadeCalculation(AlignmentAnnotation ann, int col)
410    {
411  119 float range = 1f;
412  119 float value = ann.annotations[col].value;
413  119 if (thresholdIsMinMax && ann.threshold != null
414    && aboveAnnotationThreshold == ABOVE_THRESHOLD
415    && value >= ann.threshold.value)
416    {
417  12 range = (value - ann.threshold.value)
418    / (ann.graphMax - ann.threshold.value);
419    }
420  107 else if (thresholdIsMinMax && ann.threshold != null
421    && aboveAnnotationThreshold == BELOW_THRESHOLD
422    && value <= ann.threshold.value)
423    {
424  12 range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
425    }
426    else
427    {
428  95 if (ann.graphMax != ann.graphMin)
429    {
430  95 range = (value - ann.graphMin) / (ann.graphMax - ann.graphMin);
431    }
432    else
433    {
434  0 range = 0f;
435    }
436    }
437   
438  119 int dr = (int) (redRange * range + redMin);
439  119 int dg = (int) (greenRange * range + greenMin);
440  119 int db = (int) (blueRange * range + blueMin);
441   
442  119 return new Color(dr, dg, db);
443    }
444   
 
445  2 toggle public boolean isPredefinedColours()
446    {
447  2 return predefinedColours;
448    }
449   
 
450  3 toggle public void setPredefinedColours(boolean predefinedColours)
451    {
452  3 this.predefinedColours = predefinedColours;
453    }
454   
 
455  4 toggle public boolean isSeqAssociated()
456    {
457  4 return seqAssociated;
458    }
459   
 
460  4 toggle public void setSeqAssociated(boolean sassoc)
461    {
462  4 seqAssociated = sassoc;
463    }
464   
 
465  0 toggle public boolean isThresholdIsMinMax()
466    {
467  0 return thresholdIsMinMax;
468    }
469   
 
470  4 toggle public void setThresholdIsMinMax(boolean minMax)
471    {
472  4 this.thresholdIsMinMax = minMax;
473    }
474   
 
475  4 toggle @Override
476    public String getSchemeName()
477    {
478  4 return "Annotation";
479    }
480   
 
481  0 toggle @Override
482    public boolean isSimple()
483    {
484  0 return false;
485    }
486    }