JAL-1620 version bump and release notes
[jalview.git] / src / jalview / appletgui / PCAPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 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.appletgui;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 import jalview.datamodel.*;
27 import jalview.util.MessageManager;
28 import jalview.viewmodel.PCAModel;
29
30 public class PCAPanel extends EmbmenuFrame implements Runnable,
31         ActionListener, ItemListener
32 {
33   RotatableCanvas rc;
34
35   AlignViewport av;
36
37   PCAModel pcaModel;
38
39   int top = 0;
40
41   public PCAPanel(AlignViewport av)
42   {
43     try
44     {
45       jbInit();
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     boolean selected = av.getSelectionGroup() != null
60             && av.getSelectionGroup().getSize() > 0;
61     AlignmentView seqstrings = av.getAlignmentView(selected);
62     boolean nucleotide = av.getAlignment().isNucleotide();
63     SequenceI[] seqs;
64     if (!selected)
65     {
66       seqs = av.getAlignment().getSequencesArray();
67     }
68     else
69     {
70       seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
71     }
72     SeqCigar sq[] = seqstrings.getSequences();
73     int length = sq[0].getWidth();
74
75     for (int i = 0; i < seqs.length; i++)
76     {
77       if (sq[i].getWidth() != length)
78       {
79         System.out
80                 .println("Sequences must be equal length for PCA analysis");
81         return;
82       }
83     }
84     pcaModel = new PCAModel(seqstrings, seqs, nucleotide);
85
86     rc = new RotatableCanvas(av);
87     embedMenuIfNeeded(rc);
88     add(rc, BorderLayout.CENTER);
89
90     jalview.bin.JalviewLite.addFrame(this,
91             MessageManager.getString("label.principal_component_analysis"),
92             475, 400);
93
94     Thread worker = new Thread(this);
95     worker.start();
96   }
97
98   /**
99    * DOCUMENT ME!
100    */
101   public void run()
102   {
103     // TODO progress indicator
104     calcSettings.setEnabled(false);
105     rc.setEnabled(false);
106     try
107     {
108       nuclSetting.setState(pcaModel.isNucleotide());
109       protSetting.setState(!pcaModel.isNucleotide());
110       pcaModel.run();
111       // ////////////////
112       xCombobox.select(0);
113       yCombobox.select(1);
114       zCombobox.select(2);
115
116       pcaModel.updateRc(rc);
117       // rc.invalidate();
118       top = pcaModel.getTop();
119     } catch (OutOfMemoryError x)
120     {
121       System.err.println("Out of memory when calculating PCA.");
122       return;
123     }
124     calcSettings.setEnabled(true);
125
126     // TODO revert progress indicator
127     rc.setEnabled(true);
128     rc.repaint();
129     this.repaint();
130   }
131
132   void doDimensionChange()
133   {
134     if (top == 0)
135     {
136       return;
137     }
138
139     int dim1 = top - xCombobox.getSelectedIndex();
140     int dim2 = top - yCombobox.getSelectedIndex();
141     int dim3 = top - zCombobox.getSelectedIndex();
142     pcaModel.updateRcView(dim1, dim2, dim3);
143     rc.img = null;
144     rc.rotmat.setIdentity();
145     rc.initAxes();
146     rc.paint(rc.getGraphics());
147   }
148
149   public void actionPerformed(ActionEvent evt)
150   {
151     if (evt.getSource() == inputData)
152     {
153       showOriginalData();
154     }
155     if (evt.getSource() == resetButton)
156     {
157       xCombobox.select(0);
158       yCombobox.select(1);
159       zCombobox.select(2);
160       doDimensionChange();
161     }
162     if (evt.getSource() == values)
163     {
164       values_actionPerformed();
165     }
166   }
167
168   public void itemStateChanged(ItemEvent evt)
169   {
170     if (evt.getSource() == xCombobox)
171     {
172       xCombobox_actionPerformed();
173     }
174     else if (evt.getSource() == yCombobox)
175     {
176       yCombobox_actionPerformed();
177     }
178     else if (evt.getSource() == zCombobox)
179     {
180       zCombobox_actionPerformed();
181     }
182     else if (evt.getSource() == labels)
183     {
184       labels_itemStateChanged(evt);
185     }
186     else if (evt.getSource() == nuclSetting)
187     {
188       if (!pcaModel.isNucleotide())
189       {
190         pcaModel.setNucleotide(true);
191         new Thread(this).start();
192       }
193     }
194     else if (evt.getSource() == protSetting)
195     {
196       if (pcaModel.isNucleotide())
197       {
198         pcaModel.setNucleotide(false);
199         new Thread(this).start();
200       }
201     }
202   }
203
204   protected void xCombobox_actionPerformed()
205   {
206     doDimensionChange();
207   }
208
209   protected void yCombobox_actionPerformed()
210   {
211     doDimensionChange();
212   }
213
214   protected void zCombobox_actionPerformed()
215   {
216     doDimensionChange();
217   }
218
219   public void values_actionPerformed()
220   {
221
222     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, null);
223     Frame frame = new Frame();
224     frame.add(cap);
225     jalview.bin.JalviewLite.addFrame(frame,
226             MessageManager.getString("label.pca_details"), 500, 500);
227
228     cap.setText(pcaModel.getDetails());
229   }
230
231   void showOriginalData()
232   {
233     // decide if av alignment is sufficiently different to original data to
234     // warrant a new window to be created
235     // create new alignmnt window with hidden regions (unhiding hidden regions
236     // yields unaligned seqs)
237     // or create a selection box around columns in alignment view
238     // test Alignment(SeqCigar[])
239     char gc = '-';
240     try
241     {
242       // we try to get the associated view's gap character
243       // but this may fail if the view was closed...
244       gc = av.getGapCharacter();
245     } catch (Exception ex)
246     {
247     }
248     ;
249     Object[] alAndColsel = pcaModel.getSeqtrings()
250             .getAlignmentAndColumnSelection(gc);
251
252     if (alAndColsel != null && alAndColsel[0] != null)
253     {
254       Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
255       AlignFrame af = new AlignFrame(al, av.applet,
256               "Original Data for PCA", false);
257
258       af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
259     }
260   }
261
262   public void labels_itemStateChanged(ItemEvent itemEvent)
263   {
264     rc.showLabels(labels.getState());
265   }
266
267   Panel jPanel2 = new Panel();
268
269   Label jLabel1 = new Label();
270
271   Label jLabel2 = new Label();
272
273   Label jLabel3 = new Label();
274
275   protected Choice xCombobox = new Choice();
276
277   protected Choice yCombobox = new Choice();
278
279   protected Choice zCombobox = new Choice();
280
281   protected Button resetButton = new Button();
282
283   FlowLayout flowLayout1 = new FlowLayout();
284
285   BorderLayout borderLayout1 = new BorderLayout();
286
287   MenuBar menuBar1 = new MenuBar();
288
289   Menu menu1 = new Menu();
290
291   Menu menu2 = new Menu();
292
293   Menu calcSettings = new Menu();
294
295   protected CheckboxMenuItem labels = new CheckboxMenuItem();
296
297   protected CheckboxMenuItem protSetting = new CheckboxMenuItem();
298
299   protected CheckboxMenuItem nuclSetting = new CheckboxMenuItem();
300
301   MenuItem values = new MenuItem();
302
303   MenuItem inputData = new MenuItem();
304
305   private void jbInit() throws Exception
306   {
307     this.setLayout(borderLayout1);
308     jPanel2.setLayout(flowLayout1);
309     jLabel1.setFont(new java.awt.Font("Verdana", 0, 12));
310     jLabel1.setText("x=");
311     jLabel2.setFont(new java.awt.Font("Verdana", 0, 12));
312     jLabel2.setText("y=");
313     jLabel3.setFont(new java.awt.Font("Verdana", 0, 12));
314     jLabel3.setText("z=");
315     jPanel2.setBackground(Color.white);
316     zCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
317     zCombobox.addItemListener(this);
318     yCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
319     yCombobox.addItemListener(this);
320     xCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
321     xCombobox.addItemListener(this);
322     resetButton.setFont(new java.awt.Font("Verdana", 0, 12));
323     resetButton.setLabel(MessageManager.getString("action.reset"));
324     resetButton.addActionListener(this);
325     this.setMenuBar(menuBar1);
326     menu1.setLabel(MessageManager.getString("action.file"));
327     menu2.setLabel(MessageManager.getString("action.view"));
328     calcSettings.setLabel(MessageManager.getString("action.change_params"));
329     labels.setLabel(MessageManager.getString("label.labels"));
330     labels.addItemListener(this);
331     values.setLabel(MessageManager.getString("label.output_values"));
332     values.addActionListener(this);
333     inputData.setLabel(MessageManager.getString("label.input_data"));
334     nuclSetting.setLabel(MessageManager
335             .getString("label.nucleotide_matrix"));
336     nuclSetting.addItemListener(this);
337     protSetting.setLabel(MessageManager.getString("label.protein_matrix"));
338     protSetting.addItemListener(this);
339     this.add(jPanel2, BorderLayout.SOUTH);
340     jPanel2.add(jLabel1, null);
341     jPanel2.add(xCombobox, null);
342     jPanel2.add(jLabel2, null);
343     jPanel2.add(yCombobox, null);
344     jPanel2.add(jLabel3, null);
345     jPanel2.add(zCombobox, null);
346     jPanel2.add(resetButton, null);
347     menuBar1.add(menu1);
348     menuBar1.add(menu2);
349     menuBar1.add(calcSettings);
350     menu2.add(labels);
351     menu1.add(values);
352     menu1.add(inputData);
353     calcSettings.add(nuclSetting);
354     calcSettings.add(protSetting);
355     inputData.addActionListener(this);
356   }
357
358 }