JAL-2938 update colour schemes enum for class name changes
[jalview.git] / src / jalview / schemes / HmmerColourScheme.java
1 package jalview.schemes;
2
3 import jalview.datamodel.AnnotatedCollectionI;
4 import jalview.datamodel.HiddenMarkovModel;
5 import jalview.datamodel.SequenceCollectionI;
6 import jalview.datamodel.SequenceI;
7 import jalview.util.ColorUtils;
8 import jalview.util.Comparison;
9
10 import java.awt.Color;
11 import java.util.Map;
12
13 /**
14  * Base class for colour schemes based on a selected Hidden Markov Model. The
15  * colour is
16  * <ul>
17  * <li>white for a gap</li>
18  * <li>red for an insertion</li>
19  * <li>orange for negative information content</li>
20  * <li>white to blue for increasing information content</li>
21  * </ul>
22  * where information content is the log ratio
23  * 
24  * <pre>
25  *   log(profile match emission probability / residue background probability)
26  * </pre>
27  * 
28  * Sub-class implementations use either global ('Uniprot') or local
29  * ('alignment') background frequencies.
30  * 
31  * @author tzvanaalten
32  * @author gmcarstairs
33  */
34 public abstract class HmmerColourScheme extends ResidueColourScheme
35 {
36   private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish
37
38   private HiddenMarkovModel hmm;
39
40   private Map<Character, Float> frequencies;
41
42   /**
43    * Constructor given a Hidden Markov Model
44    * 
45    * @param markov
46    */
47   public HmmerColourScheme(HiddenMarkovModel markov)
48   {
49     hmm = markov;
50   }
51
52   /**
53    * Default constructor (required by ColourSchemes.loadColourSchemes)
54    */
55   public HmmerColourScheme()
56   {
57   }
58
59   @Override
60   public Color findColour(char symbol, int position, SequenceI seq,
61           String consensusResidue, float pid)
62   {
63     return findColour(symbol, position);
64   }
65
66   /**
67    * Returns the colour at a particular symbol at a column in the alignment:
68    * <ul>
69    * <li>white for a gap</li>
70    * <li>red for an insertion</li>
71    * <li>orange for negative information content</li>
72    * <li>white to blue for increasing information content</li>
73    * </ul>
74    * 
75    * @param symbol
76    * @param column
77    * @return
78    */
79   private Color findColour(char symbol, int column)
80   {
81     if (getHmm() == null || Comparison.isGap(symbol))
82     {
83       return Color.white;
84     }
85     if (Character.isLowerCase(symbol))
86     {
87       symbol = Character.toUpperCase(symbol);
88     }
89
90     final double prob = getHmm().getMatchEmissionProbability(column,
91             symbol);
92
93     Float freq = 0f;
94
95     if (!frequencies.containsKey(symbol))
96     {
97       return Color.WHITE;
98     }
99     else
100     {
101       freq = frequencies.get(symbol);
102     }
103     if (prob == 0D)
104     {
105       return INSERTION_COLOUR;
106     }
107     double value = Math.log(prob / freq.floatValue());
108     Color colour = null;
109     if (value < 0)
110     {
111       return Color.ORANGE;
112     }
113
114     colour = ColorUtils.getGraduatedColour((float) value, 0, Color.WHITE,
115             getMaxInformationScore(), Color.blue);
116     return colour;
117   }
118
119   /**
120    * Answers the maximum possible value of information score (log ratio), for
121    * use in scaling a graduated colour range
122    * 
123    * @return
124    */
125   abstract float getMaxInformationScore();
126
127   @Override
128   public void alignmentChanged(AnnotatedCollectionI collection,
129           Map<SequenceI, SequenceCollectionI> hiddenReps)
130   {
131     /*
132      * ? no need to do anything if alignment is adjusted
133      * since findColour() handles everything 
134      */
135   }
136
137   /**
138    * Answers a new colour scheme instance based on the HMM of the first sequence
139    * in ac that has an HMM
140    */
141   @Override
142   public ColourSchemeI getInstance(AnnotatedCollectionI ac,
143           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
144   {
145     SequenceI hmmSeq = ac.getHmmConsensus();
146     HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM();
147
148     return newInstance(ac, model);
149   }
150
151   /**
152    * Answers a new instance of the colour scheme for the given HMM
153    * 
154    * @param ac
155    * @param model
156    * @return
157    */
158   protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac,
159           HiddenMarkovModel model);
160
161   @Override
162   public boolean isSimple()
163   {
164     return false;
165   }
166
167   /**
168    * Answers true if the sequence collection has an HMM consensus sequence, else
169    * false
170    */
171   @Override
172   public boolean isApplicableTo(AnnotatedCollectionI ac)
173   {
174     return ac.getHmmConsensus() != null;
175   }
176
177   protected Map<Character, Float> getFrequencies()
178   {
179     return frequencies;
180   }
181
182   protected void setFrequencies(Map<Character, Float> frequencies)
183   {
184     this.frequencies = frequencies;
185   }
186
187   protected HiddenMarkovModel getHmm()
188   {
189     return hmm;
190   }
191
192 }