patch to fix occasional arrayoutofbounds exception when working with hidden columns...
[jalview.git] / src / jalview / appletgui / PCAPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.appletgui;
20
21 import java.util.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 import jalview.analysis.*;
27 import jalview.datamodel.*;
28
29 public class PCAPanel extends EmbmenuFrame implements Runnable,
30         ActionListener, ItemListener
31 {
32   PCA pca;
33
34   int top;
35
36   RotatableCanvas rc;
37
38   AlignViewport av;
39
40   SequenceI[] seqs;
41
42   AlignmentView seqstrings;
43
44   public PCAPanel(AlignViewport av)
45   {
46     try
47     {
48       jbInit();
49     } catch (Exception e)
50     {
51       e.printStackTrace();
52     }
53
54     for (int i = 1; i < 8; i++)
55     {
56       xCombobox.addItem("dim " + i);
57       yCombobox.addItem("dim " + i);
58       zCombobox.addItem("dim " + i);
59     }
60
61     this.av = av;
62     seqstrings = av.getAlignmentView(av.getSelectionGroup() != null);
63     if (av.getSelectionGroup() == null)
64     {
65       seqs = av.alignment.getSequencesArray();
66     }
67     else
68     {
69       seqs = av.getSelectionGroup().getSequencesInOrder(av.alignment);
70     }
71     SeqCigar sq[] = seqstrings.getSequences();
72     int length = sq[0].getWidth();
73
74     for (int i = 0; i < seqs.length; i++)
75     {
76       if (sq[i].getWidth() != length)
77       {
78         System.out
79                 .println("Sequences must be equal length for PCA analysis");
80         return;
81       }
82     }
83
84     rc = new RotatableCanvas(av);
85     embedMenuIfNeeded(rc);
86     add(rc, BorderLayout.CENTER);
87
88     jalview.bin.JalviewLite.addFrame(this, "Principal component analysis",
89             400, 400);
90
91     Thread worker = new Thread(this);
92     worker.start();
93   }
94
95   /**
96    * DOCUMENT ME!
97    */
98   public void run()
99   {
100     pca = new PCA(seqstrings.getSequenceStrings(' '));
101     pca.run();
102
103     // Now find the component coordinates
104     int ii = 0;
105
106     while ((ii < seqs.length) && (seqs[ii] != null))
107     {
108       ii++;
109     }
110
111     double[][] comps = new double[ii][ii];
112
113     for (int i = 0; i < ii; i++)
114     {
115       if (pca.getEigenvalue(i) > 1e-4)
116       {
117         comps[i] = pca.component(i);
118       }
119     }
120
121     // ////////////////
122     xCombobox.select(0);
123     yCombobox.select(1);
124     zCombobox.select(2);
125
126     top = pca.getM().rows - 1;
127
128     Vector points = new Vector();
129     float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
130
131     for (int i = 0; i < pca.getM().rows; i++)
132     {
133       SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
134       points.addElement(sp);
135     }
136
137     rc.setPoints(points, pca.getM().rows);
138     rc.repaint();
139     seqs = null;
140     this.repaint();
141   }
142
143   void doDimensionChange()
144   {
145     if (top == 0)
146     {
147       return;
148     }
149
150     int dim1 = top - xCombobox.getSelectedIndex();
151     int dim2 = top - yCombobox.getSelectedIndex();
152     int dim3 = top - zCombobox.getSelectedIndex();
153
154     float[][] scores = pca.getComponents(dim1, dim2, dim3, 100);
155     for (int i = 0; i < pca.getM().rows; i++)
156     {
157       ((SequencePoint) rc.points.elementAt(i)).coord = scores[i];
158     }
159
160     rc.img = null;
161     rc.rotmat.setIdentity();
162     rc.initAxes();
163     rc.paint(rc.getGraphics());
164   }
165
166   public void actionPerformed(ActionEvent evt)
167   {
168     if (evt.getSource() == inputData)
169     {
170       showOriginalData();
171     }
172     else
173     {
174       values_actionPerformed();
175     }
176   }
177
178   public void itemStateChanged(ItemEvent evt)
179   {
180     if (evt.getSource() == xCombobox)
181     {
182       xCombobox_actionPerformed();
183     }
184     else if (evt.getSource() == yCombobox)
185     {
186       yCombobox_actionPerformed();
187     }
188     else if (evt.getSource() == zCombobox)
189     {
190       zCombobox_actionPerformed();
191     }
192   }
193
194   protected void xCombobox_actionPerformed()
195   {
196     doDimensionChange();
197   }
198
199   protected void yCombobox_actionPerformed()
200   {
201     doDimensionChange();
202   }
203
204   protected void zCombobox_actionPerformed()
205   {
206     doDimensionChange();
207   }
208
209   public void values_actionPerformed()
210   {
211
212     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, null);
213     Frame frame = new Frame();
214     frame.add(cap);
215     jalview.bin.JalviewLite.addFrame(frame, "PCA details", 500, 500);
216
217     cap.setText(pca.getDetails());
218   }
219
220   void showOriginalData()
221   {
222     // decide if av alignment is sufficiently different to original data to
223     // warrant a new window to be created
224     // create new alignmnt window with hidden regions (unhiding hidden regions
225     // yields unaligned seqs)
226     // or create a selection box around columns in alignment view
227     // test Alignment(SeqCigar[])
228     char gc = '-';
229     try
230     {
231       // we try to get the associated view's gap character
232       // but this may fail if the view was closed...
233       gc = av.getGapCharacter();
234     } catch (Exception ex)
235     {
236     }
237     ;
238     Object[] alAndColsel = seqstrings.getAlignmentAndColumnSelection(gc);
239
240     if (alAndColsel != null && alAndColsel[0] != null)
241     {
242       Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
243       AlignFrame af = new AlignFrame(al, av.applet,
244               "Original Data for PCA", false);
245
246       af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
247     }
248   }
249
250   public void labels_itemStateChanged(ItemEvent itemEvent)
251   {
252     rc.showLabels(labels.getState());
253   }
254
255   Panel jPanel2 = new Panel();
256
257   Label jLabel1 = new Label();
258
259   Label jLabel2 = new Label();
260
261   Label jLabel3 = new Label();
262
263   protected Choice xCombobox = new Choice();
264
265   protected Choice yCombobox = new Choice();
266
267   protected Choice zCombobox = new Choice();
268
269   FlowLayout flowLayout1 = new FlowLayout();
270
271   BorderLayout borderLayout1 = new BorderLayout();
272
273   MenuBar menuBar1 = new MenuBar();
274
275   Menu menu1 = new Menu();
276
277   Menu menu2 = new Menu();
278
279   protected CheckboxMenuItem labels = new CheckboxMenuItem();
280
281   MenuItem values = new MenuItem();
282
283   MenuItem inputData = new MenuItem();
284
285   private void jbInit() throws Exception
286   {
287     this.setLayout(borderLayout1);
288     jPanel2.setLayout(flowLayout1);
289     jLabel1.setFont(new java.awt.Font("Verdana", 0, 12));
290     jLabel1.setText("x=");
291     jLabel2.setFont(new java.awt.Font("Verdana", 0, 12));
292     jLabel2.setText("y=");
293     jLabel3.setFont(new java.awt.Font("Verdana", 0, 12));
294     jLabel3.setText("z=");
295     jPanel2.setBackground(Color.white);
296     zCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
297     zCombobox.addItemListener(this);
298     yCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
299     yCombobox.addItemListener(this);
300     xCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
301     xCombobox.addItemListener(this);
302     this.setMenuBar(menuBar1);
303     menu1.setLabel("File");
304     menu2.setLabel("View");
305     labels.setLabel("Labels");
306     labels.addItemListener(this);
307     values.setLabel("Output Values...");
308     values.addActionListener(this);
309     inputData.setLabel("Input Data...");
310     this.add(jPanel2, BorderLayout.SOUTH);
311     jPanel2.add(jLabel1, null);
312     jPanel2.add(xCombobox, null);
313     jPanel2.add(jLabel2, null);
314     jPanel2.add(yCombobox, null);
315     jPanel2.add(jLabel3, null);
316     jPanel2.add(zCombobox, null);
317     menuBar1.add(menu1);
318     menuBar1.add(menu2);
319     menu2.add(labels);
320     menu1.add(values);
321     menu1.add(inputData);
322     inputData.addActionListener(this);
323   }
324
325 }