Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.workers

File InformationThread.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
20% of files have more coverage

Code metrics

26
74
8
1
284
164
23
0.31
9.25
8
2.88

Classes

Class Line # Actions
InformationThread 24 74 23
0.722222272.2%
 

Contributing tests

This file is covered by 213 tests. .

Source view

1    package jalview.workers;
2   
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;
14   
15    import java.util.ArrayList;
16    import java.util.List;
17   
18    /**
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.
22    *
23    */
 
24    public class InformationThread extends AlignCalcWorker
25    {
26    public static final String HMM_CALC_ID = "HMM";
27   
28    /**
29    * Constructor
30    *
31    * @param alignViewport
32    * @param alignPanel
33    */
 
34  482 toggle public InformationThread(AlignViewportI alignViewport,
35    AlignmentViewPanel alignPanel)
36    {
37  482 super(alignViewport, alignPanel);
38    }
39   
40    /**
41    * Recomputes Information annotations for any HMM consensus sequences (for
42    * alignment and/or groups)
43    */
 
44  903 toggle @Override
45    public void run()
46    {
47  903 if (alignViewport.getAlignment().getHmmSequences().isEmpty())
48    {
49  898 return;
50    }
51  5 if (alignViewport.isClosed())
52    {
53  0 abortAndDestroy();
54  0 return;
55    }
56   
57  5 AlignmentI alignment = alignViewport.getAlignment();
58  5 int aWidth = alignment == null ? -1 : alignment.getWidth();
59  5 if (aWidth < 0)
60    {
61  0 return;
62    }
63   
64    /*
65    * compute information profiles for any HMM consensus sequences
66    * for the alignment or sub-groups
67    */
68  5 computeProfiles(alignment);
69   
70    /*
71    * construct the corresponding annotations
72    */
73  5 updateAnnotation();
74   
75  5 if (ap != null)
76    {
77  5 ap.adjustAnnotationHeight();
78  5 ap.paintAlignment(true, true);
79    }
80    }
81   
82    /**
83    * Computes HMM profiles for any HMM consensus sequences (for alignment or
84    * subgroups). Any alignment profile computed is stored on the viewport, any
85    * group profile computed is stored on the respective sequence group.
86    *
87    * @param alignment
88    * @see AlignViewportI#setHmmProfiles(ProfilesI)
89    */
 
90  5 toggle protected void computeProfiles(AlignmentI alignment)
91    {
92  5 int width = alignment.getWidth();
93   
94    /*
95    * alignment HMM profile
96    */
97  5 List<SequenceI> seqs = alignment.getHmmSequences();
98  5 if (!seqs.isEmpty())
99    {
100  5 HiddenMarkovModel hmm = seqs.get(0).getHMM();
101  5 ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
102    0, width, alignViewport.isIgnoreBelowBackground(),
103    alignViewport.isInfoLetterHeight());
104  5 alignViewport.setHmmProfiles(hmmProfiles);
105    }
106   
107    /*
108    * group HMM profiles
109    */
110  5 List<SequenceGroup> groups = alignment.getGroups();
111  5 for (SequenceGroup group : groups)
112    {
113  0 seqs = group.getHmmSequences();
114  0 if (!seqs.isEmpty())
115    {
116  0 HiddenMarkovModel hmm = seqs.get(0).getHMM();
117  0 ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
118    0, width, group.isIgnoreBelowBackground(),
119    group.isUseInfoLetterHeight());
120  0 group.setHmmProfiles(hmmProfiles);
121    }
122    }
123    }
124   
125    /**
126    * gets the sequences on the alignment on the viewport.
127    *
128    * @return
129    */
 
130  0 toggle protected SequenceI[] getSequences()
131    {
132  0 return alignViewport.getAlignment().getSequencesArray();
133    }
134   
135    /**
136    * Get the Gap annotation for the alignment
137    *
138    * @return
139    */
 
140  0 toggle protected AlignmentAnnotation getGapAnnotation()
141    {
142  0 return alignViewport.getAlignmentGapAnnotation();
143    }
144   
145    /**
146    * Computes Information Content annotation for any HMM consensus sequences
147    * (for alignment or groups), and updates (or adds) the annotation to the
148    * sequence and the alignment
149    */
 
