X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fworkers%2FInformationThread.java;h=c8084b92914453b61371ca22c1259ecd853a0fe4;hb=788adb3977209d98934788e18f330ec1549b596b;hp=8f8dac51b37e65c70339578c019f6f86f4d5367f;hpb=bd6ce8f5f9fc8e5bc8a6188d15987ce0ffd2c1ee;p=jalview.git diff --git a/src/jalview/workers/InformationThread.java b/src/jalview/workers/InformationThread.java index 8f8dac5..c8084b9 100644 --- a/src/jalview/workers/InformationThread.java +++ b/src/jalview/workers/InformationThread.java @@ -8,18 +8,25 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; 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.ArrayList; import java.util.List; +/** + * This class calculates HMM Information Content annotations, based on any HMM + * consensus sequences and their HMM models. HMM consensus sequences may be + * present for the whole alignment, or subgroups of it. + * + */ public class InformationThread extends AlignCalcWorker { - - Float max = 0f; + public static final String HMM_CALC_ID = "HMM"; /** - * Constructor for information thread. + * Constructor * * @param alignViewport * @param alignPanel @@ -30,139 +37,99 @@ public class InformationThread extends AlignCalcWorker super(alignViewport, alignPanel); } + /** + * Recomputes Information annotations for any HMM consensus sequences (for + * alignment and/or groups) + */ @Override public void run() { - if (calcMan.isPending(this)) + if (alignViewport.getAlignment().getHmmSequences().isEmpty()) { return; } - calcMan.notifyStart(this); - long started = System.currentTimeMillis(); - - List information = getInformationAnnotations(); - try + if (alignViewport.isClosed()) { - if ((information == null) || calcMan.isPending(this)) - { - calcMan.workerComplete(this); - return; - } - while (!calcMan.notifyWorking(this)) - { - // System.err.println("Thread - // (Information"+Thread.currentThread().getName()+") Waiting around."); - try - { - if (ap != null) - { - ap.paintAlignment(false, false); - } - Thread.sleep(200); - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - if (alignViewport.isClosed()) - { - abortAndDestroy(); - return; - } - AlignmentI alignment = alignViewport.getAlignment(); - - int aWidth = -1; - - if (alignment == null || (aWidth = alignment.getWidth()) < 0) - { - calcMan.workerComplete(this); - return; - } - - eraseInformation(aWidth); - computeInformation(alignment); - updateResultAnnotation(true); + abortAndDestroy(); + return; + } - if (ap != null) - { - ap.paintAlignment(true, true); - } - } catch (OutOfMemoryError error) - { - calcMan.disableWorker(this); - ap.raiseOOMWarning("calculating information", error); - } finally + AlignmentI alignment = alignViewport.getAlignment(); + int aWidth = alignment == null ? -1 : alignment.getWidth(); + if (aWidth < 0) { - calcMan.workerComplete(this); + return; } - } - /** - * Clear out any existing information annotations - * - * @param aWidth - * the width (number of columns) of the annotated alignment - */ - protected void eraseInformation(int aWidth) - { + /* + * compute information profiles for any HMM consensus sequences + * for the alignment or sub-groups + */ + computeProfiles(alignment); + + /* + * construct the corresponding annotations + */ + updateAnnotation(); - List information = getInformationAnnotations(); - for (AlignmentAnnotation info : information) + if (ap != null) { - info.annotations = new Annotation[aWidth]; + ap.adjustAnnotationHeight(); + ap.paintAlignment(true, true); } } /** - * Computes the profiles from a HMM for an alignment. + * Computes HMM profiles for any HMM consensus sequences (for alignment or + * 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 computeInformation(AlignmentI alignment) + protected void computeProfiles(AlignmentI alignment) { int width = alignment.getWidth(); - List hmmSeqs = alignment.getHMMConsensusSequences(false); - int index = 0; - for (SequenceI seq : hmmSeqs) + /* + * alignment HMM profile + */ + List seqs = alignment.getHmmSequences(); + if (!seqs.isEmpty()) { - HiddenMarkovModel hmm = seq.getHMM(); - ProfilesI hinformation = AAFrequency.calculateHMMProfiles(hmm, width, - 0, width, true, alignViewport.isIgnoreBelowBackground(), + HiddenMarkovModel hmm = seqs.get(0).getHMM(); + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, + 0, width, alignViewport.isIgnoreBelowBackground(), alignViewport.isInfoLetterHeight()); - alignViewport.setSequenceInformationHash(hinformation, index); - // setColourSchemeInformation(hinformation); - index++; + alignViewport.setHmmProfiles(hmmProfiles); } - } - /** - * gets the sequences on the alignment on the viewport. - * - * @return - */ - protected SequenceI[] getSequences() - { - return alignViewport.getAlignment().getSequencesArray(); - } - - protected void setColourSchemeInformation(ProfilesI information) - { - ResidueShaderI cs = alignViewport.getResidueShading(); - if (cs != null) + /* + * group HMM profiles + */ + List groups = alignment.getGroups(); + for (SequenceGroup group : groups) { - cs.setInformation(information); + seqs = group.getHmmSequences(); + if (!seqs.isEmpty()) + { + HiddenMarkovModel hmm = seqs.get(0).getHMM(); + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, + 0, width, group.isIgnoreBelowBackground(), + group.isUseInfoLetterHeight()); + group.setHmmProfiles(hmmProfiles); + } } } /** - * Get the Information annotation for the alignment + * gets the sequences on the alignment on the viewport. * * @return */ - protected List getInformationAnnotations() + protected SequenceI[] getSequences() { - return alignViewport.getInformationAnnotations(); + return alignViewport.getAlignment().getSequencesArray(); } /** @@ -172,65 +139,146 @@ public class InformationThread extends AlignCalcWorker */ protected AlignmentAnnotation getGapAnnotation() { - return alignViewport.getAlignmentGapAnnotation(); + return alignViewport.getAlignmentGapAnnotation(); } /** - * update the information annotation from the sequence profile data using - * current visualization 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); - } + AlignmentI alignment = alignViewport.getAlignment(); - /** - * Derives the information content for an information annotation. - * - * @param immediate - */ - public void updateResultAnnotation(boolean immediate) - { - List annots = getInformationAnnotations(); - int index = 0; - for (AlignmentAnnotation information : annots) + float maxInformation = 0f; + List infos = new ArrayList<>(); + + /* + * annotation for alignment HMM consensus if present + */ + List hmmSeqs = alignment.getHmmSequences(); + if (!hmmSeqs.isEmpty()) { - ProfilesI hinformation = (ProfilesI) getSequenceInformation(index); - if (immediate || !calcMan.isWorking(this) && information != null - && hinformation != null) + ProfilesI profile = alignViewport.getHmmProfiles(); + float m = updateInformationAnnotation(hmmSeqs.get(0), profile, null, + infos); + maxInformation = Math.max(maxInformation, m); + } + + /* + * annotation for group HMM consensus if present + */ + for (SequenceGroup group : alignment.getGroups()) + { + hmmSeqs = group.getHmmSequences(); + if (!hmmSeqs.isEmpty()) { - deriveInformation(information, hinformation); + ProfilesI profiles = group.getHmmProfiles(); + float m = updateInformationAnnotation(hmmSeqs.get(0), profiles, + group, infos); + maxInformation = Math.max(maxInformation, m); } - index++; + } + + /* + * maxInformation holds the maximum value of information score; + * set this as graphMax in all annotations to scale them all the same + */ + for (AlignmentAnnotation ann : infos) + { + ann.graphMax = maxInformation; } } /** - * Convert the computed information data into the desired annotation for - * display. + * 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. The + * updated annotation is added to the infos list. Answers the + * maximum information content value of any annotation (for use as a scaling + * factor for display). * - * @param informationAnnotation - * the annotation to be populated - * @param hinformation - * the computed information data + * @param seq + * @param profile + * @param group + * @param infos + * @return */ - protected void deriveInformation( - AlignmentAnnotation informationAnnotation, ProfilesI hinformation) + protected float updateInformationAnnotation(SequenceI seq, + ProfilesI profile, SequenceGroup group, + List infos) { - long nseq = getSequences().length; - max = AAFrequency.completeInformation(informationAnnotation, - hinformation, hinformation.getStartColumn(), - hinformation.getEndColumn() + 1, nseq, max); + if (seq == null || profile == null) + { + return 0f; + } + + AlignmentAnnotation ann = findOrCreateAnnotation(seq, group); + + seq.addAlignmentAnnotation(ann); + infos.add(ann); + + float max = AAFrequency.completeInformation(ann, profile, + profile.getStartColumn(), profile.getEndColumn() + 1); + + return max; } /** - * Get the information data stored on the viewport. + * 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 seq + * @param group * @return */ - protected Object getSequenceInformation(int index) + AlignmentAnnotation findOrCreateAnnotation(SequenceI seq, + SequenceGroup group) { - return alignViewport.getSequenceInformationHash(index); + /* + * 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); + info.label = seq.getName(); // in case group name changed! + 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; } }