ee6c87334a52298c4d6c799874087ac2e1324430
[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  * A colour scheme based on a selected Hidden Markov Model. The colour is
15  * <ul>
16  * <li>white for a gap</li>
17  * <li>red for an insertion</li>
18  * <li>orange for negative information content</li>
19  * <li>white to blue for increasing information content</li>
20  * </ul>
21  * where information content is the log ratio
22  * 
23  * <pre>
24  *   log(profile match emission probability / residue background probability>
25  * </pre>
26  * 
27  * using global ('Uniprot') background frequencies for residues.
28  * 
29  * @author tzvanaalten
30  *
31  */
32 public class HMMERColourScheme extends ResidueColourScheme
33 {
34   /*
35    * The highest possible log ratio is when match emission probability in
36    * the HMM model is 1, and background (for W) is 0.0109 giving
37    * log(1/0.0109) = log(91.743) = 4.519
38    */
39   private static final float MAX_LOG_RATIO = 4.519f;
40
41   private static final Color REDDISH = new Color(230, 0, 0);
42
43   HiddenMarkovModel hmm;
44
45   /**
46    * Constructor given a Hidden Markov Model
47    * 
48    * @param markov
49    */
50   public HMMERColourScheme(HiddenMarkovModel markov)
51   {
52     hmm = markov;
53   }
54
55   /**
56    * Default constructor (required by ColourSchemes.loadColourSchemes)
57    */
58   public HMMERColourScheme()
59   {
60   }
61
62   @Override
63   public Color findColour(char symbol, int position, SequenceI seq,
64           String consensusResidue, float pid)
65   {
66     return findColour(symbol, position);
67   }
68
69   /**
70    * Returns the colour at a particular symbol at a column in the alignment:
71    * <ul>
72    * <li>white for a gap</li>
73    * <li>red for an insertion</li>
74    * <li>orange for negative information content</li>
75    * <li>white to blue for increasing information content</li>
76    * </ul>
77    * 
78    * @param symbol
79    * @param column
80    * @return
81    */
82   private Color findColour(char symbol, int column)
83   {
84     if (hmm == null || Comparison.isGap(symbol))
85     {
86       return Color.white;
87     }
88     if (Character.isLowerCase(symbol))
89     {
90       symbol = Character.toUpperCase(symbol);
91     }
92
93     double prob = hmm.getMatchEmissionProbability(column, symbol);
94     Float freq = 0f;
95     String alpha = hmm.getAlphabetType();
96     if (!ResidueProperties.backgroundFrequencies.get(alpha)
97             .containsKey(symbol))
98     {
99       return Color.WHITE;
100     }
101     else
102     {
103       freq = ResidueProperties.backgroundFrequencies.get(alpha).get(symbol);
104     }
105     if (prob == 0D)
106     {
107       return REDDISH;
108     }
109     double value = Math.log(prob / freq.floatValue());
110     Color colour = null;
111     if (value > 0)
112     {
113       colour = ColorUtils.getGraduatedColour((float) value, 0,
114               Color.WHITE, MAX_LOG_RATIO, Color.blue);
115     }
116     else if (value < 0)
117     {
118       return Color.ORANGE;
119     }
120     return colour;
121   }
122
123   @Override
124   public void alignmentChanged(AnnotatedCollectionI collection,
125           Map<SequenceI, SequenceCollectionI> hiddenReps)
126   {
127     /*
128      * ? no need to do anything if alignment is adjusted
129      * since findColour() handles everything 
130      */
131   }
132
133   /**
134    * Answers a new colour scheme instance based on the HMM of the first sequence
135    * in sg that has an HMM
136    */
137   @Override
138   public ColourSchemeI getInstance(AnnotatedCollectionI sg,
139           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
140   {
141     SequenceI hmmSeq = sg.getHmmConsensus();
142     HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM();
143
144     HMMERColourScheme colour = new HMMERColourScheme(model);
145     return colour;
146   }
147
148   @Override
149   public String getSchemeName()
150   {
151     return JalviewColourScheme.HMMERU.toString();
152   }
153
154   @Override
155   public boolean isSimple()
156   {
157     return false;
158   }
159
160   /**
161    * Answers true if the sequence collection has an HMM consensus sequence, else
162    * false
163    */
164   @Override
165   public boolean isApplicableTo(AnnotatedCollectionI ac)
166   {
167     return ac.getHmmConsensus() != null;
168   }
169
170 }