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