JAL-2717 JAL-2668 fixes to HMMER colour scheme display names, enabled state, test...
[jalview.git] / src / jalview / schemes / HMMERColourScheme.java
index 09e3293..2ba0898 100644 (file)
@@ -11,51 +11,78 @@ import java.awt.Color;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * A colour scheme based on a selected Hidden Markov Model. The colour is
+ * <ul>
+ * <li>white for a gap</li>
+ * <li>red for an insertion</li>
+ * <li>orange for negative information content</li>
+ * <li>white to blue for increasing information content</li>
+ * </ul>
+ * where information content is the log ratio
+ * 
+ * <pre>
+ *   log(profile match emission probability / residue background probability>
+ * </pre>
+ * 
+ * using global ('Uniprot') background frequencies for residues.
+ * 
+ * @author tzvanaalten
+ *
+ */
 public class HMMERColourScheme extends ResidueColourScheme
 {
+  /*
+   * The highest possible log ratio is when match emission probability in
+   * the HMM model is 1, and background (for W) is 0.0109 giving
+   * log(1/0.0109) = log(91.743) = 4.519
+   */
+  private static final float MAX_LOG_RATIO = 4.519f;
 
-  AnnotatedCollectionI alignment;
+  private static final Color REDDISH = new Color(230, 0, 0);
 
   HiddenMarkovModel hmm;
-  
-  boolean peptideSpecific;
-
-  boolean nucleotideSpecific;
 
+  /**
+   * Constructor given a Hidden Markov Model
+   * 
+   * @param markov
+   */
   public HMMERColourScheme(HiddenMarkovModel markov)
   {
     hmm = markov;
   }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
   public HMMERColourScheme()
   {
-
   }
 
-
   @Override
   public Color findColour(char symbol, int position, SequenceI seq,
           String consensusResidue, float pid)
   {
-    if (hmm ==null)
-    {
-      return Color.white;
-    }
     return findColour(symbol, position);
   }
 
   /**
-   * Returns the colour at a particular symbol at a column in the alignment.
+   * Returns the colour at a particular symbol at a column in the alignment:
+   * <ul>
+   * <li>white for a gap</li>
+   * <li>red for an insertion</li>
+   * <li>orange for negative information content</li>
+   * <li>white to blue for increasing information content</li>
+   * </ul>
    * 
    * @param symbol
-   * @param position
-   * @return Red for an insertion, white for a gap, orange for a negative
-   *         information content, white to blue for increasing information
-   *         content.
+   * @param column
+   * @return
    */
-  private Color findColour(char symbol, int position)
+  private Color findColour(char symbol, int column)
   {
-
-    if (Comparison.isGap(symbol))
+    if (hmm == null || Comparison.isGap(symbol))
     {
       return Color.white;
     }
@@ -63,99 +90,81 @@ public class HMMERColourScheme extends ResidueColourScheme
     {
       symbol = Character.toUpperCase(symbol);
     }
-    Double prob;
-    prob = hmm.getMatchEmissionProbability(position, symbol);
-    double freq = 0;
+
+    double prob = hmm.getMatchEmissionProbability(column, symbol);
+    Float freq = 0f;
     String alpha = hmm.getAlphabetType();
-    if (!ResidueProperties.backgroundFrequencies.get(alpha).containsKey(symbol))
+    if (!ResidueProperties.backgroundFrequencies.get(alpha)
+            .containsKey(symbol))
     {
-      return Color.white;
+      return Color.WHITE;
     }
     else
     {
       freq = ResidueProperties.backgroundFrequencies.get(alpha).get(symbol);
     }
-    if (prob == 0)
+    if (prob == 0D)
     {
-      return new Color(230, 0, 0);
+      return REDDISH;
     }
-    Double value = Math.log(prob / freq);
+    double value = Math.log(prob / freq.floatValue());
     Color colour = null;
     if (value > 0)
     {
-
-      colour = ColorUtils.getGraduatedColour(value.floatValue(), 0,
-              Color.WHITE, 4.52f, Color.blue);
+      colour = ColorUtils.getGraduatedColour((float) value, 0,
+              Color.WHITE, MAX_LOG_RATIO, Color.blue);
     }
     else if (value < 0)
     {
       return Color.ORANGE;
-
     }
     return colour;
-
   }
-    
-
-
-
-
 
   @Override
   public void alignmentChanged(AnnotatedCollectionI collection,
           Map<SequenceI, SequenceCollectionI> hiddenReps)
   {
-         List<SequenceI> seqs = collection.getSequences();
-           for (SequenceI seq : seqs)
-           {
-      if (seq.isHMMConsensusSequence())
-             {
-               hmm = seq.getHMM();
-               break;
-             }
-           }
-
+    /*
+     * ? no need to do anything if alignment is adjusted
+     * since findColour() handles everything 
+     */
   }
 
-
-
+  /**
+   * Answers a new colour scheme instance based on the HMM of the first sequence
+   * in sg that has an HMM
+   */
   @Override
   public ColourSchemeI getInstance(AnnotatedCollectionI sg,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
-         HiddenMarkovModel markov = null;
-           List<SequenceI> seqs = sg.getSequences();
-           for (SequenceI seq : seqs)
-           {
-      if (seq.isHMMConsensusSequence())
-             {
-               markov = seq.getHMM();
-               break;
-             }
-           }
-           HMMERColourScheme colour = new HMMERColourScheme(markov);
-           return colour;
-
+    HiddenMarkovModel model = null;
+    List<SequenceI> seqs = sg.getHMMConsensusSequences();
+    if (!seqs.isEmpty())
+    {
+      model = seqs.get(0).getHMM();
+    }
+    HMMERColourScheme colour = new HMMERColourScheme(model);
+    return colour;
   }
 
   @Override
-  public boolean isApplicableTo(AnnotatedCollectionI ac)
+  public String getSchemeName()
   {
-      return true;
-
+    return JalviewColourScheme.HMMERU.toString();
   }
 
   @Override
-  public String getSchemeName()
+  public boolean isSimple()
   {
-
-    return JalviewColourScheme.HMMERU.name();
+    return false;
   }
 
   @Override
-  public boolean isSimple()
+  public boolean isApplicableTo(AnnotatedCollectionI ac)
   {
-    return false;
+    return !ac.getHMMConsensusSequences().isEmpty();
   }
 
 }