JAL-2938 extracted base class for Hmmer colour schems
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 23 Mar 2018 10:28:44 +0000 (10:28 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 23 Mar 2018 10:28:44 +0000 (10:28 +0000)
src/jalview/schemes/HMMERAlignmentColourScheme.java [deleted file]
src/jalview/schemes/HmmerColourScheme.java [moved from src/jalview/schemes/HMMERColourScheme.java with 62% similarity]
src/jalview/schemes/HmmerGlobalBackground.java [new file with mode: 0644]
src/jalview/schemes/HmmerLocalBackground.java [new file with mode: 0644]
src/jalview/schemes/JalviewColourScheme.java
test/jalview/schemes/HmmerGlobalBackgroundTest.java [moved from test/jalview/schemes/HMMERColourSchemeTest.java with 95% similarity]
test/jalview/schemes/HmmerLocalBackgroundTest.java [moved from test/jalview/schemes/HMMERAlignmentColourSchemeTest.java with 95% similarity]

diff --git a/src/jalview/schemes/HMMERAlignmentColourScheme.java b/src/jalview/schemes/HMMERAlignmentColourScheme.java
deleted file mode 100644 (file)
index 79fc871..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-package jalview.schemes;
-
-import jalview.datamodel.AnnotatedCollectionI;
-import jalview.datamodel.HiddenMarkovModel;
-import jalview.datamodel.ResidueCount;
-import jalview.datamodel.SequenceCollectionI;
-import jalview.datamodel.SequenceI;
-import jalview.util.ColorUtils;
-import jalview.util.Comparison;
-
-import java.awt.Color;
-import java.util.HashMap;
-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 the alignment's background frequencies for residues.
- * 
- * @author tzvanaalten
- *
- */
-public class HMMERAlignmentColourScheme extends ResidueColourScheme
-{
-  /*
-   * the ratio, for each symbol, of its frequency to total symbol count
-   */
-  Map<Character, Double> frequency = new HashMap<>();
-
-  float logTotalCount;
-
-  HiddenMarkovModel hmm;
-
-  /**
-   * Constructor given a Hidden Markov Model
-   * 
-   * @param sg
-   * 
-   * @param markov
-   */
-  public HMMERAlignmentColourScheme(AnnotatedCollectionI sg,
-          HiddenMarkovModel markov)
-  {
-    hmm = markov;
-    countFrequencies(sg);
-  }
-
-  /**
-   * Default constructor (required by ColourSchemes.loadColourSchemes)
-   */
-  public HMMERAlignmentColourScheme()
-  {
-  }
-
-  @Override
-  public Color findColour(char symbol, int position, SequenceI seq,
-          String consensusResidue, float pid)
-  {
-    return findColour(symbol, 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 (hmm == null || Comparison.isGap(symbol))
-    {
-      return Color.white;
-    }
-    if (Character.isLowerCase(symbol))
-    {
-      symbol = Character.toUpperCase(symbol);
-    }
-    double prob = hmm.getMatchEmissionProbability(column, symbol);
-    Double freq = frequency.get(symbol);
-    if (freq == null)
-    {
-      return Color.white;
-    }
-    if (prob == 0)
-    {
-      return new Color(230, 0, 0);
-    }
-    double value = Math.log(prob / freq.doubleValue());
-    Color colour = null;
-    if (value > 0)
-    {
-      colour = ColorUtils.getGraduatedColour((float) value, 0,
-              Color.WHITE, logTotalCount, Color.blue);
-    }
-    else if (value < 0)
-    {
-      return Color.ORANGE;
-    }
-    return colour;
-  }
-
-  @Override
-  public void alignmentChanged(AnnotatedCollectionI collection,
-          Map<SequenceI, SequenceCollectionI> hiddenReps)
-  {
-    /*
-     * ? no need to do anything if alignment is adjusted
-     * since findColour() handles everything 
-     */
-  }
-
-  @Override
-  public ColourSchemeI getInstance(AnnotatedCollectionI sg,
-          Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
-  {
-    SequenceI hmmSeq = sg.getHmmConsensus();
-    HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM();
-    return new HMMERAlignmentColourScheme(sg, model);
-  }
-
-  /**
-   * Answers true if the sequence collection has an HMM consensus sequence, else
-   * false
-   */
-  @Override
-  public boolean isApplicableTo(AnnotatedCollectionI ac)
-  {
-    return ac.getHmmConsensus() != null;
-  }
-
-  @Override
-  public String getSchemeName()
-  {
-    return JalviewColourScheme.HMMERA.toString();
-  }
-
-  @Override
-  public boolean isSimple()
-  {
-    return false;
-  }
-
-  /**
-   * Counts and stores the relatively frequency of every residue in the
-   * alignment
-   * 
-   * @param sg
-   */
-  public void countFrequencies(AnnotatedCollectionI sg)
-  {
-    ResidueCount counts = new ResidueCount(sg.getSequences());
-    int total = counts.getTotalResidueCount(); // excludes gaps
-
-    for (char symbol : counts.getSymbolCounts().symbols)
-    {
-      double freq = counts.getCount(symbol) / (double) total;
-      frequency.put(symbol, freq);
-    }
-    logTotalCount = (float) Math.log(total);
-  }
-}
similarity index 62%
rename from src/jalview/schemes/HMMERColourScheme.java
rename to src/jalview/schemes/HmmerColourScheme.java
index ee6c873..011c071 100644 (file)
@@ -11,7 +11,8 @@ import java.awt.Color;
 import java.util.Map;
 
 /**
- * A colour scheme based on a selected Hidden Markov Model. The colour is
+ * Base class for colour schemes based on a selected Hidden Markov Model. The
+ * colour is
  * <ul>
  * <li>white for a gap</li>
  * <li>red for an insertion</li>
@@ -21,33 +22,29 @@ import java.util.Map;
  * where information content is the log ratio
  * 
  * <pre>
- *   log(profile match emission probability / residue background probability>
+ *   log(profile match emission probability / residue background probability)
  * </pre>
  * 
- * using global ('Uniprot') background frequencies for residues.
+ * Sub-class implementations use either global ('Uniprot') or local
+ * ('alignment') background frequencies.
  * 
  * @author tzvanaalten
- *
+ * @author gmcarstairs
  */
-public class HMMERColourScheme extends ResidueColourScheme
+public abstract 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;
+  private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish
 
-  private static final Color REDDISH = new Color(230, 0, 0);
+  private HiddenMarkovModel hmm;
 
-  HiddenMarkovModel hmm;
+  private Map<Character, Float> frequencies;
 
   /**
    * Constructor given a Hidden Markov Model
    * 
    * @param markov
    */
-  public HMMERColourScheme(HiddenMarkovModel markov)
+  public HmmerColourScheme(HiddenMarkovModel markov)
   {
     hmm = markov;
   }
@@ -55,7 +52,7 @@ public class HMMERColourScheme extends ResidueColourScheme
   /**
    * Default constructor (required by ColourSchemes.loadColourSchemes)
    */
-  public HMMERColourScheme()
+  public HmmerColourScheme()
   {
   }
 
@@ -81,7 +78,7 @@ public class HMMERColourScheme extends ResidueColourScheme
    */
   private Color findColour(char symbol, int column)
   {
-    if (hmm == null || Comparison.isGap(symbol))
+    if (getHmm() == null || Comparison.isGap(symbol))
     {
       return Color.white;
     }
@@ -90,28 +87,27 @@ public class HMMERColourScheme extends ResidueColourScheme
       symbol = Character.toUpperCase(symbol);
     }
 
-    double prob = hmm.getMatchEmissionProbability(column, symbol);
+    double prob = getHmm().getMatchEmissionProbability(column, symbol);
     Float freq = 0f;
-    String alpha = hmm.getAlphabetType();
-    if (!ResidueProperties.backgroundFrequencies.get(alpha)
-            .containsKey(symbol))
+
+    if (!frequencies.containsKey(symbol))
     {
       return Color.WHITE;
     }
     else
     {
-      freq = ResidueProperties.backgroundFrequencies.get(alpha).get(symbol);
+      freq = frequencies.get(symbol);
     }
     if (prob == 0D)
     {
-      return REDDISH;
+      return INSERTION_COLOUR;
     }
     double value = Math.log(prob / freq.floatValue());
     Color colour = null;
     if (value > 0)
     {
       colour = ColorUtils.getGraduatedColour((float) value, 0,
-              Color.WHITE, MAX_LOG_RATIO, Color.blue);
+              Color.WHITE, getMaxInformationScore(), Color.blue);
     }
     else if (value < 0)
     {
@@ -120,6 +116,14 @@ public class HMMERColourScheme extends ResidueColourScheme
     return colour;
   }
 
+  /**
+   * Answers the maximum possible value of information score (log ratio), for
+   * use in scaling a graduated colour range
+   * 
+   * @return
+   */
+  abstract float getMaxInformationScore();
+
   @Override
   public void alignmentChanged(AnnotatedCollectionI collection,
           Map<SequenceI, SequenceCollectionI> hiddenReps)
@@ -132,24 +136,27 @@ public class HMMERColourScheme extends ResidueColourScheme
 
   /**
    * Answers a new colour scheme instance based on the HMM of the first sequence
-   * in sg that has an HMM
+   * in ac that has an HMM
    */
   @Override
-  public ColourSchemeI getInstance(AnnotatedCollectionI sg,
+  public ColourSchemeI getInstance(AnnotatedCollectionI ac,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
-    SequenceI hmmSeq = sg.getHmmConsensus();
+    SequenceI hmmSeq = ac.getHmmConsensus();
     HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM();
 
-    HMMERColourScheme colour = new HMMERColourScheme(model);
-    return colour;
+    return newInstance(ac, model);
   }
 
-  @Override
-  public String getSchemeName()
-  {
-    return JalviewColourScheme.HMMERU.toString();
-  }
+  /**
+   * Answers a new instance of the colour scheme for the given HMM
+   * 
+   * @param ac
+   * @param model
+   * @return
+   */
+  protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac,
+          HiddenMarkovModel model);
 
   @Override
   public boolean isSimple()
@@ -167,4 +174,19 @@ public class HMMERColourScheme extends ResidueColourScheme
     return ac.getHmmConsensus() != null;
   }
 
+  protected Map<Character, Float> getFrequencies()
+  {
+    return frequencies;
+  }
+
+  protected void setFrequencies(Map<Character, Float> frequencies)
+  {
+    this.frequencies = frequencies;
+  }
+
+  protected HiddenMarkovModel getHmm()
+  {
+    return hmm;
+  }
+
 }
