JAL-1632 add score model params to PCAModel and PCA constructors
[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.analysis.scoremodels.ScoreModels;
25 import jalview.api.RotatableCanvasI;
26 import jalview.api.analysis.ScoreModelI;
27 import jalview.api.analysis.SimilarityParamsI;
28 import jalview.datamodel.AlignmentView;
29 import jalview.datamodel.SequenceI;
30 import jalview.datamodel.SequencePoint;
31
32 import java.util.Vector;
33
34 public class PCAModel
35 {
36   private volatile PCA pca;
37
38   int top;
39
40   AlignmentView seqstrings;
41
42   SequenceI[] seqs;
43
44   /*
45    * Score model used to calculate PCA
46    */
47   ScoreModelI scoreModel;
48
49   private boolean nucleotide = false;
50
51   private Vector<SequencePoint> points;
52
53   private boolean jvCalcMode = true;
54
55   private SimilarityParamsI similarityParams;
56
57   /**
58    * Constructor given sequence data and score calculation parameter options.
59    * The initial state is to compute PCA using a default score model (BLOSUM62
60    * for peptide, DNA for nucleotide).
61    * 
62    * @param seqData
63    * @param sqs
64    * @param nuc
65    * @param params
66    */
67   public PCAModel(AlignmentView seqData, SequenceI[] sqs, boolean nuc,
68           SimilarityParamsI params)
69   {
70     seqstrings = seqData;
71     seqs = sqs;
72     nucleotide = nuc;
73     scoreModel = ScoreModels.getInstance().getDefaultModel(!nucleotide);
74     similarityParams = params;
75   }
76
77   public boolean isJvCalcMode()
78   {
79     return jvCalcMode;
80   }
81
82   public void run()
83   {
84     pca = new PCA(seqstrings, scoreModel, similarityParams);
85     pca.setJvCalcMode(jvCalcMode);
86     pca.run();
87
88     // Now find the component coordinates
89     int ii = 0;
90
91     while ((ii < seqs.length) && (seqs[ii] != null))
92     {
93       ii++;
94     }
95
96     int height = pca.getHeight();
97     // top = pca.getM().height() - 1;
98     top = height - 1;
99
100     points = new Vector<SequencePoint>();
101     float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
102
103     for (int i = 0; i < height; i++)
104     {
105       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
106       points.addElement(sp);
107     }
108   }
109
110   public void updateRc(RotatableCanvasI rc)
111   {
112     rc.setPoints(points, pca.getHeight());
113   }
114
115   public boolean isNucleotide()
116   {
117     return nucleotide;
118   }
119
120   public void setNucleotide(boolean nucleotide)
121   {
122     this.nucleotide = nucleotide;
123   }
124
125   /**
126    * 
127    * 
128    * @return index of principle dimension of PCA
129    */
130   public int getTop()
131   {
132     return top;
133   }
134
135   /**
136    * update the 2d coordinates for the list of points to the given dimensions
137    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
138    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero,
139    * rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 ..)
140    * 
141    * @param dim1
142    * @param dim2
143    * @param dim3
144    */
145   public void updateRcView(int dim1, int dim2, int dim3)
146   {
147     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
148     float[][] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
149
150     for (int i = 0; i < pca.getHeight(); i++)
151     {
152       points.elementAt(i).coord = scores[i];
153     }
154   }
155
156   public String getDetails()
157   {
158     return pca.getDetails();
159   }
160
161   public AlignmentView getSeqtrings()
162   {
163     return seqstrings;
164   }
165
166   public String getPointsasCsv(boolean transformed, int xdim, int ydim,
167           int zdim)
168   {
169     StringBuffer csv = new StringBuffer();
170     csv.append("\"Sequence\"");
171     if (transformed)
172     {
173       csv.append(",");
174       csv.append(xdim);
175       csv.append(",");
176       csv.append(ydim);
177       csv.append(",");
178       csv.append(zdim);
179     }
180     else
181     {
182       for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
183       {
184         csv.append("," + d);
185       }
186     }
187     csv.append("\n");
188     for (int s = 0; s < seqs.length; s++)
189     {
190       csv.append("\"" + seqs[s].getName() + "\"");
191       double fl[];
192       if (!transformed)
193       {
194         // output pca in correct order
195         fl = pca.component(s);
196         for (int d = fl.length - 1; d >= 0; d--)
197         {
198           csv.append(",");
199           csv.append(fl[d]);
200         }
201       }
202       else
203       {
204         // output current x,y,z coords for points
205         fl = getPointPosition(s);
206         for (int d = 0; d < fl.length; d++)
207         {
208           csv.append(",");
209           csv.append(fl[d]);
210         }
211       }
212       csv.append("\n");
213     }
214     return csv.toString();
215   }
216
217   /**
218    * 
219    * @return x,y,z positions of point s (index into points) under current
220    *         transform.
221    */
222   public double[] getPointPosition(int s)
223   {
224     double pts[] = new double[3];
225     float[] p = points.elementAt(s).coord;
226     pts[0] = p[0];
227     pts[1] = p[1];
228     pts[2] = p[2];
229     return pts;
230   }
231
232   public void setJvCalcMode(boolean state)
233   {
234     jvCalcMode = state;
235   }
236
237   public String getScoreModelName()
238   {
239     return scoreModel == null ? "" : scoreModel.getName();
240   }
241
242   public void setScoreModel(ScoreModelI sm)
243   {
244     this.scoreModel = sm;
245   }
246
247 }