JAL-1179 - regression from JAL-1030 patch implicitly treats empty selection as null
[jalview.git] / src / jalview / viewmodel / PCAModel.java
1 package jalview.viewmodel;
2
3 import java.util.Vector;
4
5 import jalview.analysis.PCA;
6 import jalview.datamodel.AlignmentView;
7 import jalview.datamodel.SequenceI;
8 import jalview.datamodel.SequencePoint;
9 import jalview.api.RotatableCanvasI;
10
11 public class PCAModel
12 {
13
14   public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
15           boolean nucleotide2)
16   {
17     seqstrings=seqstrings2;
18     seqs=seqs2;
19     nucleotide=nucleotide2;
20   }
21
22   private volatile PCA pca;
23   
24   int top;
25   
26   AlignmentView seqstrings;
27
28   SequenceI[] seqs;
29
30   /**
31    * use the identity matrix for calculating similarity between sequences. 
32    */
33   private boolean nucleotide=false;
34
35   private Vector<SequencePoint> points;
36
37   private boolean jvCalcMode=true;
38
39   public boolean isJvCalcMode()
40   {
41     return jvCalcMode;
42   }
43
44   public void run()
45   {
46     
47     pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide);
48     pca.setJvCalcMode(jvCalcMode);
49     pca.run();
50
51     // Now find the component coordinates
52     int ii = 0;
53
54     while ((ii < seqs.length) && (seqs[ii] != null))
55     {
56       ii++;
57     }
58
59     double[][] comps = new double[ii][ii];
60
61     for (int i = 0; i < ii; i++)
62     {
63       if (pca.getEigenvalue(i) > 1e-4)
64       {
65         comps[i] = pca.component(i);
66       }
67     }
68
69     top = pca.getM().rows - 1;
70
71     points = new Vector<SequencePoint>();
72     float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
73
74     for (int i = 0; i < pca.getM().rows; i++)
75     {
76       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
77       points.addElement(sp);
78     }
79     
80   }
81
82   public void updateRc(RotatableCanvasI rc)
83   {
84     rc.setPoints(points, pca.getM().rows);
85   }
86
87   public boolean isNucleotide()
88   {
89     return nucleotide;
90   }
91   public void setNucleotide(boolean nucleotide)
92   {
93     this.nucleotide=nucleotide;
94   }
95
96   /**
97    * 
98    * 
99    * @return index of principle dimension of PCA
100    */
101   public int getTop()
102   {
103     return top;
104   }
105
106   /**
107    * update the 2d coordinates for the list of points to the given dimensions
108    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
109    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero, rather than rank-1, so getComponents(dimN ...)  == updateRcView(dimN+1 ..)  
110    * @param dim1 
111    * @param dim2
112    * @param dim3
113    */
114   public void updateRcView(int dim1, int dim2, int dim3)
115   {
116     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
117     float[][] scores = pca.getComponents(dim1-1, dim2-1, dim3-1, 100);
118
119     for (int i = 0; i < pca.getM().rows; i++)
120     {
121       ((SequencePoint) points.elementAt(i)).coord = scores[i];
122     }
123   }
124
125   public String getDetails()
126   {
127     return pca.getDetails();
128   }
129
130   public AlignmentView getSeqtrings()
131   {
132     return seqstrings;
133   }
134   public String getPointsasCsv(boolean transformed, int xdim, int ydim, int zdim)
135   {
136     StringBuffer csv = new StringBuffer();
137     csv.append("\"Sequence\"");
138     if (transformed)
139     {
140       csv.append(",");
141       csv.append(xdim);
142       csv.append(",");
143       csv.append(ydim);
144       csv.append(",");
145       csv.append(zdim);
146     }
147     else
148     {
149       for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
150       {
151         csv.append("," + d);
152       }
153     }
154     csv.append("\n");
155     for (int s = 0; s < seqs.length; s++)
156     {
157       csv.append("\"" + seqs[s].getName() + "\"");
158       double fl[];
159       if (!transformed)
160       {
161         // output pca in correct order
162         fl = pca.component(s);
163         for (int d = fl.length - 1; d >= 0; d--)
164         {
165           csv.append(",");
166           csv.append(fl[d]);
167         }
168       }
169       else
170       {
171         // output current x,y,z coords for points
172         fl = getPointPosition(s);
173         for (int d = 0; d < fl.length; d++)
174         {
175           csv.append(",");
176           csv.append(fl[d]);
177         }
178       }
179       csv.append("\n");
180     }
181     return csv.toString();
182   }
183
184   /**
185    * 
186    * @return x,y,z positions of point s (index into points) under current
187    *         transform.
188    */
189   public double[] getPointPosition(int s)
190   {
191     double pts[] = new double[3];
192     float[] p = points.elementAt(s).coord;
193     pts[0] = p[0];
194     pts[1] = p[1];
195     pts[2] = p[2];
196     return pts;
197   }
198
199   public void setJvCalcMode(boolean state)
200   {
201     jvCalcMode=state;
202   }
203
204 }