Clover icon

Coverage Report

  1. Project Clover database Tue Oct 29 2024 21:36:55 GMT
  2. Package jalview.renderer

File ResidueShader.java

 

Coverage histogram

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

Code metrics

44
74
22
1
465
224
50
0.68
3.36
22
2.27

Classes

Class Line # Actions
ResidueShader 50 74 50
0.8071428580.7%
 

Contributing tests

This file is covered by 266 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.renderer;
22   
23    import jalview.analysis.Conservation;
24    import jalview.api.ViewStyleI;
25    import jalview.datamodel.AnnotatedCollectionI;
26    import jalview.datamodel.ProfileI;
27    import jalview.datamodel.ProfilesI;
28    import jalview.datamodel.SequenceCollectionI;
29    import jalview.datamodel.SequenceI;
30    import jalview.schemes.ColourSchemeI;
31    import jalview.util.ColorUtils;
32    import jalview.util.Comparison;
33   
34    import java.awt.Color;
35    import java.util.Map;
36   
37    /**
38    * A class that computes the colouring of an alignment (or subgroup). Currently
39    * the factors that may influence residue colouring are
40    * <ul>
41    * <li>the colour scheme that provides a colour for each aligned residue</li>
42    * <li>any threshold for colour, based on percentage identity with
43    * consensus</li>
44    * <li>any graduation based on conservation of physico-chemical properties</li>
45    * </ul>
46    *
47    * @author gmcarstairs
48    *
49    */
 
