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