JAL-2629 add file that should have been in previous commit
[jalview.git] / src / jalview / schemes / HMMMatchScoreColourScheme.java
1 package jalview.schemes;
2
3 import jalview.api.AlignViewportI;
4 import jalview.datamodel.AnnotatedCollectionI;
5 import jalview.datamodel.HiddenMarkovModel;
6 import jalview.datamodel.SequenceI;
7 import jalview.util.ColorUtils;
8 import jalview.util.Comparison;
9
10 import java.awt.Color;
11 import java.io.BufferedReader;
12 import java.io.FileNotFoundException;
13 import java.io.FileReader;
14 import java.io.IOException;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19
20 public class HMMMatchScoreColourScheme extends ResidueColourScheme
21 {
22   
23   private Map<Character, Map<String, Double>> probabilities;
24
25   public class MatchProbReader
26   {
27     private BufferedReader reader;
28     
29     MatchProbReader() throws FileNotFoundException
30     {
31       reader = new BufferedReader(
32               new FileReader("resources/ProbabilityOfMatch"));
33     }
34     
35     public Map<Character, Map<String, Double>>  getProbabilities() throws IOException
36     {
37       Map<Character, Map<String, Double>> probabilities = new HashMap<>();
38       
39       String[] alphabet = reader.readLine().split("\\,");
40       for (int i = 1; i < alphabet.length - 1; i++)
41       {
42         probabilities.put(alphabet[i].replaceAll("\\ ", "").charAt(0),
43                 new HashMap<>());
44       }
45       
46       String line = reader.readLine();
47       while(line != null)
48       {
49         String[] contents = line.split("\\,");
50         
51         for(int i = 1; i < contents.length; i++)
52         {
53           probabilities.get(alphabet[i].replaceAll("\\ ", "").charAt(0))
54                   .put(contents[0], Double
55                           .valueOf(contents[i].replaceAll("\\ ", "")));
56         }
57         line = reader.readLine();
58
59       }
60       reader.close();
61       return probabilities;
62     }
63     
64     
65   }
66
67   private static final Color INSERTION_COLOUR = Color.white;
68
69   /*
70    * the aligned HMM consensus sequence to use as reference for colouring
71    */
72   private SequenceI hmmSeq;
73
74   private HiddenMarkovModel hmm;
75
76   private Map<Character, Float> frequencies;
77
78   /**
79    * Constructor given a list of Hidden Markov Model consensus sequences. The
80    * first sequence provides the HMM profile from which we can read the emission
81    * probabilities that determine the colour.
82    * 
83    * @param hmmSeqs
84    * @throws IOException
85    */
86   public HMMMatchScoreColourScheme(List<SequenceI> hmmSeqs)
87   {
88     hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0);
89     hmm = hmmSeq == null ? null : hmmSeq.getHMM();
90
91     try
92     {
93       MatchProbReader probabilityReader = new MatchProbReader();
94       probabilities = probabilityReader.getProbabilities();
95     } catch (IOException e)
96     {
97       System.out.println(e.getStackTrace());
98     }
99   }
100
101   /**
102    * Default constructor (required by ColourSchemes.loadColourSchemes)
103    */
104   public HMMMatchScoreColourScheme()
105   {
106   }
107
108   @Override
109   public Color findColour(char symbol, int column, SequenceI seq,
110           String consensusResidue, float pid)
111   {
112     return findColour(symbol, column);
113   }
114
115   // TODO change
116   /**
117    * Returns the colour at a particular symbol at a column in the alignment:
118    * <ul>
119    * <li>white for a gap</li>
120    * <li>red for an insertion</li>
121    * <li>orange for negative information content</li>
122    * <li>white to blue for increasing information content</li>
123    * </ul>
124    * 
125    * @param symbol
126    * @param column
127    * @return
128    */
129   private Color findColour(char symbol, int column)
130   {
131     if (getHmm() == null || Comparison.isGap(symbol))
132     {
133       return Color.white;
134     }
135     if (Comparison.isGap(hmmSeq.getCharAt(column)))
136     {
137       return INSERTION_COLOUR;
138     }
139     if (Character.isLowerCase(symbol))
140     {
141       symbol = Character.toUpperCase(symbol);
142     }
143
144     double llr = Math
145             .log(getHmm().getMatchEmissionProbability(column, symbol)
146                     / hmm.getBackgroundFrequencies().get(symbol));
147
148     double prob = probabilities.get(symbol).get(format(llr));
149
150     Color colour = Color.ORANGE;
151     if (prob >= 0.5)
152     {
153
154       colour = ColorUtils.getGraduatedColour((float) prob, 0.5f,
155               Color.WHITE, 1f,
156               Color.blue);
157     }
158     else
159     {
160       colour = ColorUtils.getGraduatedColour((float) prob, 0f, Color.red,
161               0.5f, Color.WHITE);
162     }
163
164     return colour;
165   }
166
167   public static String format(Double d)
168   {
169     String formatted = String.format("%.1f", d);
170     if (Double.valueOf(formatted) == 0)
171     {
172       formatted = "0";
173     }
174     return formatted;
175   }
176
177   /**
178    * Answers the maximum possible value of information score (log ratio), for use
179    * in scaling a graduated colour range
180    * 
181    * @return
182    */
183   protected float getMaxInformationScore()
184   {
185     return 0f;
186   }
187
188   /**
189    * Answers a new colour scheme instance based on the HMM of the first sequence
190    * in ac that has an HMM
191    */
192   @Override
193   public ColourSchemeI getInstance(AlignViewportI viewport,
194           AnnotatedCollectionI ac)
195   {
196     return newInstance(ac);
197   }
198
199   /**
200    * Constructor given a sequence collection
201    * 
202    * @param ac
203    */
204   public HMMMatchScoreColourScheme(AnnotatedCollectionI ac)
205   {
206     this(ac.getHmmSequences());
207   }
208
209   /**
210    * Answers a new instance of the colour scheme for the given HMM
211    * 
212    * @param ac
213    * @return
214    */
215   protected HMMMatchScoreColourScheme newInstance(AnnotatedCollectionI ac)
216   {
217     return new HMMMatchScoreColourScheme(ac);
218   }
219
220   @Override
221   public boolean isSimple()
222   {
223     return false;
224   }
225
226   /**
227    * Answers true if the sequence collection has an HMM consensus sequence, else
228    * false
229    */
230   @Override
231   public boolean isApplicableTo(AnnotatedCollectionI ac)
232   {
233     return !ac.getHmmSequences().isEmpty();
234   }
235
236   protected Map<Character, Float> getFrequencies()
237   {
238     return frequencies;
239   }
240
241   protected void setFrequencies(Map<Character, Float> frequencies)
242   {
243     this.frequencies = frequencies;
244   }
245
246   protected HiddenMarkovModel getHmm()
247   {
248     return hmm;
249   }
250
251   protected SequenceI getHmmSequence()
252   {
253     return hmmSeq;
254   }
255
256   @Override
257   public String getSchemeName()
258   {
259     return JalviewColourScheme.HMMMatchScore.toString();
260   }
261
262   
263 }
264
265