JAL-629 Move more stdout messages to stderr when outputting file to stdout
[jalview.git] / test / jalview / renderer / ResidueShaderTest.java
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.renderer;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertTrue;
26
27 import jalview.analysis.Conservation;
28 import jalview.datamodel.Profile;
29 import jalview.datamodel.ProfileI;
30 import jalview.datamodel.Profiles;
31 import jalview.datamodel.ProfilesI;
32 import jalview.datamodel.ResidueCount;
33 import jalview.datamodel.Sequence;
34 import jalview.datamodel.SequenceI;
35 import jalview.schemes.ColourSchemeI;
36 import jalview.schemes.PIDColourScheme;
37 import jalview.schemes.ResidueProperties;
38 import jalview.schemes.UserColourScheme;
39 import jalview.schemes.ZappoColourScheme;
40
41 import java.awt.Color;
42 import java.util.Collections;
43
44 import org.testng.annotations.Test;
45
46 public class ResidueShaderTest
47 {
48
49   @Test(groups = "Functional")
50   public void testAboveThreshold()
51   {
52     /*
53      * make up profiles for this alignment:
54      * AR-Q
55      * AR--
56      * SR-T
57      * SR-T
58      */
59     ProfileI[] profiles = new ProfileI[4];
60     profiles[0] = new Profile(4, 0, 2, "AS");
61     profiles[1] = new Profile(4, 0, 4, "R");
62     profiles[2] = new Profile(4, 4, 0, "");
63     profiles[3] = new Profile(4, 1, 2, "T");
64     ResidueShader ccs = new ResidueShader(new PIDColourScheme());
65     ccs.setConsensus(new Profiles(profiles));
66
67     /*
68      * no threshold
69      */
70     ccs.setThreshold(0, true);
71     assertTrue(ccs.aboveThreshold('a', 0));
72     assertTrue(ccs.aboveThreshold('S', 0));
73     assertTrue(ccs.aboveThreshold('W', 0));
74     assertTrue(ccs.aboveThreshold('R', 1));
75     assertTrue(ccs.aboveThreshold('W', 2));
76     assertTrue(ccs.aboveThreshold('t', 3));
77     assertTrue(ccs.aboveThreshold('Q', 3));
78
79     /*
80      * with threshold, include gaps
81      */
82     ccs.setThreshold(60, false);
83     assertFalse(ccs.aboveThreshold('a', 0));
84     assertFalse(ccs.aboveThreshold('S', 0));
85     assertTrue(ccs.aboveThreshold('R', 1));
86     assertFalse(ccs.aboveThreshold('W', 2));
87     assertFalse(ccs.aboveThreshold('t', 3)); // 50% < 60%
88
89     /*
90      * with threshold, ignore gaps
91      */
92     ccs.setThreshold(60, true);
93     assertFalse(ccs.aboveThreshold('a', 0));
94     assertFalse(ccs.aboveThreshold('S', 0));
95     assertTrue(ccs.aboveThreshold('R', 1));
96     assertFalse(ccs.aboveThreshold('W', 2));
97     assertTrue(ccs.aboveThreshold('t', 3)); // 67% > 60%
98   }
99
100   /**
101    * Test colour bleaching based on conservation score and conservation slider.
102    * Scores of 10 or 11 should leave colours unchanged. Gap is always white.
103    */
104   @Test(groups = "Functional")
105   public void testApplyConservation()
106   {
107     ResidueShader ccs = new ResidueShader(new PIDColourScheme());
108
109     // no conservation present - no fading
110     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 12));
111
112     /*
113      * stub Conservation to return a given consensus string
114      */
115     final String consSequence = "0123456789+*-";
116     Conservation cons = new Conservation(null,
117             Collections.<SequenceI> emptyList(), 0, 0)
118     {
119       @Override
120       public SequenceI getConsSequence()
121       {
122         return new Sequence("seq", consSequence);
123       }
124     };
125     ccs.setConservation(cons);
126
127     // column out of range:
128     assertEquals(Color.RED,
129             ccs.applyConservation(Color.RED, consSequence.length()));
130
131     /*
132      * with 100% threshold, 'fade factor' is 
133      * (11-score)/10 * 100/20 = (11-score)/2
134      * which is >= 1 for all scores i.e. all fade to white except +, *
135      */
136     ccs.setConservationInc(100);
137     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 0));
138     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 1));
139     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 2));
140     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 3));
141     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 4));
142     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 5));
143     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 6));
144     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 7));
145     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 8));
146     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 9));
147     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 10));
148     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 11));
149     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 12));
150
151     /*
152      * with 0% threshold, there should be no fading
153      */
154     ccs.setConservationInc(0);
155     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 0));
156     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 1));
157     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 2));
158     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 3));
159     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 4));
160     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 5));
161     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 6));
162     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 7));
163     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 8));
164     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 9));
165     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 10));
166     assertEquals(Color.RED, ccs.applyConservation(Color.RED, 11));
167     assertEquals(Color.WHITE, ccs.applyConservation(Color.RED, 12)); // gap
168
169     /*
170      * with 40% threshold, 'fade factor' is 
171      * (11-score)/10 * 40/20 = (11-score)/5
172      * which is {>1, >1, >1, >1, >1, >1, 1, 0.8, 0.6, 0.4} for score 0-9
173      * e.g. score 7 colour fades 80% of the way to white (255, 255, 255)
174      */
175     ccs.setConservationInc(40);
176     Color colour = new Color(155, 105, 55);
177     assertEquals(Color.WHITE, ccs.applyConservation(colour, 0));
178     assertEquals(Color.WHITE, ccs.applyConservation(colour, 1));
179     assertEquals(Color.WHITE, ccs.applyConservation(colour, 2));
180     assertEquals(Color.WHITE, ccs.applyConservation(colour, 3));
181     assertEquals(Color.WHITE, ccs.applyConservation(colour, 4));
182     assertEquals(Color.WHITE, ccs.applyConservation(colour, 5));
183     assertEquals(Color.WHITE, ccs.applyConservation(colour, 6));
184     assertEquals(new Color(235, 225, 215),
185             ccs.applyConservation(colour, 7));
186     assertEquals(new Color(215, 195, 175),
187             ccs.applyConservation(colour, 8));
188     assertEquals(new Color(195, 165, 135),
189             ccs.applyConservation(colour, 9));
190     assertEquals(colour, ccs.applyConservation(colour, 10));
191     assertEquals(colour, ccs.applyConservation(colour, 11));
192     assertEquals(Color.WHITE, ccs.applyConservation(colour, 12));
193   }
194
195   @Test(groups = "Functional")
196   public void testFindColour_gapColour()
197   {
198     /*
199      * normally, a gap is coloured white
200      */
201     ResidueShader rs = new ResidueShader(new ZappoColourScheme());
202     assertEquals(Color.white, rs.findColour(' ', 7, null));
203
204     /*
205      * a User Colour Scheme may specify a bespoke gap colour
206      */
207     Color[] colours = new Color[ResidueProperties.maxProteinIndex + 1];
208     colours[5] = Color.blue; // Q colour
209     colours[23] = Color.red; // gap colour
210     ColourSchemeI cs = new UserColourScheme(colours);
211     rs = new ResidueShader(cs);
212
213     assertEquals(Color.red, rs.findColour(' ', 7, null));
214     assertEquals(Color.blue, rs.findColour('Q', 7, null));
215
216     /*
217      * stub Conservation to return a given consensus string
218      */
219     final String consSequence = "0123456789+*-";
220     Conservation cons = new Conservation(null,
221             Collections.<SequenceI> emptyList(), 0, 0)
222     {
223       @Override
224       public SequenceI getConsSequence()
225       {
226         return new Sequence("seq", consSequence);
227       }
228     };
229     rs.setConservation(cons);
230
231     /*
232      * with 0% threshold, there should be no fading
233      */
234     rs.setConservationInc(0);
235     assertEquals(Color.red, rs.findColour(' ', 7, null));
236     assertEquals(Color.blue, rs.findColour('Q', 7, null));
237
238     /*
239      * with 40% threshold, 'fade factor' is 
240      * (11-score)/10 * 40/20 = (11-score)/5
241      * so position 7, score 7 fades 80% of the way to white (255, 255, 255)
242      */
243     rs.setConservationInc(40);
244
245     /*
246      * gap colour is unchanged for Conservation
247      */
248     assertEquals(Color.red, rs.findColour(' ', 7, null));
249     assertEquals(Color.red, rs.findColour('-', 7, null));
250     assertEquals(Color.red, rs.findColour('.', 7, null));
251
252     /*
253      * residue colour is faded 80% of the way from
254      * blue(0, 0, 255) to white(255, 255, 255)
255      * making (204, 204, 255)
256      */
257     assertEquals(new Color(204, 204, 255), rs.findColour('Q', 7, null));
258
259     /*
260      * turn off By Conservation, apply Above Identity Threshold
261      * providing a stub Consensus that has modal residue "Q" with pid 60%
262      */
263     rs.setConservationApplied(false);
264     ProfilesI consensus = getStubConsensus("Q", 60f);
265     rs.setConsensus(consensus);
266
267     // with consensus pid (60) above threshold (50), colours are unchanged
268     rs.setThreshold(50, false);
269     assertEquals(Color.blue, rs.findColour('Q', 7, null));
270     assertEquals(Color.red, rs.findColour('-', 7, null));
271
272     // with consensus pid (60) below threshold (70),
273     // residue colour becomes white, gap colour is unchanged
274     rs.setThreshold(70, false);
275     assertEquals(Color.white, rs.findColour('Q', 7, null));
276     assertEquals(Color.red, rs.findColour('-', 7, null));
277   }
278
279   /**
280    * @param modalResidue
281    * @param pid
282    * @return
283    */
284   protected ProfilesI getStubConsensus(final String modalResidue,
285           final float pid)
286   {
287     ProfilesI consensus = new ProfilesI()
288     {
289
290       @Override
291       public ProfileI get(int i)
292       {
293         return new ProfileI()
294         {
295           @Override
296           public void setCounts(ResidueCount residueCounts)
297           {
298           }
299
300           @Override
301           public float getPercentageIdentity(boolean ignoreGaps)
302           {
303             return pid;
304           }
305
306           @Override
307           public ResidueCount getCounts()
308           {
309             return null;
310           }
311
312           @Override
313           public int getHeight()
314           {
315             return 0;
316           }
317
318           @Override
319           public int getGapped()
320           {
321             return 0;
322           }
323
324           @Override
325           public int getMaxCount()
326           {
327             return 0;
328           }
329
330           @Override
331           public String getModalResidue()
332           {
333             return modalResidue;
334           }
335
336           @Override
337           public int getNonGapped()
338           {
339             return 0;
340           }
341         };
342       }
343
344       @Override
345       public int getStartColumn()
346       {
347         return 0;
348       }
349
350       @Override
351       public int getEndColumn()
352       {
353         return 0;
354       }
355
356     };
357     return consensus;
358   }
359 }