From: gmungoc Date: Tue, 20 Mar 2018 16:32:13 +0000 (+0000) Subject: JAL-2629 InformationThread.findOrCreateAnnotation and related updates for a more... X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=05a51640d2a5c35cd32e8ad831963bd268ea10f6;p=jalview.git JAL-2629 InformationThread.findOrCreateAnnotation and related updates for a more stable recalculation --- diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 3e59274..963bfbd 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -344,20 +344,16 @@ public class AAFrequency * @param endCol * end column (exclusive) * @param ignoreGaps - * if true, normalise residue percentages + * if true, normalise residue percentages * @param showSequenceLogo * if true include all information symbols, else just show modal * residue - * @param nseq - * number of sequences */ public static float completeInformation(AlignmentAnnotation information, - ProfilesI profiles, int startCol, int endCol, long nseq, - float currentMax) + ProfilesI profiles, int startCol, int endCol) { // long now = System.currentTimeMillis(); - if (information == null || information.annotations == null - || information.annotations.length < endCol) + if (information == null || information.annotations == null) { /* * called with a bad alignment annotation row @@ -368,10 +364,22 @@ public class AAFrequency float max = 0f; SequenceI hmmSeq = information.sequenceRef; + + int seqLength = hmmSeq.getLength(); + if (information.annotations.length < seqLength) + { + return 0; + } + HiddenMarkovModel hmm = hmmSeq.getHMM(); for (int column = startCol; column < endCol; column++) { + if (column >= seqLength) + { + // hmm consensus sequence is shorter than the alignment + break; + } ProfileI profile = profiles.get(column); if (profile == null) { @@ -398,7 +406,6 @@ public class AAFrequency description, ' ', value); } - max = Math.max(max, currentMax); information.graphMax = max; return max; } diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 3ae46b8..6b100ea 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -1661,7 +1661,7 @@ public class Alignment implements AlignmentI annot.hasText = false; if (calcId != null) { - annot.setCalcId(new String(calcId)); + annot.setCalcId(calcId); } annot.autoCalculated = autoCalc; if (seqRef != null) diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index dd3692a..d591f42 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -504,8 +504,6 @@ public interface AlignmentI extends AnnotatedCollectionI * - null or specific sequence reference * @param groupRef * - null or specific group reference - * @param method - * - CalcId for the annotation (must match) * * @return existing annotation matching the given attributes */ diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index b7ec9f9..4c38aa0 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -619,7 +619,7 @@ public class SequenceGroup implements AnnotatedCollectionI (endRes + 1) - startRes, startRes, endRes + 1, showHMMSequenceLogo, hmmIgnoreBelowBackground, hmmUseInfoLetterHeight); - _updateInformationRow(info, sequences.size()); + _updateInformationRow(info); upd = true; } if (consensus != null) @@ -720,12 +720,11 @@ public class SequenceGroup implements AnnotatedCollectionI } /** - * Recalculates the information content on the HMM annotation. + * Recalculates the information content on the HMM annotation * * @param cnsns - * @param nseq */ - private void _updateInformationRow(ProfilesI cnsns, long nseq) + private void _updateInformationRow(ProfilesI cnsns) { if (hmmInformation == null) { @@ -744,7 +743,7 @@ public class SequenceGroup implements AnnotatedCollectionI // width hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); AAFrequency.completeInformation(hmmInformation, cnsns, startRes, - endRes + 1, nseq, 0f); + endRes + 1); } /** diff --git a/src/jalview/hmmer/HMMBuild.java b/src/jalview/hmmer/HMMBuild.java index b892e5c..6887cb5 100644 --- a/src/jalview/hmmer/HMMBuild.java +++ b/src/jalview/hmmer/HMMBuild.java @@ -1,8 +1,8 @@ package jalview.hmmer; import jalview.api.AlignViewportI; +import jalview.bin.Cache; import jalview.datamodel.Alignment; -import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.SequenceGroup; @@ -15,7 +15,6 @@ import jalview.io.DataSourceType; import jalview.io.FileParse; import jalview.io.HMMFile; import jalview.util.MessageManager; -import jalview.workers.InformationThread; import jalview.ws.params.ArgumentI; import java.io.File; @@ -58,6 +57,12 @@ public class HMMBuild extends HmmerCommand @Override public void run() { + if (params == null) + { + Cache.log.error("No parameters to HMMBuild!|"); + return; + } + long msgID = System.currentTimeMillis(); af.setProgressBar(MessageManager.getString("status.running_hmmbuild"), msgID); @@ -65,53 +70,11 @@ public class HMMBuild extends HmmerCommand AlignViewportI viewport = af.getViewport(); try { - List runBuildFor = new ArrayList<>(); - if (params != null) - { - for (ArgumentI arg : params) - { - String name = arg.getName(); - if (MessageManager.getString("label.hmmbuild_for").equals(name)) - { - String value = arg.getValue(); - if (MessageManager.getString("label.alignment") - .equals(value)) - { - runBuildFor.add(alignment); - } - else if (MessageManager.getString("label.groups_and_alignment") - .equals(value)) - { - runBuildFor.add(alignment); - runBuildFor.addAll(viewport.getAlignment().getGroups()); - } - else if (MessageManager.getString("label.groups").equals(value)) - { - runBuildFor.addAll(viewport.getAlignment().getGroups()); - } - else if (MessageManager.getString("label.selected_group") - .equals(value)) - { - runBuildFor.add(viewport.getSelectionGroup()); - } - } - else if (MessageManager.getString("label.use_reference") - .equals(name)) - { - // todo disable this option if no RF annotation on alignment - if (!af.getViewport().hasReferenceAnnotation()) - { - JvOptionPane.showInternalMessageDialog(af, MessageManager - .getString("warn.no_reference_annotation")); - // return; - } - } - } - } - /* * run hmmbuild for alignment and/or groups as selected */ + List runBuildFor = parseParameters(viewport); + for (AnnotatedCollectionI grp : runBuildFor) { runHMMBuild(grp); @@ -125,6 +88,58 @@ public class HMMBuild extends HmmerCommand } /** + * Scans the parameters to determine whether to run hmmmbuild for the whole + * alignment or specified subgroup(s) or both + * + * @param viewport + * @return + */ + protected List parseParameters( + AlignViewportI viewport) + { + List runBuildFor = new ArrayList<>(); + for (ArgumentI arg : params) + { + String name = arg.getName(); + if (MessageManager.getString("label.hmmbuild_for").equals(name)) + { + String value = arg.getValue(); + if (MessageManager.getString("label.alignment").equals(value)) + { + runBuildFor.add(alignment); + } + else if (MessageManager.getString("label.groups_and_alignment") + .equals(value)) + { + runBuildFor.add(alignment); + runBuildFor.addAll(viewport.getAlignment().getGroups()); + } + else if (MessageManager.getString("label.groups").equals(value)) + { + runBuildFor.addAll(viewport.getAlignment().getGroups()); + } + else if (MessageManager.getString("label.selected_group") + .equals(value)) + { + runBuildFor.add(viewport.getSelectionGroup()); + } + } + else if (MessageManager.getString("label.use_reference") + .equals(name)) + { + // todo disable this option if no RF annotation on alignment + if (!af.getViewport().hasReferenceAnnotation()) + { + JvOptionPane.showInternalMessageDialog(af, MessageManager + .getString("warn.no_reference_annotation")); + // return; + } + } + } + return runBuildFor; + } + + /** * Runs hmmbuild on the given sequences (alignment or group) * * @param grp @@ -153,8 +168,10 @@ public class HMMBuild extends HmmerCommand /* * copy over sequences, excluding hmm consensus sequences - * hmm sequences and their Information annotation are also deleted - * in preparation for re-adding them when recalculated + * hmm sequences are also deleted in preparation for + * re-adding them when recalculated; Information annotation is not + * deleted, it will be updated to reference the new hmm sequence + * by InformationThread.findOrCreateAnnotation */ Iterator it = copy.iterator(); while (it.hasNext()) @@ -162,19 +179,6 @@ public class HMMBuild extends HmmerCommand SequenceI seq = it.next(); if (seq.isHMMConsensusSequence()) { - // todo leave it to InformationThread to delete annotations? - AlignmentAnnotation[] seqAnnotations = seq - .getAnnotation(); - if (seqAnnotations != null) - { - for (AlignmentAnnotation ann : seqAnnotations) - { - if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId())) - { - alignment.deleteAnnotation(ann); - } - } - } alignment.deleteSequence(seq); it.remove(); } diff --git a/src/jalview/renderer/ResidueShader.java b/src/jalview/renderer/ResidueShader.java index b312730..c031170 100644 --- a/src/jalview/renderer/ResidueShader.java +++ b/src/jalview/renderer/ResidueShader.java @@ -415,11 +415,4 @@ public class ResidueShader implements ResidueShaderI { colourScheme = cs; } - - @Override - public void setInformation(ProfilesI info) - { - // TODO Auto-generated method stub - - } } diff --git a/src/jalview/renderer/ResidueShaderI.java b/src/jalview/renderer/ResidueShaderI.java index d0b25b6..7e67598 100644 --- a/src/jalview/renderer/ResidueShaderI.java +++ b/src/jalview/renderer/ResidueShaderI.java @@ -5,16 +5,16 @@ * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License + * modify it under the terms of the GNU General License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * PURPOSE. See the GNU General License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ @@ -32,18 +32,15 @@ import java.util.Map; public interface ResidueShaderI { + void setConsensus(ProfilesI cons); - public abstract void setConsensus(ProfilesI cons); + boolean conservationApplied(); - public abstract void setInformation(ProfilesI info); + void setConservationApplied(boolean conservationApplied); - public abstract boolean conservationApplied(); + void setConservation(Conservation cons); - public abstract void setConservationApplied(boolean conservationApplied); - - public abstract void setConservation(Conservation cons); - - public abstract void alignmentChanged(AnnotatedCollectionI alignment, + void alignmentChanged(AnnotatedCollectionI alignment, Map hiddenReps); /** @@ -53,19 +50,19 @@ public interface ResidueShaderI * @param consensusThreshold * @param ignoreGaps */ - public abstract void setThreshold(int consensusThreshold, + void setThreshold(int consensusThreshold, boolean ignoreGaps); - public abstract void setConservationInc(int i); + void setConservationInc(int i); - public abstract int getConservationInc(); + int getConservationInc(); /** * Get the percentage threshold for this colour scheme * * @return Returns the percentage threshold */ - public abstract int getThreshold(); + int getThreshold(); /** * Returns the possibly context dependent colour for the given symbol at the @@ -77,11 +74,11 @@ public interface ResidueShaderI * @param seq * @return */ - public abstract Color findColour(char symbol, int position, + Color findColour(char symbol, int position, SequenceI seq); - public abstract ColourSchemeI getColourScheme(); + ColourSchemeI getColourScheme(); - public abstract void setColourScheme(ColourSchemeI cs); + void setColourScheme(ColourSchemeI cs); } \ No newline at end of file diff --git a/src/jalview/workers/InformationThread.java b/src/jalview/workers/InformationThread.java index 6a86a61..28b4962 100644 --- a/src/jalview/workers/InformationThread.java +++ b/src/jalview/workers/InformationThread.java @@ -10,7 +10,6 @@ import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.ProfilesI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; -import jalview.renderer.ResidueShaderI; import jalview.util.MessageManager; import java.util.List; @@ -91,9 +90,8 @@ public class InformationThread extends AlignCalcWorker return; } - eraseAnnotations(alignment); computeProfiles(alignment); - updateResultAnnotation(true); + updateAnnotation(); if (ap != null) { @@ -111,27 +109,12 @@ public class InformationThread extends AlignCalcWorker } /** - * Deletes any existing information annotations. These are sequence-related - * annotations which relate to HMM consensus sequences for either the - * alignment or a subgroup. - * - * @param alignment - */ - protected void eraseAnnotations(AlignmentI alignment) - { - Iterable anns = alignment - .findAnnotation(HMM_CALC_ID); - for (AlignmentAnnotation ann : anns) - { - alignment.deleteAnnotation(ann); - } - } - - /** * Computes HMM profiles for any HMM consensus sequences (for alignment or - * subgroups) + * subgroups). Any alignment profile computed is stored on the viewport, any + * group profile computed is stored on the respective sequence group. * * @param alignment + * @see AlignViewportI#setHmmProfiles(ProfilesI) */ protected void computeProfiles(AlignmentI alignment) { @@ -148,7 +131,6 @@ public class InformationThread extends AlignCalcWorker 0, width, true, alignViewport.isIgnoreBelowBackground(), alignViewport.isInfoLetterHeight()); alignViewport.setHmmProfiles(hmmProfiles); - // setColourSchemeInformation(hmmProfiles); } /* @@ -165,7 +147,6 @@ public class InformationThread extends AlignCalcWorker 0, width, true, group.isIgnoreBelowBackground(), group.isUseInfoLetterHeight()); group.setHmmProfiles(hmmProfiles); - // setColourSchemeInformation(hmmProfiles); } } } @@ -180,15 +161,6 @@ public class InformationThread extends AlignCalcWorker return alignViewport.getAlignment().getSequencesArray(); } - protected void setColourSchemeInformation(ProfilesI information) - { - ResidueShaderI cs = alignViewport.getResidueShading(); - if (cs != null) - { - cs.setInformation(information); - } - } - /** * Get the Gap annotation for the alignment * @@ -200,36 +172,23 @@ public class InformationThread extends AlignCalcWorker } /** - * Updates the information annotation from the sequence profile data using - * current visualisation settings + * Computes Information Content annotation for any HMM consensus sequences + * (for alignment or groups), and updates (or adds) the annotation to the + * sequence and the alignment */ @Override public void updateAnnotation() { - updateResultAnnotation(false); - } - - /** - * Constructs Information Content annotation for any HMM consensus sequences - * (for alignment or groups), and adds the annotation to the sequence and the - * alignment - * - * @param immediate - */ - public void updateResultAnnotation(boolean immediate) - { AlignmentI alignment = alignViewport.getAlignment(); + this.max = 0f; + /* * annotation for alignment HMM consensus if present */ SequenceI hmmSeq = alignment.getHmmConsensus(); ProfilesI profile = alignViewport.getHmmProfiles(); - AlignmentAnnotation ann = makeInformationAnnotation(hmmSeq, profile); - if (ann != null) - { - alignment.addAnnotation(ann); - } + updateInformationAnnotation(hmmSeq, profile, null); /* * annotation for group HMM consensus if present @@ -238,65 +197,96 @@ public class InformationThread extends AlignCalcWorker { hmmSeq = group.getHmmConsensus(); ProfilesI profiles = group.getHmmProfiles(); - ann = makeInformationAnnotation(hmmSeq, profiles); - if (ann != null) - { - ann.groupRef = group; - alignment.addAnnotation(ann); - } + updateInformationAnnotation(hmmSeq, profiles, group); } + + /* + * todo: this.max is not used, but acquires the maximum value of + * information in any of the annotations; set this as graphMax in all + * annotations to have them all scaled the same + */ } /** - * Constructs an HMM Profile information content annotation for a sequence + * Updates (and first constructs if necessary) an HMM Profile information + * content annotation for a sequence. The group argument is null + * for the whole alignment annotation, not null for a subgroup annotation. * * @param seq * @param profile + * @param group * @return */ - protected AlignmentAnnotation makeInformationAnnotation(SequenceI seq, - ProfilesI profile) + protected AlignmentAnnotation updateInformationAnnotation(SequenceI seq, + ProfilesI profile, SequenceGroup group) { if (seq == null || profile == null) { return null; } - AlignmentI alignment = alignViewport.getAlignment(); - int aWidth = alignment == null ? 0 : alignment.getWidth(); - AlignmentAnnotation ann = new AlignmentAnnotation(seq.getName(), - MessageManager.getString("label.information_description"), - new Annotation[aWidth], 0f, 6.52f, - AlignmentAnnotation.BAR_GRAPH); - ann.hasText = true; - ann.autoCalculated = false; - ann.sequenceRef = seq; - ann.setCalcId(InformationThread.HMM_CALC_ID); + AlignmentAnnotation ann = findOrCreateAnnotation(seq, group); + seq.addAlignmentAnnotation(ann); - long nseq = getSequences().length; max = AAFrequency.completeInformation(ann, profile, - profile.getStartColumn(), profile.getEndColumn() + 1, nseq, - max); + profile.getStartColumn(), profile.getEndColumn() + 1); return ann; } /** - * Convert the computed information data into the desired annotation for - * display. + * A helper method that first searches for the HMM annotation that matches the + * group reference (null for the whole alignment annotation). If found, its + * sequence reference is updated to the given sequence (the recomputed HMM + * consensus sequence). If not found, it is created. This supports both + * creating the annotation the first time hmmbuild is run, and updating it if + * hmmbuild is re-run. * - * @param informationAnnotation - * the annotation to be populated - * @param hinformation - * the computed information data + * @param seq + * @param group + * @return */ - protected void deriveInformation( - AlignmentAnnotation informationAnnotation, ProfilesI hinformation) + AlignmentAnnotation findOrCreateAnnotation(SequenceI seq, + SequenceGroup group) { - long nseq = getSequences().length; - max = AAFrequency.completeInformation(informationAnnotation, - hinformation, hinformation.getStartColumn(), - hinformation.getEndColumn() + 1, nseq, max); + /* + * can't use Alignment.findOrCreateAnnotation here because we + * want to update, rather than match on, the sequence ref + */ + AlignmentAnnotation info = null; + + AlignmentI alignment = alignViewport.getAlignment(); + AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation(); + if (anns != null) + { + for (AlignmentAnnotation ann : anns) + { + if (HMM_CALC_ID.equals(ann.getCalcId()) && group == ann.groupRef) + { + info = ann; + info.setSequenceRef(seq); + break; + } + } + } + + if (info == null) + { + int aWidth = alignment.getWidth(); + String desc = MessageManager + .getString("label.information_description"); + float graphMax = 6.52f; // todo where does this value derive from? + info = new AlignmentAnnotation(seq.getName(), desc, + new Annotation[aWidth], 0f, graphMax, + AlignmentAnnotation.BAR_GRAPH); + info.setCalcId(HMM_CALC_ID); + info.setSequenceRef(seq); + info.groupRef = group; + info.hasText = true; + alignment.addAnnotation(info); + } + + return info; } } diff --git a/test/jalview/analysis/AAFrequencyTest.java b/test/jalview/analysis/AAFrequencyTest.java index fc4063a..2b6c512 100644 --- a/test/jalview/analysis/AAFrequencyTest.java +++ b/test/jalview/analysis/AAFrequencyTest.java @@ -335,7 +335,7 @@ public class AAFrequencyTest seq.setHMM(hmm); AlignmentAnnotation annot = new AlignmentAnnotation("", "", annots); annot.setSequenceRef(seq); - AAFrequency.completeInformation(annot, profs, 0, 1, 1, 1f); + AAFrequency.completeInformation(annot, profs, 0, 1); float ic = annot.annotations[0].value; assertEquals(0.91532f, ic, 0.0001f); ic = annot.annotations[1].value;