diff --git a/src/jalview/schemes/HmmerGlobalBackground.java b/src/jalview/schemes/HmmerGlobalBackground.java
new file mode 100644 (file)
index 0000000..76d77ab
--- /dev/null
@@ -0,0 +1,59 @@
+package jalview.schemes;
+
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+
+/**
+ * An HMM colour scheme that uses global ('Uniprot') background frequencies for
+ * residues
+ * 
+ * @author tzvanaalten
+ */
+public class HmmerGlobalBackground extends HmmerColourScheme
+{
+  /*
+   * 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;
+
+  /**
+   * Constructor given a Hidden Markov Model
+   * 
+   * @param markov
+   */
+  public HmmerGlobalBackground(HiddenMarkovModel markov)
+  {
+    super(markov);
+    setFrequencies(ResidueProperties.backgroundFrequencies
+            .get(getHmm().getAlphabetType()));
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HmmerGlobalBackground()
+  {
+  }
+
+  @Override
+  public String getSchemeName()
+  {
+    return JalviewColourScheme.HMMERU.toString();
+  }
+
+  @Override
+  protected HmmerColourScheme newInstance(AnnotatedCollectionI ac,
+          HiddenMarkovModel model)
+  {
+    return new HmmerGlobalBackground(model);
+  }
+
+  @Override
+  float getMaxInformationScore()
+  {
+    return MAX_LOG_RATIO;
+  }
+
+}
diff --git a/src/jalview/schemes/HmmerLocalBackground.java b/src/jalview/schemes/HmmerLocalBackground.java
new file mode 100644 (file)
index 0000000..b878b9e
--- /dev/null
@@ -0,0 +1,81 @@
+package jalview.schemes;
+
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.ResidueCount;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An HMM colour scheme that uses local (alignment or sub-group) background
+ * frequencies for residues
+ * 
+ * @author tzvanaalten
+ */
+public class HmmerLocalBackground extends HmmerColourScheme
+{
+  float logTotalCount;
+
+  /**
+   * Constructor given a Hidden Markov Model
+   * 
+   * @param sg
+   * 
+   * @param markov
+   */
+  public HmmerLocalBackground(AnnotatedCollectionI sg,
+          HiddenMarkovModel markov)
+  {
+    super(markov);
+    countFrequencies(sg);
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HmmerLocalBackground()
+  {
+  }
+
+  @Override
+  public String getSchemeName()
+  {
+    return JalviewColourScheme.HMMERA.toString();
+  }
+
+  /**
+   * Counts and stores the relative frequency of every residue in the alignment
+   * 
+   * @param sg
+   */
+  public void countFrequencies(AnnotatedCollectionI sg)
+  {
+    Map<Character, Float> freqs = new HashMap<>();
+    ResidueCount counts = new ResidueCount(sg.getSequences());
+    int total = counts.getTotalResidueCount(); // excludes gaps
+
+    for (char symbol : counts.getSymbolCounts().symbols)
+    {
+      double freq = counts.getCount(symbol) / (double) total;
+      freqs.put(symbol, (float) freq);
+    }
+
+    setFrequencies(freqs);
+
+    logTotalCount = (float) Math.log(total);
+  }
+
+  @Override
+  float getMaxInformationScore()
+  {
+    return logTotalCount;
+  }
+
+  @Override
+  protected HmmerColourScheme newInstance(AnnotatedCollectionI ac,
+          HiddenMarkovModel model)
+  {
+    return new HmmerLocalBackground(ac, model);
+  }
+}
index 3d6d88d..57ff88d 100644 (file)
@@ -43,8 +43,8 @@ public enum JalviewColourScheme
   PurinePyrimidine("Purine/Pyrimidine", PurinePyrimidineColourScheme.class),
   RNAHelices("RNA Helices", RNAHelicesColour.class),
   TCoffee("T-Coffee Scores", TCoffeeColourScheme.class),
-  HMMERU("HMMER-Uniprot", HMMERColourScheme.class),
-  HMMERA("HMMER-Alignment", HMMERAlignmentColourScheme.class);
+  HMMERU("HMMER-Uniprot", HmmerColourScheme.class),
+  HMMERA("HMMER-Alignment", HmmerLocalBackground.class);
   // RNAInteraction("RNA Interaction type", RNAInteractionColourScheme.class)
 
   private String name;
@@ -11,7 +11,7 @@ import java.net.MalformedURLException;
 
 import org.testng.annotations.Test;
 
-public class HMMERColourSchemeTest {
+public class HmmerGlobalBackgroundTest {
 
   @Test(groups = "Functional")
   public void testFindColour() throws MalformedURLException, IOException
@@ -19,7 +19,7 @@ public class HMMERColourSchemeTest {
     HMMFile file = new HMMFile("test/jalview/io/test_PKinase_hmm.txt",
             DataSourceType.FILE);
 
-    ColourSchemeI scheme = new HMMERColourScheme(file.getHMM());
+    ColourSchemeI scheme = new HmmerGlobalBackground(file.getHMM());
 
     /*
      * 'A' in column 1, node 2, match emission 2.77204
@@ -15,7 +15,7 @@ import java.net.MalformedURLException;
 
 import org.testng.annotations.Test;
 
-public class HMMERAlignmentColourSchemeTest {
+public class HmmerLocalBackgroundTest {
 
   @Test(groups = "Functional")
   public void testFindColour() throws MalformedURLException, IOException
@@ -34,7 +34,7 @@ public class HMMERAlignmentColourSchemeTest {
     SequenceI seq1 = new Sequence("seq1", "AAMMMKKKVV");
     SequenceI seq2 = new Sequence("seq2", "aAM-QKRSSSL");
     AnnotatedCollectionI ac = new Alignment(new SequenceI[] { seq1, seq2 });
-    ColourSchemeI scheme = new HMMERAlignmentColourScheme(ac,
+    ColourSchemeI scheme = new HmmerLocalBackground(ac,
             file.getHMM());
 
     /*