50    public class ResidueShader implements ResidueShaderI
51    {
52    private static final int INITIAL_CONSERVATION = 30;
53   
54    /*
55    * the colour scheme that gives the colour of each residue
56    * before applying any conservation or PID shading
57    */
58    private ColourSchemeI colourScheme;
59   
60    /*
61    * the consensus data for each column
62    */
63    private ProfilesI consensus;
64   
65    /*
66    * the consensus data for each column
67    */
68    private ProfilesI ssConsensus;
69   
 
70  0 toggle public ProfilesI getSsConsensus()
71    {
72  0 return ssConsensus;
73    }
74   
 
75  974 toggle public void setSsConsensus(ProfilesI ssConsensus)
76    {
77  974 this.ssConsensus = ssConsensus;
78    }
79   
80    /*
81    * if true, apply shading of colour by conservation
82    */
83    private boolean conservationColouring;
84   
85    /*
86    * the physico-chemical property conservation scores for columns, with values
87    * 0-9, '+' (all properties conserved), '*' (residue fully conserved) or '-' (gap)
88    * (may be null if colour by conservation is not selected)
89    */
90    private char[] conservation;
91   
92    /*
93    * minimum percentage identity for colour to be applied;
94    * if above zero, residue must match consensus (or joint consensus)
95    * and column have >= pidThreshold identity with the residue
96    */
97    private int pidThreshold;
98   
99    /*
100    * if true, ignore gaps in percentage identity calculation
101    */
102    private boolean ignoreGaps;
103   
104    /*
105    * setting of the By Conservation slider
106    */
107    private int conservationIncrement = INITIAL_CONSERVATION;
108   
 
109  3200 toggle public ResidueShader(ColourSchemeI cs)
110    {
111  3200 colourScheme = cs;
112    }
113   
114    /**
115    * Default constructor
116    */
 
117  1485 toggle public ResidueShader()
118    {
119    }
120   
121    /**
122    * Constructor given view style settings
123    *
124    * @param viewStyle
125    */
 
126  0 toggle public ResidueShader(ViewStyleI viewStyle)
127    {
128    // TODO remove duplicated storing of conservation / pid thresholds?
129  0 this();
130  0 setConservationApplied(viewStyle.isConservationColourSelected());
131    // setThreshold(viewStyle.getThreshold());
132    }
133   
134    /**
135    * Copy constructor
136    */
 
137  103 toggle public ResidueShader(ResidueShader rs)
138    {
139  103 this.colourScheme = rs.colourScheme;
140  103 this.consensus = rs.consensus;
141  103 this.conservation = rs.conservation;
142  103 this.conservationColouring = rs.conservationColouring;
143  103 this.conservationIncrement = rs.conservationIncrement;
144  103 this.ignoreGaps = rs.ignoreGaps;
145  103 this.pidThreshold = rs.pidThreshold;
146  103 this.ssConsensus = rs.ssConsensus;
147    }
148   
149    /**
150    * @see jalview.renderer.ResidueShaderI#setConsensus(jalview.datamodel.ProfilesI)
151    */
 
152  2495 toggle @Override
153    public void setConsensus(ProfilesI cons)
154    {
155  2495 consensus = cons;
156   
157    }
158   
159    /**
160    * @see jalview.renderer.ResidueShaderI#conservationApplied()
161    */
 
162  997 toggle @Override
163    public boolean conservationApplied()
164    {
165  997 return conservationColouring;
166    }
167   
168    /**
169    * @see jalview.renderer.ResidueShaderI#setConservationApplied(boolean)
170    */
 
171  194 toggle @Override
172    public void setConservationApplied(boolean conservationApplied)
173    {
174  194 conservationColouring = conservationApplied;
175    }
176   
177    /**
178    * @see jalview.renderer.ResidueShaderI#setConservation(jalview.analysis.Conservation)
179    */
 
180  29 toggle @Override
181    public void setConservation(Conservation cons)
182    {
183  29 if (cons == null)
184    {
185  5 conservationColouring = false;
186  5 conservation = null;
187    }
188    else
189    {
190  24 conservationColouring = true;
191  24 conservation = cons.getConsSequence().getSequenceAsString()
192    .toCharArray();
193    }
194   
195    }
196   
197    /**
198    * @see jalview.renderer.ResidueShaderI#alignmentChanged(jalview.datamodel.AnnotatedCollectionI,
199    * java.util.Map)
200    */
 
201  1194 toggle @Override
202    public void alignmentChanged(AnnotatedCollectionI alignment,
203    Map<SequenceI, SequenceCollectionI> hiddenReps)
204    {
205  1194 if (colourScheme != null)
206    {
207  336 colourScheme.alignmentChanged(alignment, hiddenReps);
208    }
209    }
210   
211    /**
212    * @see jalview.renderer.ResidueShaderI#setThreshold(int, boolean)
213    */
 
214  169 toggle @Override
215    public void setThreshold(int consensusThreshold, boolean ignoreGaps)
216    {
217  169 pidThreshold = consensusThreshold;
218  169 this.ignoreGaps = ignoreGaps;
219    }
220   
221    /**
222    * @see jalview.renderer.ResidueShaderI#setConservationInc(int)
223    */
 
224  72 toggle @Override
225    public void setConservationInc(int i)
226    {
227  72 conservationIncrement = i;
228    }
229   
230    /**
231    * @see jalview.renderer.ResidueShaderI#getConservationInc()
232    */
 
233  37 toggle @Override
234    public int getConservationInc()
235    {
236  37 return conservationIncrement;
237    }
238   
239    /**
240    * @see jalview.renderer.ResidueShaderI#getThreshold()
241    */
 
242  59 toggle @Override
243    public int getThreshold()
244    {
245  59 return pidThreshold;
246    }
247   
248    /**
249    * @see jalview.renderer.ResidueShaderI#findColour(char, int,
250    * jalview.datamodel.SequenceI)
251    */
 
252  915532 toggle @Override
253    public Color findColour(char symbol, int position, SequenceI seq)
254    {
255  915569 if (colourScheme == null)
256    {
257  1 return Color.white; // Colour is 'None'
258    }
259   
260    /*
261    * get 'base' colour
262    */
263  915575 ProfileI profile = consensus == null ? null : consensus.get(position);
264  915575 String modalResidue = profile == null ? null
265    : profile.getModalResidue();
266  915571 float pid = profile == null ? 0f
267    : profile.getPercentageIdentity(ignoreGaps);
268  915574 Color colour = colourScheme.findColour(symbol, position, seq,
269    modalResidue, pid);
270   
271    /*
272    * apply PID threshold and consensus fading if in force
273    */
274  915549 if (!Comparison.isGap(symbol))
275    {
276  878322 colour = adjustColour(symbol, position, colour);
277    }
278   
279  915546 return colour;
280    }
281   
 
282  0 toggle @Override
283    public Color findSSColour(char symbol, int position, SequenceI seq)
284    {
285  0 if (colourScheme == null)
286    {
287  0 return Color.white; // Colour is 'None'
288    }
289   
290    /*
291    * get 'base' colour
292    */
293  0 ProfileI profile = ssConsensus == null ? null
294    : ssConsensus.get(position);
295  0 String modalSS = profile == null ? null : profile.getModalSS();
296  0 float pid = profile == null ? 0f
297    : profile.getSSPercentageIdentity(ignoreGaps);
298  0 Color colour = colourScheme.findColour(symbol, position, seq, modalSS,
299    pid);
300   
301    /*
302    * apply PID threshold and consensus fading if in force
303    */
304  0 if (!Comparison.isGap(symbol))
305    {
306  0 colour = adjustColour(symbol, position, colour);
307    }
308   
309  0 return colour;
310    }
311   
312    /**
313    * Adjusts colour by applying thresholding or conservation shading, if in
314    * force. That is
315    * <ul>
316    * <li>if there is a threshold set for colouring, and the residue doesn't
317    * match the consensus (or a joint consensus) residue, or the consensus score
318    * is not above the threshold, then the colour is set to white</li>
319    * <li>if conservation colouring is selected, the colour is faded by an amount
320    * depending on the conservation score for the column, and the conservation
321    * colour threshold</li>
322    * </ul>
323    *
324    * @param symbol
325    * @param column
326    * @param colour
327    * @return
328    */
 
329  878318 toggle protected Color adjustColour(char symbol, int column, Color colour)
330    {
331  878327 if (!aboveThreshold(symbol, column))
332    {
333  3622 colour = Color.white;
334    }
335   
336  878328 if (conservationColouring)
337    {
338  10455 colour = applyConservation(colour, column);
339    }
340  878331 return colour;
341    }
342   
343    /**
344    * Answers true if there is a consensus profile for the specified column, and
345    * the given residue matches the consensus (or joint consensus) residue for
346    * the column, and the percentage identity for the profile is equal to or
347    * greater than the current threshold; else answers false. The percentage
348    * calculation depends on whether or not we are ignoring gapped sequences.
349    *
350    * @param residue
351    * @param column
352    * (index into consensus profiles)
353    *
354    * @return
355    * @see #setThreshold(int, boolean)
356    */
 
357  878329 toggle protected boolean aboveThreshold(char residue, int column)
358    {
359  878346 if (pidThreshold == 0)
360    {
361  868636 return true;
362    }
363  9722 if ('a' <= residue && residue <= 'z')
364    {
365    // TO UPPERCASE !!!
366    // Faster than toUpperCase
367  4 residue -= ('a' - 'A');
368    }
369   
370  9722 if (consensus == null)
371    {
372  0 return false;
373    }
374   
375  9722 ProfileI profile = consensus.get(column);
376   
377    /*
378    * test whether this is the consensus (or joint consensus) residue
379    */
380  9722 if (profile != null
381    && profile.getModalResidue().contains(String.valueOf(residue)))
382    {
383  6178 if (profile.getPercentageIdentity(ignoreGaps) >= pidThreshold)
384    {
385  6093 return true;
386    }
387    }
388   
389  3629 return false;
390    }
391   
392    /**
393    * Applies a combination of column conservation score, and conservation
394    * percentage slider, to 'bleach' out the residue colours towards white.
395    * <p>
396    * If a column is fully conserved (identical residues, conservation score 11,
397    * shown as *), or all 10 physico-chemical properties are conserved
398    * (conservation score 10, shown as +), then the colour is left unchanged.
399    * <p>
400    * Otherwise a 'bleaching' factor is computed and applied to the colour. This
401    * is designed to fade colours for scores of 0-9 completely to white at slider
402    * positions ranging from 18% - 100% respectively.
403    *
404    * @param currentColour
405    * @param column
406    *
407    * @return bleached (or unmodified) colour
408    */
 
409  10496 toggle protected Color applyConservation(Color currentColour, int column)
410    {
411  10496 if (conservation == null || conservation.length <= column)
412    {
413  748 return currentColour;
414    }
415  9748 char conservationScore = conservation[column];
416   
417    /*
418    * if residues are fully conserved (* or 11), or all properties
419    * are conserved (+ or 10), leave colour unchanged
420    */
421  9748 if (conservationScore == '*' || conservationScore == '+'
422    || conservationScore == (char) 10
423    || conservationScore == (char) 11)
424    {
425  422 return currentColour;
426    }
427   
428  9326 if (Comparison.isGap(conservationScore))
429    {
430  2889 return Color.white;
431    }
432   
433    /*
434    * convert score 0-9 to a bleaching factor 1.1 - 0.2
435    */
436  6437 float bleachFactor = (11 - (conservationScore - '0')) / 10f;
437   
438    /*
439    * scale this up by 0-5 (percentage slider / 20)
440    * as a result, scores of: 0 1 2 3 4 5 6 7 8 9
441    * fade to white at slider value: 18 20 22 25 29 33 40 50 67 100%
442    */
443  6437 bleachFactor *= (conservationIncrement / 20f);
444   
445  6437 return ColorUtils.bleachColour(currentColour, bleachFactor);
446    }
447   
448    /**
449    * @see jalview.renderer.ResidueShaderI#getColourScheme()
450    */
 
451  1294746 toggle @Override
452    public ColourSchemeI getColourScheme()
453    {
454  1294809 return this.colourScheme;
455    }
456   
457    /**
458    * @see jalview.renderer.ResidueShaderI#setColourScheme(jalview.schemes.ColourSchemeI)
459    */
 
460  340 toggle @Override
461    public void setColourScheme(ColourSchemeI cs)
462    {
463  340 colourScheme = cs;
464    }
465    }