150  5 toggle @Override
151    public void updateAnnotation()
152    {
153  5 AlignmentI alignment = alignViewport.getAlignment();
154   
155  5 float maxInformation = 0f;
156  5 List<AlignmentAnnotation> infos = new ArrayList<>();
157   
158    /*
159    * annotation for alignment HMM consensus if present
160    */
161  5 List<SequenceI> hmmSeqs = alignment.getHmmSequences();
162  5 if (!hmmSeqs.isEmpty())
163    {
164  5 ProfilesI profile = alignViewport.getHmmProfiles();
165  5 float m = updateInformationAnnotation(hmmSeqs.get(0), profile, null,
166    infos);
167  5 maxInformation = Math.max(maxInformation, m);
168    }
169   
170    /*
171    * annotation for group HMM consensus if present
172    */
173  5 for (SequenceGroup group : alignment.getGroups())
174    {
175  0 hmmSeqs = group.getHmmSequences();
176  0 if (!hmmSeqs.isEmpty())
177    {
178  0 ProfilesI profiles = group.getHmmProfiles();
179  0 float m = updateInformationAnnotation(hmmSeqs.get(0), profiles,
180    group, infos);
181  0 maxInformation = Math.max(maxInformation, m);
182    }
183    }
184   
185    /*
186    * maxInformation holds the maximum value of information score;
187    * set this as graphMax in all annotations to scale them all the same
188    */
189  5 for (AlignmentAnnotation ann : infos)
190    {
191  5 ann.graphMax = maxInformation;
192    }
193    }
194   
195    /**
196    * Updates (and first constructs if necessary) an HMM Profile information
197    * content annotation for a sequence. The <code>group</code> argument is null
198    * for the whole alignment annotation, not null for a subgroup annotation. The
199    * updated annotation is added to the <code>infos</code> list. Answers the
200    * maximum information content value of any annotation (for use as a scaling
201    * factor for display).
202    *
203    * @param seq
204    * @param profile
205    * @param group
206    * @param infos
207    * @return
208    */
 
209  5 toggle protected float updateInformationAnnotation(SequenceI seq,
210    ProfilesI profile, SequenceGroup group,
211    List<AlignmentAnnotation> infos)
212    {
213  5 if (seq == null || profile == null)
214    {
215  0 return 0f;
216    }
217   
218  5 AlignmentAnnotation ann = findOrCreateAnnotation(seq, group);
219   
220  5 seq.addAlignmentAnnotation(ann);
221  5 infos.add(ann);
222   
223  5 float max = AAFrequency.completeInformation(ann, profile,
224    profile.getStartColumn(), profile.getEndColumn() + 1);
225   
226  5 return max;
227    }
228   
229    /**
230    * A helper method that first searches for the HMM annotation that matches the
231    * group reference (null for the whole alignment annotation). If found, its
232    * sequence reference is updated to the given sequence (the recomputed HMM
233    * consensus sequence). If not found, it is created. This supports both
234    * creating the annotation the first time hmmbuild is run, and updating it if
235    * hmmbuild is re-run.
236    *
237    * @param seq
238    * @param group
239    * @return
240    */
 
241  5 toggle AlignmentAnnotation findOrCreateAnnotation(SequenceI seq,
242    SequenceGroup group)
243    {
244    /*
245    * can't use Alignment.findOrCreateAnnotation here because we
246    * want to update, rather than match on, the sequence ref
247    */
248  5 AlignmentAnnotation info = null;
249   
250  5 AlignmentI alignment = alignViewport.getAlignment();
251  5 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
252  5 if (anns != null)
253    {
254  5 for (AlignmentAnnotation ann : anns)
255    {
256  11 if (HMM_CALC_ID.equals(ann.getCalcId()) && group == ann.groupRef)
257    {
258  3 info = ann;
259  3 info.setSequenceRef(seq);
260  3 info.label = seq.getName(); // in case group name changed!
261  3 break;
262    }
263    }
264    }
265   
266  5 if (info == null)
267    {
268  2 int aWidth = alignment.getWidth();
269  2 String desc = MessageManager
270    .getString("label.information_description");
271  2 float graphMax = 6.52f; // todo where does this value derive from?
272  2 info = new AlignmentAnnotation(seq.getName(), desc,
273    new Annotation[aWidth], 0f, graphMax,
274    AlignmentAnnotation.BAR_GRAPH);
275  2 info.setCalcId(HMM_CALC_ID);
276  2 info.setSequenceRef(seq);
277  2 info.groupRef = group;
278  2 info.hasText = true;
279  2 alignment.addAnnotation(info);
280    }
281   
282  5 return info;
283    }
284    }