JAL - 3690 AlignCalc rebuilt - FutureTask-based manager
[jalview.git] / src / jalview / workers / ConsensusThread.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.workers;
22
23 import jalview.analysis.AAFrequency;
24 import jalview.api.AlignViewportI;
25 import jalview.api.AlignmentViewPanel;
26 import jalview.datamodel.AlignmentAnnotation;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.Annotation;
29 import jalview.datamodel.ProfilesI;
30 import jalview.datamodel.SequenceI;
31 import jalview.renderer.ResidueShaderI;
32
33 public class ConsensusThread extends AlignCalcWorker
34 {
35   public ConsensusThread(AlignViewportI alignViewport,
36           AlignmentViewPanel alignPanel)
37   {
38     super(alignViewport, alignPanel);
39   }
40
41   @Override
42   public void run()
43   {
44     AlignmentAnnotation consensus = getConsensusAnnotation();
45     AlignmentAnnotation gap = getGapAnnotation();
46     if ((consensus == null && gap == null))
47     {
48       return;
49     }
50     if (alignViewport.isClosed())
51     {
52       abortAndDestroy();
53       return;
54     }
55     AlignmentI alignment = alignViewport.getAlignment();
56
57     int aWidth = -1;
58
59     if (alignment == null || (aWidth = alignment.getWidth()) < 0)
60     {
61       return;
62     }
63
64     eraseConsensus(aWidth);
65     computeConsensus(alignment);
66     updateResultAnnotation(true);
67
68     if (ap != null)
69     {
70       ap.paintAlignment(true, true);
71     }
72   }
73
74   /**
75    * Clear out any existing consensus annotations
76    * 
77    * @param aWidth
78    *          the width (number of columns) of the annotated alignment
79    */
80   protected void eraseConsensus(int aWidth)
81   {
82     AlignmentAnnotation consensus = getConsensusAnnotation();
83     if (consensus != null)
84     {
85       consensus.annotations = new Annotation[aWidth];
86     }
87     AlignmentAnnotation gap = getGapAnnotation();
88     if (gap != null)
89     {
90       gap.annotations = new Annotation[aWidth];
91     }
92   }
93
94   /**
95    * @param alignment
96    */
97   protected void computeConsensus(AlignmentI alignment)
98   {
99
100     SequenceI[] aseqs = getSequences();
101     int width = alignment.getWidth();
102     ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width,
103             true);
104
105     alignViewport.setSequenceConsensusHash(hconsensus);
106     setColourSchemeConsensus(hconsensus);
107   }
108
109   /**
110    * @return
111    */
112   protected SequenceI[] getSequences()
113   {
114     return alignViewport.getAlignment().getSequencesArray();
115   }
116
117   /**
118    * @param hconsensus
119    */
120   protected void setColourSchemeConsensus(ProfilesI hconsensus)
121   {
122     ResidueShaderI cs = alignViewport.getResidueShading();
123     if (cs != null)
124     {
125       cs.setConsensus(hconsensus);
126     }
127   }
128
129   /**
130    * Get the Consensus annotation for the alignment
131    * 
132    * @return
133    */
134   protected AlignmentAnnotation getConsensusAnnotation()
135   {
136     return alignViewport.getAlignmentConsensusAnnotation();
137   }
138
139   /**
140    * Get the Gap annotation for the alignment
141    * 
142    * @return
143    */
144   protected AlignmentAnnotation getGapAnnotation()
145   {
146     return alignViewport.getAlignmentGapAnnotation();
147   }
148
149   /**
150    * update the consensus annotation from the sequence profile data using
151    * current visualization settings.
152    */
153   @Override
154   public void updateAnnotation()
155   {
156     updateResultAnnotation(false);
157   }
158
159   public void updateResultAnnotation(boolean immediate)
160   {
161     AlignmentAnnotation consensus = getConsensusAnnotation();
162     ProfilesI hconsensus = (ProfilesI) getViewportConsensus();
163     if (immediate || !calcMan.isWorking(this) && consensus != null
164             && hconsensus != null)
165     {
166       deriveConsensus(consensus, hconsensus);
167       AlignmentAnnotation gap = getGapAnnotation();
168       if (gap != null)
169       {
170         deriveGap(gap, hconsensus);
171       }
172     }
173   }
174
175   /**
176    * Convert the computed consensus data into the desired annotation for
177    * display.
178    * 
179    * @param consensusAnnotation
180    *          the annotation to be populated
181    * @param hconsensus
182    *          the computed consensus data
183    */
184   protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
185           ProfilesI hconsensus)
186   {
187     long nseq = getSequences().length;
188     AAFrequency.completeConsensus(consensusAnnotation, hconsensus,
189             hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
190             alignViewport.isIgnoreGapsConsensus(),
191             alignViewport.isShowSequenceLogo(), nseq);
192   }
193
194   /**
195    * Convert the computed consensus data into a gap annotation row for display.
196    * 
197    * @param gapAnnotation
198    *          the annotation to be populated
199    * @param hconsensus
200    *          the computed consensus data
201    */
202   protected void deriveGap(AlignmentAnnotation gapAnnotation,
203           ProfilesI hconsensus)
204   {
205     long nseq = getSequences().length;
206     AAFrequency.completeGapAnnot(gapAnnotation, hconsensus,
207             hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
208             nseq);
209   }
210
211   /**
212    * Get the consensus data stored on the viewport.
213    * 
214    * @return
215    */
216   protected Object getViewportConsensus()
217   {
218     // TODO convert ComplementConsensusThread to use Profile
219     return alignViewport.getSequenceConsensusHash();
220   }
221 }