Merge branch 'develop' into trialMerge
[jalview.git] / src / jalview / schemes / HMMERColourScheme.java
index 113afd1..ee6c873 100644 (file)
@@ -8,160 +8,163 @@ import jalview.util.ColorUtils;
 import jalview.util.Comparison;
 
 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);
   }
 
-  public Color findColour(char symbol, int position)
+  /**
+   * 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 column
+   * @return
+   */
+  private Color findColour(char symbol, int column)
   {
-
-    if (Comparison.isGap(symbol))
+    if (hmm == null || Comparison.isGap(symbol))
     {
       return Color.white;
     }
     if (Character.isLowerCase(symbol))
     {
-      return new Color(230, 0, 0);
-    }
-    Double prob;
-    prob = hmm.getMatchEmissionProbability(position, symbol);
-    double freq = 0;
-    if ("amino".equals(hmm.getAlphabetType()))
-    {
-      if (!ResidueProperties.aminoBackgroundFrequencies.containsKey(symbol))
-      {
-        return Color.white;
-      }
-      freq = ResidueProperties.aminoBackgroundFrequencies.get(symbol);
+      symbol = Character.toUpperCase(symbol);
     }
-    else if ("DNA".equals(hmm.getAlphabetType()))
+
+    double prob = hmm.getMatchEmissionProbability(column, symbol);
+    Float freq = 0f;
+    String alpha = hmm.getAlphabetType();
+    if (!ResidueProperties.backgroundFrequencies.get(alpha)
+            .containsKey(symbol))
     {
-      if (!ResidueProperties.dnaBackgroundFrequencies.containsKey(symbol))
-      {
-        return Color.white;
-      }
-      freq = ResidueProperties.dnaBackgroundFrequencies.get(symbol);
+      return Color.WHITE;
     }
-    else if ("RNA".equals(hmm.getAlphabetType()))
+    else
     {
-      if (!ResidueProperties.rnaBackgroundFrequencies.containsKey(symbol))
-      {
-        return Color.white;
-      }
-      freq = ResidueProperties.rnaBackgroundFrequencies.get(symbol);
+      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.getHMM() != null)
-             {
-               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.getHMM() != null)
-             {
-               markov = seq.getHMM();
-               break;
-             }
-           }
-           HMMERColourScheme colour = new HMMERColourScheme(markov);
-           return colour;
+    SequenceI hmmSeq = sg.getHmmConsensus();
+    HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.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.HMMER.name();
+    return false;
   }
 
+  /**
+   * Answers true if the sequence collection has an HMM consensus sequence, else
+   * false
+   */
   @Override
-  public boolean isSimple()
+  public boolean isApplicableTo(AnnotatedCollectionI ac)
   {
-    // TODO Auto-generated method stub
-    return false;
+    return ac.getHmmConsensus() != null;
   }
 
 }