Merge branch 'bug/JAL-3072scrollThread' into merge/JAL-3072_3073
[jalview.git] / src / jalview / viewmodel / PCAModel.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.viewmodel;
22
23 import jalview.analysis.PCA;
24 import jalview.api.RotatableCanvasI;
25 import jalview.api.analysis.ScoreModelI;
26 import jalview.api.analysis.SimilarityParamsI;
27 import jalview.datamodel.AlignmentView;
28 import jalview.datamodel.Point;
29 import jalview.datamodel.SequenceI;
30 import jalview.datamodel.SequencePoint;
31
32 import java.util.List;
33 import java.util.Vector;
34
35 public class PCAModel
36 {
37   /*
38    * inputs
39    */
40   private AlignmentView inputData;
41
42   private final SequenceI[] seqs;
43
44   private final SimilarityParamsI similarityParams;
45
46   /*
47    * options - score model, nucleotide / protein
48    */
49   private ScoreModelI scoreModel;
50
51   private boolean nucleotide = false;
52
53   /*
54    * outputs
55    */
56   private PCA pca;
57
58   int top;
59
60   private List<SequencePoint> points;
61
62   /**
63    * Constructor given sequence data, score model and score calculation
64    * parameter options.
65    * 
66    * @param seqData
67    * @param sqs
68    * @param nuc
69    * @param modelName
70    * @param params
71    */
72   public PCAModel(AlignmentView seqData, SequenceI[] sqs, boolean nuc,
73           ScoreModelI modelName, SimilarityParamsI params)
74   {
75     inputData = seqData;
76     seqs = sqs;
77     nucleotide = nuc;
78     scoreModel = modelName;
79     similarityParams = params;
80   }
81
82   /**
83    * Performs the PCA calculation (in the same thread) and extracts result data
84    * needed for visualisation by PCAPanel
85    */
86   public void calculate()
87   {
88     pca = new PCA(inputData, scoreModel, similarityParams);
89     pca.run(); // executes in same thread, wait for completion
90
91     // Now find the component coordinates
92     int ii = 0;
93
94     while ((ii < seqs.length) && (seqs[ii] != null))
95     {
96       ii++;
97     }
98
99     int height = pca.getHeight();
100     // top = pca.getM().height() - 1;
101     top = height - 1;
102
103     points = new Vector<>();
104     Point[] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
105
106     for (int i = 0; i < height; i++)
107     {
108       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
109       points.add(sp);
110     }
111   }
112
113   public void updateRc(RotatableCanvasI rc)
114   {
115     rc.setPoints(points, pca.getHeight());
116   }
117
118   public boolean isNucleotide()
119   {
120     return nucleotide;
121   }
122
123   public void setNucleotide(boolean nucleotide)
124   {
125     this.nucleotide = nucleotide;
126   }
127
128   /**
129    * Answers the index of the principal dimension of the PCA
130    * 
131    * @return
132    */
133   public int getTop()
134   {
135     return top;
136   }
137
138   public void setTop(int t)
139   {
140     top = t;
141   }
142
143   /**
144    * Updates the 3D coordinates for the list of points to the given dimensions.
145    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
146    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero,
147    * rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 ..)
148    * 
149    * @param dim1
150    * @param dim2
151    * @param dim3
152    */
153   public void updateRcView(int dim1, int dim2, int dim3)
154   {
155     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
156     Point[] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
157
158     for (int i = 0; i < pca.getHeight(); i++)
159     {
160       points.get(i).coord = scores[i];
161     }
162   }
163
164   public String getDetails()
165   {
166     return pca.getDetails();
167   }
168
169   public AlignmentView getInputData()
170   {
171     return inputData;
172   }
173
174   public void setInputData(AlignmentView data)
175   {
176     inputData = data;
177   }
178
179   public String getPointsasCsv(boolean transformed, int xdim, int ydim,
180           int zdim)
181   {
182     StringBuffer csv = new StringBuffer();
183     csv.append("\"Sequence\"");
184     if (transformed)
185     {
186       csv.append(",");
187       csv.append(xdim);
188       csv.append(",");
189       csv.append(ydim);
190       csv.append(",");
191       csv.append(zdim);
192     }
193     else
194     {
195       for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
196       {
197         csv.append("," + d);
198       }
199     }
200     csv.append("\n");
201     for (int s = 0; s < seqs.length; s++)
202     {
203       csv.append("\"" + seqs[s].getName() + "\"");
204       double fl[];
205       if (!transformed)
206       {
207         // output pca in correct order
208         fl = pca.component(s);
209         for (int d = fl.length - 1; d >= 0; d--)
210         {
211           csv.append(",");
212           csv.append(fl[d]);
213         }
214       }
215       else
216       {
217         Point p = points.get(s).coord;
218         csv.append(",").append(p.x);
219         csv.append(",").append(p.y);
220         csv.append(",").append(p.z);
221       }
222       csv.append("\n");
223     }
224     return csv.toString();
225   }
226
227   public String getScoreModelName()
228   {
229     return scoreModel == null ? "" : scoreModel.getName();
230   }
231
232   public void setScoreModel(ScoreModelI sm)
233   {
234     this.scoreModel = sm;
235   }
236
237   /**
238    * Answers the parameters configured for pairwise similarity calculations
239    * 
240    * @return
241    */
242   public SimilarityParamsI getSimilarityParameters()
243   {
244     return similarityParams;
245   }
246
247   public List<SequencePoint> getSequencePoints()
248   {
249     return points;
250   }
251
252   public void setSequencePoints(List<SequencePoint> sp)
253   {
254     points = sp;
255   }
256
257   /**
258    * Answers the object holding the values of the computed PCA
259    * 
260    * @return
261    */
262   public PCA getPcaData()
263   {
264     return pca;
265   }
266
267   public void setPCA(PCA data)
268   {
269     pca = data;
270   }
271 }