Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:38:20 GMT
  2. Package jalview.schemes

File AnnotationColourGradient.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
33% of files have more coverage

Code metrics

66
118
21
1
490
340
82
0.69
5.62
21
3.9

Classes

Class Line # Actions
AnnotationColourGradient 38 118 82
0.5073170750.7%
 

Contributing tests

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