JAL-1123 - make clear where off-by-one error was occuring (patched problem in previou...
[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   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   public void run()
38   {
39     
40     pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide);
41     pca.run();
42
43     // Now find the component coordinates
44     int ii = 0;
45
46     while ((ii < seqs.length) && (seqs[ii] != null))
47     {
48       ii++;
49     }
50
51     double[][] comps = new double[ii][ii];
52
53     for (int i = 0; i < ii; i++)
54     {
55       if (pca.getEigenvalue(i) > 1e-4)
56       {
57         comps[i] = pca.component(i);
58       }
59     }
60
61     top = pca.getM().rows - 1;
62
63     points = new Vector<SequencePoint>();
64     float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
65
66     for (int i = 0; i < pca.getM().rows; i++)
67     {
68       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
69       points.addElement(sp);
70     }
71     
72   }
73
74   public void updateRc(RotatableCanvasI rc)
75   {
76     rc.setPoints(points, pca.getM().rows);
77   }
78
79   public boolean isNucleotide()
80   {
81     return nucleotide;
82   }
83   public void setNucleotide(boolean nucleotide)
84   {
85     this.nucleotide=nucleotide;
86   }
87
88   /**
89    * 
90    * 
91    * @return index of principle dimension of PCA
92    */
93   public int getTop()
94   {
95     return top;
96   }
97
98   /**
99    * update the 2d coordinates for the list of points to the given dimensions
100    * Principal dimension is getTop(). Next greatest eigenvector is getTop()-1.
101    * Note - pca.getComponents starts counting the spectrum from rank-2 to zero, rather than rank-1, so getComponents(dimN ...)  == updateRcView(dimN+1 ..)  
102    * @param dim1 
103    * @param dim2
104    * @param dim3
105    */
106   public void updateRcView(int dim1, int dim2, int dim3)
107   {
108     // note: actual indices for components are dim1-1, etc (patch for JAL-1123)
109     float[][] scores = pca.getComponents(dim1-1, dim2-1, dim3-1, 100);
110
111     for (int i = 0; i < pca.getM().rows; i++)
112     {
113       ((SequencePoint) points.elementAt(i)).coord = scores[i];
114     }
115   }
116
117   public String getDetails()
118   {
119     return pca.getDetails();
120   }
121
122   public AlignmentView getSeqtrings()
123   {
124     return seqstrings;
125   }
126   public String getPointsasCsv(boolean transformed, int xdim, int ydim, int zdim)
127   {
128     StringBuffer csv = new StringBuffer();
129     csv.append("\"Sequence\"");
130     if (transformed)
131     {
132       csv.append(",");
133       csv.append(xdim);
134       csv.append(",");
135       csv.append(ydim);
136       csv.append(",");
137       csv.append(zdim);
138     }
139     else
140     {
141       for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
142       {
143         csv.append("," + d);
144       }
145     }
146     csv.append("\n");
147     for (int s = 0; s < seqs.length; s++)
148     {
149       csv.append("\"" + seqs[s].getName() + "\"");
150       double fl[];
151       if (!transformed)
152       {
153         // output pca in correct order
154         fl = pca.component(s);
155         for (int d = fl.length - 1; d >= 0; d--)
156         {
157           csv.append(",");
158           csv.append(fl[d]);
159         }
160       }
161       else
162       {
163         // output current x,y,z coords for points
164         fl = getPointPosition(s);
165         for (int d = 0; d < fl.length; d++)
166         {
167           csv.append(",");
168           csv.append(fl[d]);
169         }
170       }
171       csv.append("\n");
172     }
173     return csv.toString();
174   }
175
176   /**
177    * 
178    * @return x,y,z positions of point s (index into points) under current
179    *         transform.
180    */
181   public double[] getPointPosition(int s)
182   {
183     double pts[] = new double[3];
184     float[] p = points.elementAt(s).coord;
185     pts[0] = p[0];
186     pts[1] = p[1];
187     pts[2] = p[2];
188     return pts;
189   }
190
191 }