1 package jalview.workers;
3 import jalview.analysis.AAFrequency;
4 import jalview.api.AlignViewportI;
5 import jalview.api.AlignmentViewPanel;
6 import jalview.datamodel.AlignmentAnnotation;
7 import jalview.datamodel.AlignmentI;
8 import jalview.datamodel.Annotation;
9 import jalview.datamodel.HiddenMarkovModel;
10 import jalview.datamodel.ProfilesI;
11 import jalview.datamodel.SequenceGroup;
12 import jalview.datamodel.SequenceI;
13 import jalview.util.MessageManager;
15 import java.util.ArrayList;
16 import java.util.List;
19 * This class calculates HMM Information Content annotations, based on any HMM
20 * consensus sequences and their HMM models. HMM consensus sequences may be
21 * present for the whole alignment, or subgroups of it.
24 public class InformationThread extends AlignCalcWorker
26 public static final String HMM_CALC_ID = "HMM";
31 * @param alignViewport
34 public InformationThread(AlignViewportI alignViewport,
35 AlignmentViewPanel alignPanel)
37 super(alignViewport, alignPanel);
41 * Recomputes Information annotations for any HMM consensus sequences (for
42 * alignment and/or groups)
47 if (calcMan.isPending(this))
51 calcMan.notifyStart(this);
52 // long started = System.currentTimeMillis();
56 if (calcMan.isPending(this))
58 // another instance of this is waiting to run
59 calcMan.workerComplete(this);
62 while (!calcMan.notifyWorking(this))
64 // another thread in progress, wait my turn
69 ap.paintAlignment(false, false);
72 } catch (Exception ex)
77 if (alignViewport.isClosed())
83 AlignmentI alignment = alignViewport.getAlignment();
84 int aWidth = alignment == null ? -1 : alignment.getWidth();
87 calcMan.workerComplete(this);
92 * compute information profiles for any HMM consensus sequences
93 * for the alignment or sub-groups
95 computeProfiles(alignment);
98 * construct the corresponding annotations
104 ap.adjustAnnotationHeight();
105 ap.paintAlignment(true, true);
107 } catch (OutOfMemoryError error)
109 calcMan.disableWorker(this);
110 ap.raiseOOMWarning("calculating information", error);
113 calcMan.workerComplete(this);
118 * Computes HMM profiles for any HMM consensus sequences (for alignment or
119 * subgroups). Any alignment profile computed is stored on the viewport, any
120 * group profile computed is stored on the respective sequence group.
123 * @see AlignViewportI#setHmmProfiles(ProfilesI)
125 protected void computeProfiles(AlignmentI alignment)
127 int width = alignment.getWidth();
130 * alignment HMM profile
132 SequenceI seq = alignment.getHmmConsensus();
135 HiddenMarkovModel hmm = seq.getHMM();
136 ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
137 0, width, alignViewport.isIgnoreBelowBackground(),
138 alignViewport.isInfoLetterHeight());
139 alignViewport.setHmmProfiles(hmmProfiles);
145 List<SequenceGroup> groups = alignment.getGroups();
146 for (SequenceGroup group : groups)
148 seq = group.getHmmConsensus();
151 HiddenMarkovModel hmm = seq.getHMM();
152 ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
153 0, width, group.isIgnoreBelowBackground(),
154 group.isUseInfoLetterHeight());
155 group.setHmmProfiles(hmmProfiles);
161 * gets the sequences on the alignment on the viewport.
165 protected SequenceI[] getSequences()
167 return alignViewport.getAlignment().getSequencesArray();
171 * Get the Gap annotation for the alignment
175 protected AlignmentAnnotation getGapAnnotation()
177 return alignViewport.getOccupancyAnnotation();
181 * Computes Information Content annotation for any HMM consensus sequences
182 * (for alignment or groups), and updates (or adds) the annotation to the
183 * sequence and the alignment
186 public void updateAnnotation()
188 AlignmentI alignment = alignViewport.getAlignment();
190 float maxInformation = 0f;
191 List<AlignmentAnnotation> infos = new ArrayList<>();
194 * annotation for alignment HMM consensus if present
196 SequenceI hmmSeq = alignment.getHmmConsensus();
197 ProfilesI profile = alignViewport.getHmmProfiles();
198 float m = updateInformationAnnotation(hmmSeq, profile, null, infos);
199 maxInformation = Math.max(maxInformation, m);
202 * annotation for group HMM consensus if present
204 for (SequenceGroup group : alignment.getGroups())
206 hmmSeq = group.getHmmConsensus();
207 ProfilesI profiles = group.getHmmProfiles();
208 m = updateInformationAnnotation(hmmSeq, profiles, group, infos);
209 maxInformation = Math.max(maxInformation, m);
213 * maxInformation holds the maximum value of information score;
214 * set this as graphMax in all annotations to scale them all the same
216 for (AlignmentAnnotation ann : infos)
218 ann.graphMax = maxInformation;
223 * Updates (and first constructs if necessary) an HMM Profile information
224 * content annotation for a sequence. The <code>group</code> argument is null
225 * for the whole alignment annotation, not null for a subgroup annotation. The
226 * updated annotation is added to the <code>infos</code> list. Answers the
227 * maximum information content value of any annotation (for use as a scaling
228 * factor for display).
236 protected float updateInformationAnnotation(SequenceI seq,
237 ProfilesI profile, SequenceGroup group,
238 List<AlignmentAnnotation> infos)
240 if (seq == null || profile == null)
245 AlignmentAnnotation ann = findOrCreateAnnotation(seq, group);
247 seq.addAlignmentAnnotation(ann);
250 float max = AAFrequency.completeInformation(ann, profile,
251 profile.getStartColumn(), profile.getEndColumn() + 1);
257 * A helper method that first searches for the HMM annotation that matches the
258 * group reference (null for the whole alignment annotation). If found, its
259 * sequence reference is updated to the given sequence (the recomputed HMM
260 * consensus sequence). If not found, it is created. This supports both
261 * creating the annotation the first time hmmbuild is run, and updating it if
262 * hmmbuild is re-run.
268 AlignmentAnnotation findOrCreateAnnotation(SequenceI seq,
272 * can't use Alignment.findOrCreateAnnotation here because we
273 * want to update, rather than match on, the sequence ref
275 AlignmentAnnotation info = null;
277 AlignmentI alignment = alignViewport.getAlignment();
278 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
281 for (AlignmentAnnotation ann : anns)
283 if (HMM_CALC_ID.equals(ann.getCalcId()) && group == ann.groupRef)
286 info.setSequenceRef(seq);
287 info.label = seq.getName(); // in case group name changed!
295 int aWidth = alignment.getWidth();
296 String desc = MessageManager
297 .getString("label.information_description");
298 float graphMax = 6.52f; // todo where does this value derive from?
299 info = new AlignmentAnnotation(seq.getName(), desc,
300 new Annotation[aWidth], 0f, graphMax,
301 AlignmentAnnotation.BAR_GRAPH);
302 info.setCalcId(HMM_CALC_ID);
303 info.setSequenceRef(seq);
304 info.groupRef = group;
306 alignment.addAnnotation(info);