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