JAL-1492 JAL-1397 make AnnotatedCollectionI context aware so groups can be coloured...
[jalview.git] / src / jalview / schemes / AnnotationColourGradient.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.schemes;
20
21 import jalview.datamodel.AlignmentAnnotation;
22 import jalview.datamodel.AlignmentI;
23 import jalview.datamodel.AnnotatedCollectionI;
24 import jalview.datamodel.GraphLine;
25 import jalview.datamodel.SequenceCollectionI;
26 import jalview.datamodel.SequenceI;
27
28 import java.awt.Color;
29 import java.util.IdentityHashMap;
30 import java.util.Map;
31
32 public class AnnotationColourGradient extends FollowerColourScheme
33 {
34   public static final int NO_THRESHOLD = -1;
35
36   public static final int BELOW_THRESHOLD = 0;
37
38   public static final int ABOVE_THRESHOLD = 1;
39
40   public AlignmentAnnotation annotation;
41
42   int aboveAnnotationThreshold = -1;
43
44   public boolean thresholdIsMinMax = false;
45
46   GraphLine annotationThreshold;
47
48   float r1, g1, b1, rr, gg, bb, dr, dg, db;
49
50   private boolean predefinedColours = false;
51
52   private boolean seqAssociated = false;
53
54   IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
55   @Override
56   public ColourSchemeI applyTo(AnnotatedCollectionI sg,
57           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
58   {
59     AnnotationColourGradient acg = new AnnotationColourGradient(annotation, colourScheme, aboveAnnotationThreshold);
60     acg.thresholdIsMinMax = thresholdIsMinMax;
61     acg.annotationThreshold = (annotationThreshold==null) ? null : new GraphLine(annotationThreshold);
62     acg.r1 = r1;
63     acg.g1 = g1;
64     acg.b1 = b1;
65     acg.rr = rr;
66     acg.gg = gg;
67     acg.bb = bb;
68     acg.dr = dr;
69     acg.dg = dg;
70     acg.db = db;
71     acg.predefinedColours = predefinedColours;
72     acg.seqAssociated = seqAssociated;
73     
74     return acg;
75   }
76   /**
77    * Creates a new AnnotationColourGradient object.
78    */
79   public AnnotationColourGradient(AlignmentAnnotation annotation,
80           ColourSchemeI originalColour, int aboveThreshold)
81   {
82     if (originalColour instanceof AnnotationColourGradient)
83     {
84       colourScheme = ((AnnotationColourGradient) originalColour).colourScheme;
85     }
86     else
87     {
88       colourScheme = originalColour;
89     }
90
91     this.annotation = annotation;
92
93     aboveAnnotationThreshold = aboveThreshold;
94
95     if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null)
96     {
97       annotationThreshold = annotation.threshold;
98     }
99   }
100
101   /**
102    * Creates a new AnnotationColourGradient object.
103    */
104   public AnnotationColourGradient(AlignmentAnnotation annotation,
105           Color minColour, Color maxColour, int aboveThreshold)
106   {
107     this.annotation = annotation;
108
109     aboveAnnotationThreshold = aboveThreshold;
110
111     if (aboveThreshold != NO_THRESHOLD && annotation.threshold != null)
112     {
113       annotationThreshold = annotation.threshold;
114     }
115
116     r1 = minColour.getRed();
117     g1 = minColour.getGreen();
118     b1 = minColour.getBlue();
119
120     rr = maxColour.getRed() - r1;
121     gg = maxColour.getGreen() - g1;
122     bb = maxColour.getBlue() - b1;
123   }
124
125   @Override
126   public void alignmentChanged(AnnotatedCollectionI alignment,
127           Map<SequenceI, SequenceCollectionI> hiddenReps)
128   {
129     // TODO Auto-generated method stub
130     super.alignmentChanged(alignment, hiddenReps);
131
132     if (seqAssociated && annotation.getCalcId() != null)
133     {
134       if (seqannot != null)
135       {
136         seqannot.clear();
137       }
138       else
139       {
140         seqannot = new IdentityHashMap<SequenceI, AlignmentAnnotation>();
141       }
142       // resolve the context containing all the annotation for the sequence
143       AnnotatedCollectionI alcontext = alignment instanceof AlignmentI ? alignment : alignment.getContext();
144       for (AlignmentAnnotation alan : alcontext.findAnnotation(annotation
145               .getCalcId()))
146       {
147         if (alan.sequenceRef != null
148                 && (alan.label != null && annotation != null && alan.label
149                         .equals(annotation.label)))
150         {
151           seqannot.put(alan.sequenceRef, alan);
152         }
153       }
154     }
155   }
156
157   public String getAnnotation()
158   {
159     return annotation.label;
160   }
161
162   public int getAboveThreshold()
163   {
164     return aboveAnnotationThreshold;
165   }
166
167   public float getAnnotationThreshold()
168   {
169     if (annotationThreshold == null)
170     {
171       return 0;
172     }
173     else
174     {
175       return annotationThreshold.value;
176     }
177   }
178
179   public Color getMinColour()
180   {
181     return new Color((int) r1, (int) g1, (int) b1);
182   }
183
184   public Color getMaxColour()
185   {
186     return new Color((int) (r1 + rr), (int) (g1 + gg), (int) (b1 + bb));
187   }
188
189   /**
190    * DOCUMENT ME!
191    * 
192    * @param n
193    *          DOCUMENT ME!
194    * 
195    * @return DOCUMENT ME!
196    */
197   public Color findColour(char c)
198   {
199     return Color.red;
200   }
201
202   /**
203    * DOCUMENT ME!
204    * 
205    * @param n
206    *          DOCUMENT ME!
207    * @param j
208    *          DOCUMENT ME!
209    * 
210    * @return DOCUMENT ME!
211    */
212   @Override
213   public Color findColour(char c, int j, SequenceI seq)
214   {
215     Color currentColour = Color.white;
216     AlignmentAnnotation annotation = (seqAssociated ? seqannot.get(seq)
217             : this.annotation);
218     if (annotation == null)
219     {
220       return currentColour;
221     }
222     if ((threshold == 0) || aboveThreshold(c, j))
223     {
224       if (annotation.annotations!=null && j < annotation.annotations.length
225               && annotation.annotations[j] != null
226               && !jalview.util.Comparison.isGap(c))
227       {
228
229         if (predefinedColours)
230         {
231           if (annotation.annotations[j].colour != null)
232             return annotation.annotations[j].colour;
233           else
234             return currentColour;
235         }
236
237         if (aboveAnnotationThreshold == NO_THRESHOLD
238                 || (annotationThreshold != null
239                         && aboveAnnotationThreshold == ABOVE_THRESHOLD && annotation.annotations[j].value >= annotationThreshold.value)
240                 || (annotationThreshold != null
241                         && aboveAnnotationThreshold == BELOW_THRESHOLD && annotation.annotations[j].value <= annotationThreshold.value))
242         {
243
244           float range = 1f;
245           if (thresholdIsMinMax
246                   && annotation.threshold != null
247                   && aboveAnnotationThreshold == ABOVE_THRESHOLD
248                   && annotation.annotations[j].value >= annotation.threshold.value)
249           {
250             range = (annotation.annotations[j].value - annotation.threshold.value)
251                     / (annotation.graphMax - annotation.threshold.value);
252           }
253           else if (thresholdIsMinMax && annotation.threshold != null
254                   && aboveAnnotationThreshold == BELOW_THRESHOLD
255                   && annotation.annotations[j].value >= annotation.graphMin)
256           {
257             range = (annotation.annotations[j].value - annotation.graphMin)
258                     / (annotation.threshold.value - annotation.graphMin);
259           }
260           else
261           {
262             range = (annotation.annotations[j].value - annotation.graphMin)
263                     / (annotation.graphMax - annotation.graphMin);
264           }
265
266           if (colourScheme != null)
267           {
268             currentColour = colourScheme.findColour(c, j, seq);
269           }
270           else 
271           {
272             dr = rr * range + r1;
273             dg = gg * range + g1;
274             db = bb * range + b1;
275
276             currentColour = new Color((int) dr, (int) dg, (int) db);
277           }
278         }
279       }
280     }
281
282     if (conservationColouring)
283     {
284       currentColour = applyConservation(currentColour, j);
285     }
286
287     return currentColour;
288   }
289
290   public boolean isPredefinedColours()
291   {
292     return predefinedColours;
293   }
294
295   public void setPredefinedColours(boolean predefinedColours)
296   {
297     this.predefinedColours = predefinedColours;
298   }
299
300   public boolean isSeqAssociated()
301   {
302     return seqAssociated;
303   }
304
305   public void setSeqAssociated(boolean sassoc)
306   {
307     seqAssociated = sassoc;
308   }
309 }