JAL-2629 add option to set HMM Logo letter height to info content
[jalview.git] / src / jalview / workers / InformationThread.java
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.SequenceI;
12 import jalview.renderer.ResidueShaderI;
13
14 import java.util.List;
15
16 public class InformationThread extends AlignCalcWorker
17 {
18   
19   Float max = 0f;
20   
21   /**
22    * Constructor for information thread.
23    * 
24    * @param alignViewport
25    * @param alignPanel
26    */
27   public InformationThread(AlignViewportI alignViewport,
28             AlignmentViewPanel alignPanel)
29     {
30       super(alignViewport, alignPanel);
31     }
32
33     @Override
34     public void run()
35     {
36       if (calcMan.isPending(this))
37       {
38         return;
39       }
40       calcMan.notifyStart(this);
41       long started = System.currentTimeMillis();
42
43     List<AlignmentAnnotation> information = getInformationAnnotations();
44       try
45       {
46       if ((information == null) || calcMan.isPending(this))
47         {
48           calcMan.workerComplete(this);
49           return;
50         }
51         while (!calcMan.notifyWorking(this))
52         {
53           // System.err.println("Thread
54         // (Information"+Thread.currentThread().getName()+") Waiting around.");
55           try
56           {
57             if (ap != null)
58             {
59               ap.paintAlignment(false);
60             }
61             Thread.sleep(200);
62           } catch (Exception ex)
63           {
64             ex.printStackTrace();
65           }
66         }
67         if (alignViewport.isClosed())
68         {
69           abortAndDestroy();
70           return;
71         }
72         AlignmentI alignment = alignViewport.getAlignment();
73
74         int aWidth = -1;
75
76         if (alignment == null || (aWidth = alignment.getWidth()) < 0)
77         {
78           calcMan.workerComplete(this);
79           return;
80         }
81
82       eraseInformation(aWidth);
83       computeInformation(alignment);
84         updateResultAnnotation(true);
85
86         if (ap != null)
87         {
88           ap.paintAlignment(true);
89         }
90       } catch (OutOfMemoryError error)
91       {
92         calcMan.disableWorker(this);
93       ap.raiseOOMWarning("calculating information", error);
94     } finally
95     {
96       calcMan.workerComplete(this);
97       }
98
99
100
101     }
102
103     /**
104    * Clear out any existing information annotations
105    * 
106    * @param aWidth
107    *          the width (number of columns) of the annotated alignment
108    */
109   protected void eraseInformation(int aWidth)
110     {
111
112     List<AlignmentAnnotation> information = getInformationAnnotations();
113     for (AlignmentAnnotation info : information)
114     {
115       info.annotations = new Annotation[aWidth];
116     }
117     }
118
119
120     /**
121    * Computes the profiles from a HMM for an alignment.
122    * 
123    * @param alignment
124    */
125   protected void computeInformation(AlignmentI alignment)
126     {
127
128       int width = alignment.getWidth();
129     List<SequenceI> hmmSeqs = alignment.getHMMConsensusSequences(false);
130     int index = 0;
131
132     for (SequenceI seq : hmmSeqs)
133     {
134       HiddenMarkovModel hmm = seq.getHMM();
135       ProfilesI hinformation = AAFrequency.calculateHMMProfiles(hmm, width,
136               0, width, true, alignViewport.isIgnoreBelowBackground(),
137               alignViewport.isInfoLetterHeight());
138       alignViewport.setSequenceInformationHash(hinformation, index);
139       // setColourSchemeInformation(hinformation);
140       index++;
141     }
142     }
143
144     /**
145    * gets the sequences on the alignment on the viewport.
146    * 
147    * @return
148    */
149     protected SequenceI[] getSequences()
150     {
151       return alignViewport.getAlignment().getSequencesArray();
152     }
153
154   protected void setColourSchemeInformation(ProfilesI information)
155     {
156       ResidueShaderI cs = alignViewport.getResidueShading();
157       if (cs != null)
158       {
159       cs.setInformation(information);
160       }
161     }
162
163     /**
164    * Get the Information annotation for the alignment
165    * 
166    * @return
167    */
168   protected List<AlignmentAnnotation> getInformationAnnotations()
169     {
170     return alignViewport.getInformationAnnotations();
171     }
172
173     /**
174      * Get the Gap annotation for the alignment
175      * 
176      * @return
177      */
178     protected AlignmentAnnotation getGapAnnotation()
179     {
180       return alignViewport.getAlignmentGapAnnotation();
181     }
182
183     /**
184    * update the information annotation from the sequence profile data using
185    * current visualization settings.
186    */
187     @Override
188     public void updateAnnotation()
189     {
190
191       updateResultAnnotation(false);
192     }
193
194   /**
195    * Derives the information content for an information annotation.
196    * 
197    * @param immediate
198    */
199     public void updateResultAnnotation(boolean immediate)
200     {
201     List<AlignmentAnnotation> annots = getInformationAnnotations();
202     int index = 0;
203     for (AlignmentAnnotation information : annots)
204     {
205       ProfilesI hinformation = (ProfilesI) getSequenceInformation(index);
206       if (immediate || !calcMan.isWorking(this) && information != null
207             && hinformation != null)
208       {
209         deriveInformation(information, hinformation);
210       }
211       index++;
212       }
213     }
214
215     /**
216    * Convert the computed information data into the desired annotation for
217    * display.
218    * 
219    * @param informationAnnotation
220    *          the annotation to be populated
221    * @param hinformation
222    *          the computed information data
223    */
224   protected void deriveInformation(
225           AlignmentAnnotation informationAnnotation, ProfilesI hinformation)
226     {
227       long nseq = getSequences().length;
228     max = AAFrequency.completeInformation(informationAnnotation,
229             hinformation, hinformation.getStartColumn(),
230             hinformation.getEndColumn() + 1, nseq, max);
231     }
232
233
234
235     /**
236    * Get the information data stored on the viewport.
237    * 
238    * @return
239    */
240   protected Object getSequenceInformation(int index)
241     {
242     // TODO convert ComplementInformationThread to use Profile
243     return alignViewport.getSequenceInformationHash(index);
244     }
245   }
246
247
248
249
250