From 96356075a122b745936738f478a8ee33ac7e0f0a Mon Sep 17 00:00:00 2001 From: TZVanaalten Date: Wed, 12 Jul 2017 11:05:42 +0100 Subject: [PATCH] test HMM annotaTION --- src/jalview/analysis/AAFrequency.java | 91 ++++++++++++++++++++++++ src/jalview/datamodel/SequenceGroup.java | 17 +++++ src/jalview/gui/AlignFrame.java | 7 +- src/jalview/gui/AnnotationLabels.java | 49 ++++++++++++- src/jalview/renderer/AnnotationRenderer.java | 97 +------------------------- src/jalview/viewmodel/AlignmentViewport.java | 22 ++++++ test/jalview/analysis/AAFrequencyTest.java | 48 +++++++++++++ 7 files changed, 233 insertions(+), 98 deletions(-) diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 514b300..3cc57bf 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -24,6 +24,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.Profile; import jalview.datamodel.ProfileI; import jalview.datamodel.Profiles; @@ -32,6 +33,7 @@ import jalview.datamodel.ResidueCount; import jalview.datamodel.ResidueCount.SymbolCounts; import jalview.datamodel.SequenceI; import jalview.ext.android.SparseIntArray; +import jalview.schemes.ResidueProperties; import jalview.util.Comparison; import jalview.util.Format; import jalview.util.MappingUtils; @@ -55,6 +57,10 @@ public class AAFrequency { public static final String PROFILE = "P"; + private static final String AMINO = "amino"; + + private static final String DNA = "DNA"; + /* * Quick look-up of String value of char 'A' to 'Z' */ @@ -719,4 +725,89 @@ public class AAFrequency } return scale; } + + /** + * produces a HMM profile for a column in an alignment + * + * @param aa + * Alignment annotation for which the profile is being calculated + * @param column + * column in the alignment the profile is being made for + * @param removeBelowBackground + * boolean, indicating whether to ignore residues with probabilities + * less than their background frequencies + * @return + */ + public static int[] getHMMProfileFor(AlignmentAnnotation aa, int column, + boolean removeBelowBackground) + { + + HiddenMarkovModel hmm; + hmm = aa.getHMM(); + if (hmm != null) + { + String alph = hmm.getAlphabetType(); + int size = hmm.getNumberOfSymbols(); + char symbols[] = new char[size]; + int values[] = new int[size]; + List charList = hmm.getSymbols(); + Integer totalCount = 0; + + for (int i = 0; i < size; i++) + { + char symbol = charList.get(i); + symbols[i] = symbol; + Double value; + + value = hmm.getMatchEmissionProbability(column, symbol); + double freq; + + if (alph == AMINO && removeBelowBackground) + { + freq = ResidueProperties.aminoBackgroundFrequencies.get(symbol); + if (value < freq) + { + value = 0d; + } + } + else if (alph == DNA && removeBelowBackground) + { + freq = ResidueProperties.nucleotideBackgroundFrequencies + .get(symbol); + if (value < freq) + { + value = 0d; + } + } + value = value * 10000; + values[i] = value.intValue(); + totalCount += value.intValue(); + } + + QuickSort.sort(values, symbols); + + int[] profile = new int[3 + size * 2]; + + profile[0] = AlignmentAnnotation.SEQUENCE_PROFILE; + profile[1] = size; + profile[2] = totalCount / 100; + + if (totalCount != 0) + { + int arrayPos = 3; + for (int k = size - 1; k >= 0; k--) + { + Double percentage; + Integer value = values[k]; + percentage = (value.doubleValue() / totalCount.doubleValue()) + * 100d; + profile[arrayPos] = symbols[k]; + profile[arrayPos + 1] = percentage.intValue(); + arrayPos += 2; + } + } + return profile; + } + return null; + } } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 520bfaf..688c7ae 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -102,6 +102,8 @@ public class SequenceGroup implements AnnotatedCollectionI */ private boolean ignoreGapsInConsensus = true; + private boolean ignoreBelowBackground = true; + /** * consensus calculation property */ @@ -209,6 +211,7 @@ public class SequenceGroup implements AnnotatedCollectionI thresholdTextColour = seqsel.thresholdTextColour; width = seqsel.width; ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus; + ignoreBelowBackground = seqsel.ignoreBelowBackground; if (seqsel.conserve != null) { recalcConservation(); // safer than @@ -1189,6 +1192,20 @@ public class SequenceGroup implements AnnotatedCollectionI return ignoreGapsInConsensus; } + public void setIgnoreBelowBackground(boolean state) + { + if (this.ignoreBelowBackground != state) + { + ignoreBelowBackground = state; + } + ignoreBelowBackground = state; + } + + public boolean getIgnoreBelowBackground() + { + return true; + } + /** * @param showSequenceLogo * indicates if a sequence logo is shown for consensus annotation diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index a91bb66..334d380 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -4653,7 +4653,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } else if (FileFormat.HMMER3.equals(format)) { - HMMFile hmmFile = new HMMFile(new FileParse(file, sourceType)); + HMMFile hmmFile = new HMMFile(new FileParse(file, sourceType)); // TODO + // need + // to + // follow + // standard + // pipeline hmmFile.parse(); HiddenMarkovModel hmm = hmmFile.getHMM(); AlignmentAnnotation annotation = hmm.createAnnotation( diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index 3e23ac0..ce87c72 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -438,14 +438,28 @@ public class AnnotationLabels extends JPanel implements MouseListener, else if (label.indexOf("Consensus") > -1 || label.indexOf("Information Content") > -1) { + // identifier for type of histogram and/or logo to be shown + int type = 2; + if (label.indexOf("Consensus") > -1) + { + type = 0; + } + else if (label.indexOf("Information Content") > -1) + { + type = 1; + } + pop.addSeparator(); // av and sequencegroup need to implement same interface for + final AlignmentAnnotation aaa = aa[selectedRow]; + if (type == 0) + { final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( - MessageManager.getString("label.ignore_gaps_consensus"), + MessageManager.getString("label.ignore_gaps_consensus"), (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef .getIgnoreGapsConsensus() : ap.av .isIgnoreGapsConsensus()); - final AlignmentAnnotation aaa = aa[selectedRow]; + cbmi.addActionListener(new ActionListener() { @Override @@ -466,6 +480,37 @@ public class AnnotationLabels extends JPanel implements MouseListener, } }); pop.add(cbmi); + } + if (type == 1) + { + final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( + "Ignore Below Background Frequency", + (aa[selectedRow].groupRef != null) + ? aa[selectedRow].groupRef + .getIgnoreBelowBackground() + : ap.av.isIgnoreBelowBackground()); + + cbmi.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (aaa.groupRef != null) + { + // TODO: pass on reference to ap so the view can be updated. + aaa.groupRef.setIgnoreBelowBackground(cbmi.getState()); + ap.getAnnotationPanel() + .paint(ap.getAnnotationPanel().getGraphics()); + } + else + { + ap.av.setIgnoreBelowBackground(cbmi.getState(), ap); + } + ap.alignmentChanged(); + } + }); + pop.add(cbmi); + } // av and sequencegroup need to implement same interface for if (aaa.groupRef != null) { diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 640bf45..95bbf28 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -29,14 +29,12 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; -import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.ProfilesI; import jalview.schemes.ColourSchemeI; import jalview.schemes.NucleotideColourScheme; import jalview.schemes.ResidueProperties; import jalview.schemes.ZappoColourScheme; import jalview.util.Platform; -import jalview.util.QuickSort; import java.awt.BasicStroke; import java.awt.Color; @@ -50,7 +48,6 @@ import java.awt.geom.AffineTransform; import java.awt.image.ImageObserver; import java.util.BitSet; import java.util.Hashtable; -import java.util.List; public class AnnotationRenderer { @@ -60,10 +57,6 @@ public class AnnotationRenderer private static final int CHAR_Z = 'Z'; // 90 - private static final int AMINO = 0; - - private static final int DNA = 1; - /** * flag indicating if timing and redraw parameter info should be output */ @@ -344,94 +337,7 @@ public class AnnotationRenderer av_ignoreGapsConsensus = av.isIgnoreGapsConsensus(); } - public int[] getHMMProfileFor(AlignmentAnnotation aa, int column, - boolean removeBelowBackground) - { - - HiddenMarkovModel hmm; - hmm = aa.getHMM(); - int size = 0; - int alphabet = 0; - String alph = hmm.getAlphabetType(); - if (alph.equals("amino")) - { - size = 20; - alphabet = AMINO; - } - else if (alph.equals("DNA")) - { - size = 4; - alphabet = DNA; - } - - char symbols[] = new char[size]; - int values[] = new int[size]; - List charList = hmm.getSymbols(); - - int i = 0; - for (char character : charList) - { - symbols[i] = character; - i++; - } - - Integer totalCount = 0; - for (int j = 0; j < size; j++) - { - Double value; - char symbol = symbols[j]; - value = hmm.getMatchEmissionProbability(column, symbol); - double freq; - - if (alphabet == AMINO && removeBelowBackground) - { - freq = ResidueProperties.aminoBackgroundFrequencies.get(symbol); - if (value < freq) - { - value = 0d; - } - } - else if (alphabet == DNA && removeBelowBackground) - { - freq = ResidueProperties.nucleotideBackgroundFrequencies - .get(symbol); - if (value < freq) - { - value = 0d; - } - } - value = value * 10000; - values[j] = value.intValue(); - totalCount += value.intValue(); - } - - QuickSort.sort(values, symbols); - - int[] profile = new int[3 + size * 2]; - - profile[0] = AlignmentAnnotation.SEQUENCE_PROFILE; - profile[1] = size; - profile[2] = totalCount; - - if (totalCount != 0) - { - int arrayPos = 3; - for (int k = size - 1; k >= 0; k--) - { - Double percentage; - Integer value = values[k]; - percentage = (value.doubleValue() / totalCount.doubleValue()) - * 100d; - profile[arrayPos] = symbols[k]; - profile[arrayPos + 1] = percentage.intValue(); - arrayPos += 2; - } - } - - return profile; - - } /** * Returns profile data; the first element is the profile type, the second is @@ -450,7 +356,8 @@ public class AnnotationRenderer // if (aa.label.startsWith("Information")) { - return getHMMProfileFor(aa, column, true); + return AAFrequency.getHMMProfileFor(aa, column, + true); // TODO detect setting } if (aa.autoCalculated && (aa.label.startsWith("Consensus") || aa.label diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index f86282f..dfd120b 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -610,6 +610,8 @@ public abstract class AlignmentViewport implements AlignViewportI, protected boolean ignoreGapsInConsensusCalculation = false; + protected boolean ignoreBelowBackGroundFrequencyCalculation = false; + protected ResidueShaderI residueShading = new ResidueShader(); @Override @@ -1233,6 +1235,21 @@ public abstract class AlignmentViewport implements AlignViewportI, } + public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap) + { + ignoreBelowBackGroundFrequencyCalculation = b; + if (ap != null) + { + // updateConsensus(ap); + if (residueShading != null) + { + residueShading.setThreshold(residueShading.getThreshold(), + ignoreBelowBackGroundFrequencyCalculation); + } + } + + } + private long sgrouphash = -1, colselhash = -1; /** @@ -1287,6 +1304,11 @@ public abstract class AlignmentViewport implements AlignViewportI, return ignoreGapsInConsensusCalculation; } + public boolean isIgnoreBelowBackground() + { + return ignoreBelowBackGroundFrequencyCalculation; + } + // property change stuff // JBPNote Prolly only need this in the applet version. private PropertyChangeSupport changeSupport = new PropertyChangeSupport( diff --git a/test/jalview/analysis/AAFrequencyTest.java b/test/jalview/analysis/AAFrequencyTest.java index 75fb39e..646412f 100644 --- a/test/jalview/analysis/AAFrequencyTest.java +++ b/test/jalview/analysis/AAFrequencyTest.java @@ -25,11 +25,18 @@ import static org.testng.AssertJUnit.assertNull; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.ProfileI; import jalview.datamodel.ProfilesI; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; + +import java.io.IOException; +import java.net.MalformedURLException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -232,4 +239,45 @@ public class AAFrequencyTest assertEquals("T 75%", ann.description); assertEquals("T", ann.displayCharacter); } + + @Test(groups = { "Functional" }) + public void testGetHMMProfileFor() + throws MalformedURLException, IOException + { + + HMMFile hmmFile = new HMMFile(new FileParse( + "test/jalview/io/test_MADE1_hmm.txt", DataSourceType.FILE)); + hmmFile.parse(); + HiddenMarkovModel hmm = hmmFile.getHMM(); + AlignmentAnnotation aa = hmm.createAnnotation(80); + aa.setHMM(hmm); + + int[] expected = { 0, 4, 100, 'T', 71, 'C', 12, 'G', 9, 'A', 9 }; + int[] actual = AAFrequency.getHMMProfileFor(aa, 17, false); + for (int i = 0; i < actual.length; i++) + { + if (i == 2) + { + assertEquals(actual[i], expected[i], 5); + } + else + { + assertEquals(actual[i], expected[i], 1); + } + } + + int[] expected2 = { 0, 4, 85, 'A', 85, 'C', 0, 'G', 0, 'T', 0 }; + int[] actual2 = AAFrequency.getHMMProfileFor(aa, 2, true); + for (int i = 0; i < actual.length; i++) + { + if (i == 2) + { + assertEquals(actual[i], expected[i], 5); + } + else + { + assertEquals(actual[i], expected[i], 1); + } + } + } } -- 1.7.10.2