Capitals
[jalview.git] / src / jalview / gui / PCAPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.analysis.*;\r
22 \r
23 import jalview.datamodel.*;\r
24 \r
25 import jalview.jbgui.*;\r
26 \r
27 import java.awt.*;\r
28 import java.awt.event.*;\r
29 \r
30 import java.util.*;\r
31 import javax.swing.*;\r
32 import java.awt.print.*;\r
33 \r
34 \r
35 /**\r
36  * DOCUMENT ME!\r
37  *\r
38  * @author $author$\r
39  * @version $Revision$\r
40  */\r
41 public class PCAPanel extends GPCAPanel implements Runnable\r
42 {\r
43     PCA pca;\r
44     int top;\r
45     RotatableCanvas rc;\r
46     AlignViewport av;\r
47     AlignmentView seqstrings;\r
48     SequenceI  [] seqs;\r
49 \r
50     /**\r
51      * Creates a new PCAPanel object.\r
52      *\r
53      * @param av DOCUMENT ME!\r
54      * @param s DOCUMENT ME!\r
55      */\r
56     public PCAPanel(AlignViewport av)\r
57     {\r
58         this.av = av;\r
59 \r
60         boolean sameLength = true;\r
61 \r
62         seqstrings = av.getAlignmentView(av.getSelectionGroup()!=null);\r
63         if(av.getSelectionGroup()==null)\r
64         {\r
65           seqs = av.alignment.getSequencesArray();\r
66         }\r
67         else\r
68         {\r
69           seqs = av.getSelectionGroup().getSequencesInOrder(av.alignment);\r
70         }\r
71         SeqCigar sq[]=seqstrings.getSequences();\r
72         int length = sq[0].getWidth();\r
73 \r
74         for (int i = 0; i < seqs.length; i++)\r
75         {\r
76           if (sq[i].getWidth() != length)\r
77           {\r
78             sameLength = false;\r
79             break;\r
80           }\r
81         }\r
82 \r
83         if (!sameLength)\r
84         {\r
85           JOptionPane.showMessageDialog(Desktop.desktop,\r
86                                         "The sequences must be aligned before calculating PCA.\n" +\r
87                                         "Try using the Pad function in the edit menu,\n" +\r
88                                         "or one of the multiple sequence alignment web services.",\r
89                                         "Sequences not aligned",\r
90                                         JOptionPane.WARNING_MESSAGE);\r
91 \r
92           return;\r
93         }\r
94 \r
95 \r
96         Desktop.addInternalFrame(this, "Principal component analysis",\r
97                                400, 400);\r
98 \r
99 \r
100         rc = new RotatableCanvas(av);\r
101         this.getContentPane().add(rc, BorderLayout.CENTER);\r
102         Thread worker = new Thread(this);\r
103         worker.start();\r
104     }\r
105 \r
106     public void bgcolour_actionPerformed(ActionEvent e)\r
107     {\r
108       Color col = JColorChooser.showDialog(this, "Select Background Colour",\r
109                 rc.bgColour);\r
110 \r
111       if(col!=null)\r
112         rc.bgColour = col;\r
113       rc.repaint();\r
114     }\r
115 \r
116 \r
117 \r
118 \r
119     /**\r
120      * DOCUMENT ME!\r
121      */\r
122     public void run()\r
123     {\r
124       try{\r
125         pca = new PCA(seqstrings.getSequenceStrings(' '));\r
126         pca.run();\r
127 \r
128         // Now find the component coordinates\r
129         int ii = 0;\r
130 \r
131         while ( (ii < seqs.length) && (seqs[ii] != null))\r
132         {\r
133           ii++;\r
134         }\r
135 \r
136         double[][] comps = new double[ii][ii];\r
137 \r
138         for (int i = 0; i < ii; i++)\r
139         {\r
140           if (pca.getEigenvalue(i) > 1e-4)\r
141           {\r
142             comps[i] = pca.component(i);\r
143           }\r
144         }\r
145 \r
146         //////////////////\r
147         xCombobox.setSelectedIndex(0);\r
148         yCombobox.setSelectedIndex(1);\r
149         zCombobox.setSelectedIndex(2);\r
150 \r
151         top = pca.getM().rows - 1;\r
152 \r
153         Vector points = new Vector();\r
154         float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);\r
155 \r
156         for (int i = 0; i < pca.getM().rows; i++)\r
157         {\r
158           SequencePoint sp = new SequencePoint(seqs[i], scores[i]);\r
159           points.addElement(sp);\r
160         }\r
161 \r
162         rc.setPoints(points, pca.getM().rows);\r
163         rc.repaint();\r
164       }\r
165      catch(OutOfMemoryError er)\r
166       { JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
167                                               "Out of memory calculating PCA!!"\r
168                                               +\r
169                                               "\nSee help files for increasing Java Virtual Machine memory."\r
170                                               , "Out of memory",\r
171                                               JOptionPane.WARNING_MESSAGE);\r
172         System.out.println("PCAPanel: "+er);\r
173         System.gc();\r
174 \r
175       }\r
176 \r
177     }\r
178 \r
179     /**\r
180      * DOCUMENT ME!\r
181      */\r
182     void doDimensionChange()\r
183     {\r
184         if (top == 0)\r
185         {\r
186             return;\r
187         }\r
188 \r
189         int dim1 = top - xCombobox.getSelectedIndex();\r
190         int dim2 = top - yCombobox.getSelectedIndex();\r
191         int dim3 = top - zCombobox.getSelectedIndex();\r
192 \r
193         float[][] scores = pca.getComponents(dim1, dim2, dim3, 100);\r
194 \r
195         for (int i = 0; i < pca.getM().rows; i++)\r
196         {\r
197             ((SequencePoint) rc.points.elementAt(i)).coord = scores[i];\r
198         }\r
199 \r
200         rc.img = null;\r
201         rc.rotmat.setIdentity();\r
202         rc.initAxes();\r
203         rc.paint(rc.getGraphics());\r
204     }\r
205 \r
206     /**\r
207      * DOCUMENT ME!\r
208      *\r
209      * @param e DOCUMENT ME!\r
210      */\r
211     protected void xCombobox_actionPerformed(ActionEvent e)\r
212     {\r
213         doDimensionChange();\r
214     }\r
215 \r
216     /**\r
217      * DOCUMENT ME!\r
218      *\r
219      * @param e DOCUMENT ME!\r
220      */\r
221     protected void yCombobox_actionPerformed(ActionEvent e)\r
222     {\r
223         doDimensionChange();\r
224     }\r
225 \r
226     /**\r
227      * DOCUMENT ME!\r
228      *\r
229      * @param e DOCUMENT ME!\r
230      */\r
231     protected void zCombobox_actionPerformed(ActionEvent e)\r
232     {\r
233         doDimensionChange();\r
234     }\r
235 \r
236 \r
237     public void outputValues_actionPerformed(ActionEvent e)\r
238     {\r
239       CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
240       Desktop.addInternalFrame(cap, "PCA details", 500,\r
241                 500);\r
242 \r
243       cap.setText(pca.getDetails());\r
244      }\r
245 \r
246     public void showLabels_actionPerformed(ActionEvent e)\r
247     {\r
248       rc.showLabels(showLabels.getState());\r
249     }\r
250 \r
251     public void print_actionPerformed(ActionEvent e)\r
252     {\r
253       PCAPrinter printer = new PCAPrinter();\r
254       printer.start();\r
255     }\r
256 \r
257     public void originalSeqData_actionPerformed(ActionEvent e)\r
258     {\r
259       // this was cut'n'pasted from the equivalent TreePanel method - we should make this an abstract function of all jalview analysis windows\r
260       if (seqstrings==null)\r
261       {\r
262         jalview.bin.Cache.log.info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");\r
263         return;\r
264       }\r
265       // decide if av alignment is sufficiently different to original data to warrant a new window to be created\r
266       // create new alignmnt window with hidden regions (unhiding hidden regions yields unaligned seqs)\r
267       // or create a selection box around columns in alignment view\r
268       // test Alignment(SeqCigar[])\r
269       Object[] alAndColsel = seqstrings.getAlignmentAndColumnSelection(av.\r
270           getGapCharacter());\r
271 \r
272 \r
273       if (alAndColsel != null && alAndColsel[0]!=null)\r
274       {\r
275           // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);\r
276 \r
277           Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);\r
278           Alignment dataset = av.getAlignment().getDataset();\r
279           if (dataset != null)\r
280           {\r
281             al.setDataset(dataset);\r
282           }\r
283 \r
284           if (true)\r
285           {\r
286               // make a new frame!\r
287               AlignFrame af = new AlignFrame(al, (ColumnSelection) alAndColsel[1]);\r
288 \r
289               //>>>This is a fix for the moment, until a better solution is found!!<<<\r
290               // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());\r
291 \r
292               //           af.addSortByOrderMenuItem(ServiceName + " Ordering",\r
293               //                                     msaorder);\r
294 \r
295               Desktop.addInternalFrame(af, "Original Data for " + this.title,\r
296                                        AlignFrame.NEW_WINDOW_WIDTH,\r
297                                        AlignFrame.NEW_WINDOW_HEIGHT);\r
298             }\r
299           }\r
300           /*      CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
301                  for (int i = 0; i < seqs.length; i++)\r
302                  {\r
303                    cap.appendText(new jalview.util.Format("%-" + 15 + "s").form(\r
304             seqs[i].getName()));\r
305                    cap.appendText(" " + seqstrings[i] + "\n");\r
306 \r
307                  }\r
308 \r
309                  Desktop.addInternalFrame(cap, "Original Data",\r
310                      400, 400);\r
311            */\r
312     }\r
313 \r
314 \r
315 \r
316     class PCAPrinter extends Thread implements Printable\r
317     {\r
318       public void run()\r
319       {\r
320         PrinterJob printJob = PrinterJob.getPrinterJob();\r
321         PageFormat pf = printJob.pageDialog(printJob.defaultPage());\r
322 \r
323         printJob.setPrintable(this, pf);\r
324 \r
325         if (printJob.printDialog())\r
326         {\r
327           try\r
328           {\r
329             printJob.print();\r
330           }\r
331           catch (Exception PrintException)\r
332           {\r
333             PrintException.printStackTrace();\r
334           }\r
335         }\r
336       }\r
337 \r
338       public int print(Graphics pg, PageFormat pf, int pi)\r
339           throws PrinterException\r
340       {\r
341         pg.translate( (int) pf.getImageableX(), (int) pf.getImageableY());\r
342 \r
343         rc.drawBackground(pg, rc.bgColour);\r
344         rc.drawScene(pg);\r
345         if (rc.drawAxes == true)\r
346         {\r
347           rc.drawAxes(pg);\r
348         }\r
349 \r
350         if (pi == 0)\r
351           return Printable.PAGE_EXISTS;\r
352         else\r
353           return Printable.NO_SUCH_PAGE;\r
354       }\r
355     }\r
356 \r
357 \r
358 \r
359     /**\r
360      * DOCUMENT ME!\r
361      *\r
362      * @param e DOCUMENT ME!\r
363      */\r
364     public void eps_actionPerformed(ActionEvent e)\r
365     {\r
366       makePCAImage(jalview.util.ImageMaker.EPS);\r
367     }\r
368 \r
369     /**\r
370      * DOCUMENT ME!\r
371      *\r
372      * @param e DOCUMENT ME!\r
373      */\r
374     public void png_actionPerformed(ActionEvent e)\r
375     {\r
376        makePCAImage(jalview.util.ImageMaker.PNG);\r
377     }\r
378 \r
379     void makePCAImage(int type)\r
380     {\r
381       int width = rc.getWidth();\r
382       int height = rc.getHeight();\r
383 \r
384       jalview.util.ImageMaker im;\r
385 \r
386       if(type == jalview.util.ImageMaker.PNG)\r
387         im = new jalview.util.ImageMaker(this,\r
388                                          jalview.util.ImageMaker.PNG,\r
389                                          "Make PNG image from PCA",\r
390                                          width, height,\r
391                                          null, null);\r
392         else\r
393           im = new jalview.util.ImageMaker(this,\r
394                                  jalview.util.ImageMaker.EPS,\r
395                                  "Make EPS file from PCA",\r
396                                  width, height,\r
397                                  null, this.getTitle());\r
398 \r
399       if(im.getGraphics()!=null)\r
400        {\r
401          rc.drawBackground(im.getGraphics(), Color.black);\r
402          rc.drawScene(im.getGraphics());\r
403          if (rc.drawAxes == true)\r
404          {\r
405            rc.drawAxes(im.getGraphics());\r
406          }\r
407          im.writeImage();\r
408        }\r
409     }\r
410   }\r