Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
PaSiMap | 44 | 68 | 29 |
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.analysis; | |
22 | ||
23 | import jalview.api.analysis.ScoreModelI; | |
24 | import jalview.api.analysis.SimilarityParamsI; | |
25 | import jalview.analysis.scoremodels.ScoreMatrix; | |
26 | import jalview.analysis.scoremodels.ScoreModels; | |
27 | import jalview.bin.Console; | |
28 | import jalview.datamodel.Point; | |
29 | import jalview.datamodel.SequenceI; | |
30 | import jalview.datamodel.SequenceGroup; | |
31 | import jalview.gui.PairwiseAlignPanel; | |
32 | import jalview.math.Matrix; | |
33 | import jalview.math.MatrixI; | |
34 | import jalview.viewmodel.AlignmentViewport; | |
35 | ||
36 | import java.io.PrintStream; | |
37 | import java.util.Hashtable; | |
38 | ||
39 | /** | |
40 | * Performs Principal Component Analysis on given sequences | |
41 | * | |
42 | * @AUTHOR MorellThomas | |
43 | */ | |
44 | public class PaSiMap implements Runnable | |
45 | { | |
46 | /* | |
47 | * inputs | |
48 | */ | |
49 | final private AlignmentViewport seqs; | |
50 | ||
51 | final private ScoreMatrix scoreMatrix; | |
52 | ||
53 | final private byte dim = 8; | |
54 | ||
55 | final private int openCost = 100; | |
56 | ||
57 | final private int extendCost = 5; | |
58 | ||
59 | /* | |
60 | * outputs | |
61 | */ | |
62 | final private PairwiseAlignPanel alignment; | |
63 | ||
64 | private boolean cancelled=false; | |
65 | ||
66 | private MatrixI pairwiseScores; | |
67 | ||
68 | private MatrixI eigenMatrix; | |
69 | ||
70 | private volatile boolean canCancel; | |
71 | ||
72 | /** | |
73 | * Constructor given the sequences to compute for, the similarity model to | |
74 | * use, and a set of parameters for sequence comparison | |
75 | * | |
76 | * @param sequences | |
77 | * @param sm | |
78 | * @param options | |
79 | */ | |
80 | 0 | public PaSiMap(AlignmentViewport sequences, ScoreModelI sm, |
81 | PairwiseAlignPanel pap) | |
82 | { | |
83 | 0 | this.seqs = sequences; |
84 | ||
85 | 0 | if (sm != null && sm instanceof ScoreMatrix) |
86 | { | |
87 | 0 | this.scoreMatrix = ((ScoreMatrix) sm); |
88 | } | |
89 | else | |
90 | { | |
91 | 0 | this.scoreMatrix = null; |
92 | } | |
93 | ||
94 | 0 | this.alignment = pap; |
95 | } | |
96 | ||
97 | /** | |
98 | * Returns Eigenvalue | |
99 | * | |
100 | * @param i | |
101 | * Index of diagonal within matrix | |
102 | * | |
103 | * @return Returns value of diagonal from matrix | |
104 | */ | |
105 | 0 | public double getEigenvalue(int i) |
106 | { | |
107 | 0 | return eigenMatrix.getD()[i]; |
108 | } | |
109 | ||
110 | /** | |
111 | * Returns coordinates for each datapoint | |
112 | * | |
113 | * @param l | |
114 | * DOCUMENT ME! | |
115 | * @param n | |
116 | * DOCUMENT ME! | |
117 | * @param mm | |
118 | * DOCUMENT ME! | |
119 | * @param factor | |
120 | * ~ is 1 | |
121 | * | |
122 | * @return DOCUMENT ME! | |
123 | */ | |
124 | 0 | public Point[] getComponents(int l, int n, int mm, float factor) |
125 | { | |
126 | 0 | Point[] out = new Point[getHeight()]; |
127 | ||
128 | 0 | for (int i = 0; i < out.length; i++) |
129 | { | |
130 | 0 | float x = (float) component(i, l) * factor; |
131 | 0 | float y = (float) component(i, n) * factor; |
132 | 0 | float z = (float) component(i, mm) * factor; |
133 | 0 | out[i] = new Point(x, y, z); |
134 | } | |
135 | ||
136 | 0 | return out; |
137 | } | |
138 | ||
139 | /** | |
140 | * DOCUMENT ME! | |
141 | * | |
142 | * @param n | |
143 | * DOCUMENT ME! | |
144 | * | |
145 | * @return DOCUMENT ME! | |
146 | */ | |
147 | 0 | public double[] component(int n) |
148 | { | |
149 | // n = index of eigenvector | |
150 | 0 | double[] out = new double[getWidth()]; |
151 | ||
152 | 0 | for (int i = 0; i < out.length; i++) |
153 | { | |
154 | 0 | out[i] = component(n, i); |
155 | } | |
156 | ||
157 | 0 | return out; |
158 | } | |
159 | ||
160 | /** | |
161 | * DOCUMENT ME! | |
162 | * | |
163 | * @param row | |
164 | * DOCUMENT ME! | |
165 | * @param n | |
166 | * DOCUMENT ME! | |
167 | * | |
168 | * @return DOCUMENT ME! | |
169 | */ | |
170 | 0 | double component(int row, int n) |
171 | { | |
172 | 0 | return eigenMatrix.getValue(row, n); |
173 | } | |
174 | ||
175 | /** | |
176 | * Answers a formatted text report of the PaSiMap calculation results | |
177 | * (matrices and eigenvalues) suitable for display | |
178 | * | |
179 | * @return | |
180 | */ | |
181 | 0 | public String getDetails() |
182 | { | |
183 | 0 | StringBuilder sb = new StringBuilder(1024); |
184 | 0 | sb.append("PaSiMap calculation using ").append(scoreMatrix.getName()) |
185 | .append(" sequence similarity matrix\n========\n\n"); | |
186 | 0 | PrintStream ps = wrapOutputBuffer(sb); |
187 | ||
188 | /* | |
189 | * coordinates matrix, with D vector | |
190 | */ | |
191 | 0 | sb.append(" --- Pairwise correlation coefficients ---\n"); |
192 | 0 | pairwiseScores.print(ps, "%8.6f "); |
193 | 0 | ps.println(); |
194 | ||
195 | 0 | sb.append(" --- Eigenvalues ---\n"); |
196 | 0 | eigenMatrix.printD(ps, "%15.4e"); |
197 | 0 | ps.println(); |
198 | ||
199 | 0 | sb.append(" --- Coordinates ---\n"); |
200 | 0 | eigenMatrix.print(ps, "%8.6f "); |
201 | 0 | ps.println(); |
202 | ||
203 | 0 | return sb.toString(); |
204 | } | |
205 | ||
206 | /** | |
207 | * Performs the PaSiMap calculation | |
208 | * | |
209 | * creates a new gui/PairwiseAlignPanel with the input sequences | |
210 | * (AlignmentViewport) | |
211 | * | |
212 | * uses analysis/AlignSeq to creatue the pairwise alignments and calculate the | |
213 | * AlignmentScores (float for each pair) | |
214 | * | |
215 | * gets all float[][] scores from the gui/PairwiseAlignPanel | |
216 | * | |
217 | * checks the connections for each sequence with AlignmentViewport | |
218 | * seqs.calculateConnectivity(float[][] scores, int dim) (from | |
219 | * analysis/Connectivity) -- throws an Exception if insufficient | |
220 | * | |
221 | * creates a math/MatrixI pairwiseScores of the float[][] scores | |
222 | * | |
223 | * copys the scores and fills the diagonal to create a symmetric matrix using | |
224 | * math/Matrix.fillDiagonal() | |
225 | * | |
226 | * performs the analysis/ccAnalysis with the symmetric matrix | |
227 | * | |
228 | * gets the eigenmatrix and the eigenvalues using math/Matrix.tqli() | |
229 | */ | |
230 | 0 | @Override |
231 | public void run() | |
232 | { | |
233 | 0 | canCancel=true; |
234 | 0 | try |
235 | { | |
236 | // alignment = new PairwiseAlignPanel(seqs, true, 100, 5); | |
237 | 0 | alignment.calculate(scoreMatrix); |
238 | 0 | if (alignment.isCancelled()) |
239 | { | |
240 | 0 | cancel(); |
241 | 0 | return; |
242 | } | |
243 | //alignment.setProgressMessage("Preparing to calculate pasimap..."); | |
244 | 0 | float[][] scores = alignment.getAlignmentScores(); // bigger index first |
245 | // -- eg scores[14][13] | |
246 | 0 | SequenceI[] iseqs = alignment.getInputSequences(); |
247 | 0 | Connectivity.getConnectivity(iseqs, scores, dim); |
248 | ||
249 | 0 | canCancel=false; |
250 | 0 | alignment.updateProgress(PairwiseAlignPanel.PROGRESSMESSAGE, "Creating the PaSiMap"); |
251 | 0 | pairwiseScores = new Matrix(scores); |
252 | 0 | pairwiseScores.fillDiagonal(); |
253 | ||
254 | 0 | eigenMatrix = pairwiseScores.copy(); |
255 | ||
256 | 0 | ccAnalysis cc = new ccAnalysis(pairwiseScores, dim); |
257 | 0 | eigenMatrix = cc.run().mirrorCol(); |
258 | 0 | alignment.updateProgress(PairwiseAlignPanel.PROGRESSCOMPLETE, "Finished PaSiMap."); |
259 | ||
260 | } catch (Exception q) | |
261 | { | |
262 | 0 | Console.error("Error computing PaSiMap: " + q.getMessage()); |
263 | 0 | q.printStackTrace(); |
264 | } | |
265 | } | |
266 | ||
267 | ||
268 | ||
269 | 0 | public void cancel() |
270 | { | |
271 | 0 | if (alignment!=null) |
272 | { | |
273 | 0 | alignment.cancel(); |
274 | } | |
275 | 0 | cancelled=true; |
276 | } | |
277 | ||
278 | 0 | public boolean isCancelled() |
279 | { | |
280 | 0 | return cancelled; |
281 | } | |
282 | ||
283 | /** | |
284 | * Returns a PrintStream that wraps (appends its output to) the given | |
285 | * StringBuilder | |
286 | * | |
287 | * @param sb | |
288 | * @return | |
289 | */ | |
290 | 0 | protected PrintStream wrapOutputBuffer(StringBuilder sb) |
291 | { | |
292 | 0 | PrintStream ps = new PrintStream(System.out) |
293 | { | |
294 | 0 | @Override |
295 | public void print(String x) | |
296 | { | |
297 | 0 | sb.append(x); |
298 | } | |
299 | ||
300 | 0 | @Override |
301 | public void println() | |
302 | { | |
303 | 0 | sb.append("\n"); |
304 | } | |
305 | }; | |
306 | 0 | return ps; |
307 | } | |
308 | ||
309 | /** | |
310 | * Answers the N dimensions of the NxM PaSiMap matrix. This is the number of | |
311 | * sequences involved in the pairwise score calculation. | |
312 | * | |
313 | * @return | |
314 | */ | |
315 | 0 | public int getHeight() |
316 | { | |
317 | // TODO can any of seqs[] be null? | |
318 | 0 | return eigenMatrix.height();// seqs.getSequences().length; |
319 | } | |
320 | ||
321 | /** | |
322 | * Answers the M dimensions of the NxM PaSiMap matrix. This is the number of | |
323 | * sequences involved in the pairwise score calculation. | |
324 | * | |
325 | * @return | |
326 | */ | |
327 | 0 | public int getWidth() |
328 | { | |
329 | // TODO can any of seqs[] be null? | |
330 | 0 | return eigenMatrix.width();// seqs.getSequences().length; |
331 | } | |
332 | ||
333 | /** | |
334 | * Answers the sequence pairwise similarity scores which were the first step | |
335 | * of the PaSiMap calculation | |
336 | * | |
337 | * @return | |
338 | */ | |
339 | 0 | public MatrixI getPairwiseScores() |
340 | { | |
341 | 0 | return pairwiseScores; |
342 | } | |
343 | ||
344 | 0 | public void setPairwiseScores(MatrixI m) |
345 | { | |
346 | 0 | pairwiseScores = m; |
347 | } | |
348 | ||
349 | 0 | public MatrixI getEigenmatrix() |
350 | { | |
351 | 0 | return eigenMatrix; |
352 | } | |
353 | ||
354 | 0 | public void setEigenmatrix(MatrixI m) |
355 | { | |
356 | 0 | eigenMatrix = m; |
357 | } | |
358 | ||
359 | 0 | public PairwiseAlignPanel getAlignments() |
360 | { | |
361 | 0 | return alignment; |
362 | } | |
363 | ||
364 | 0 | public String getAlignmentOutput() |
365 | { | |
366 | 0 | return alignment.getAlignmentOutput(); |
367 | } | |
368 | ||
369 | 0 | public byte getDim() |
370 | { | |
371 | 0 | return dim; |
372 | } | |
373 | ||
374 | /** | |
375 | * | |
376 | * @return true if pasimap calculation can (still) be interrupted | |
377 | */ | |
378 | 0 | public boolean isCancellable() |
379 | { | |
380 | 0 | return canCancel; |
381 | } | |
382 | } |