JAL-1503 update version in GPL header
[jalview.git] / src / jalview / viewmodel / PCAModel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
3  * Copyright (C) 2014 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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.viewmodel;
20
21 import java.util.Vector;
22
23 import jalview.analysis.PCA;
24 import jalview.datamodel.AlignmentView;
25 import jalview.datamodel.SequenceI;
26 import jalview.datamodel.SequencePoint;
27 import jalview.api.RotatableCanvasI;
28
29 public class PCAModel
30 {
31
32   public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
33           boolean nucleotide2)
34   {
35     seqstrings = seqstrings2;
36     seqs = seqs2;
37     nucleotide = nucleotide2;
38     score_matrix = nucleotide2 ? "PID" : "BLOSUM62";
39   }
40
41   private volatile PCA pca;
42
43   int top;
44
45   AlignmentView seqstrings;
46
47   SequenceI[] seqs;
48   
49   /**
50    * Score matrix used to calculate PC
51    */
52   String score_matrix;
53
54   /**
55    * use the identity matrix for calculating similarity between sequences.
56    */
57   private boolean nucleotide = false;
58
59   private Vector<SequencePoint> points;
60
61   private boolean jvCalcMode = true;
62
63   public boolean isJvCalcMode()
64   {
65     return jvCalcMode;
66   }
67
68   public void run()
69   {
70
71     pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide, score_matrix);
72     pca.setJvCalcMode(jvCalcMode);
73     pca.run();
74
75     // Now find the component coordinates
76     int ii = 0;
77
78     while ((ii < seqs.length) && (seqs[ii] != null))
79     {
80       ii++;
81     }
82
83     double[][] comps = new double[ii][ii];
84
85     for (int i = 0; i < ii; i++)
86     {
87       if (pca.getEigenvalue(i) > 1e-4)
88       {
89         comps[i] = pca.component(i);
90       }
91     }
92
93     top = pca.getM().rows - 1;
94
95     points = new Vector<SequencePoint>();
96     float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
97
98     for (int i = 0; i < pca.getM().rows; i++)
99     {
100       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
101       points.addElement(sp);
102     }
103
104   }
105
106   public void updateRc(RotatableCanvasI rc)
107   {
108     rc.setPoints(points, pca.getM().rows);
109   }
110
111   public boolean isNucleotide()
112   {
113     return nucleotide;
114   }
115
116   public void setNucleotide(boolean nucleotide)
117   {
118     this.nucleotide = nucleotide;
119   }
120
121   /**
122    * 
123    * 
124    * @return index of principle dimension of PCA
125    */
126   public int getTop()
127   {
128     return top;
129   }
130
131   /**
132    * update the 2d coordinates for the list of points to the given dimensions
133    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
134    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero,
135    * rather than rank-1, so getComponents(dimN ...) == updateRcView(dimN+1 ..)
136    * 
137    * @param dim1
138    * @param dim2
139    * @param dim3
140    */
141   public void updateRcView(int dim1, int dim2, int dim3)
142   {
143     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
144     float[][] scores = pca.getComponents(dim1 - 1, dim2 - 1, dim3 - 1, 100);
145
146     for (int i = 0; i < pca.getM().rows; i++)
147     {
148       ((SequencePoint) points.elementAt(i)).coord = scores[i];
149     }
150   }
151
152   public String getDetails()
153   {
154     return pca.getDetails();
155   }
156
157   public AlignmentView getSeqtrings()
158   {
159     return seqstrings;
160   }
161
162   public String getPointsasCsv(boolean transformed, int xdim, int ydim,
163           int zdim)
164   {
165     StringBuffer csv = new StringBuffer();
166     csv.append("\"Sequence\"");
167     if (transformed)
168     {
169       csv.append(",");
170       csv.append(xdim);
171       csv.append(",");
172       csv.append(ydim);
173       csv.append(",");
174       csv.append(zdim);
175     }
176     else
177     {
178       for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
179       {
180         csv.append("," + d);
181       }
182     }
183     csv.append("\n");
184     for (int s = 0; s < seqs.length; s++)
185     {
186       csv.append("\"" + seqs[s].getName() + "\"");
187       double fl[];
188       if (!transformed)
189       {
190         // output pca in correct order
191         fl = pca.component(s);
192         for (int d = fl.length - 1; d >= 0; d--)
193         {
194           csv.append(",");
195           csv.append(fl[d]);
196         }
197       }
198       else
199       {
200         // output current x,y,z coords for points
201         fl = getPointPosition(s);
202         for (int d = 0; d < fl.length; d++)
203         {
204           csv.append(",");
205           csv.append(fl[d]);
206         }
207       }
208       csv.append("\n");
209     }
210     return csv.toString();
211   }
212
213   /**
214    * 
215    * @return x,y,z positions of point s (index into points) under current
216    *         transform.
217    */
218   public double[] getPointPosition(int s)
219   {
220     double pts[] = new double[3];
221     float[] p = points.elementAt(s).coord;
222     pts[0] = p[0];
223     pts[1] = p[1];
224     pts[2] = p[2];
225     return pts;
226   }
227
228   public void setJvCalcMode(boolean state)
229   {
230     jvCalcMode = state;
231   }
232
233   public String getScore_matrix()
234   {
235     return score_matrix;
236   }
237
238   public void setScore_matrix(String score_matrix)
239   {
240     this.score_matrix = score_matrix;
241   }
242   
243 }