Now an InternalFrame with menus
[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.io.FileOutputStream;\r
33 import org.jibble.epsgraphics.EpsGraphics2D;\r
34 import javax.imageio.ImageIO;\r
35 import java.awt.image.BufferedImage;\r
36 import java.awt.print.*;\r
37 \r
38 \r
39 /**\r
40  * DOCUMENT ME!\r
41  *\r
42  * @author $author$\r
43  * @version $Revision$\r
44  */\r
45 public class PCAPanel extends GPCAPanel implements Runnable\r
46 {\r
47     PCA pca;\r
48     int top;\r
49     RotatableCanvas rc;\r
50     AlignViewport av;\r
51     SequenceI [] seqs;\r
52 \r
53     /**\r
54      * Creates a new PCAPanel object.\r
55      *\r
56      * @param av DOCUMENT ME!\r
57      * @param s DOCUMENT ME!\r
58      */\r
59     public PCAPanel(AlignViewport av)\r
60     {\r
61         this.av = av;\r
62 \r
63         boolean sameLength = true;\r
64 \r
65         if ((av.getSelectionGroup() != null) &&\r
66                 (av.getSelectionGroup().getSize() > 3))\r
67         {\r
68             seqs = new Sequence[av.getSelectionGroup().getSize()];\r
69             int length = av.getSelectionGroup().getSequenceAt(0).getLength();\r
70             for (int i = 0; i < av.getSelectionGroup().getSize(); i++)\r
71             {\r
72                 seqs[i] = av.getSelectionGroup().getSequenceAt(i);\r
73                 if(seqs[i].getLength()!=length)\r
74                 {\r
75                   sameLength = false;\r
76                   break;\r
77                 }\r
78             }\r
79         }\r
80         else\r
81         {\r
82             seqs = new Sequence[av.getAlignment().getHeight()];\r
83             int length = av.alignment.getSequenceAt(0).getLength();\r
84 \r
85             for (int i = 0; i < av.getAlignment().getHeight(); i++)\r
86             {\r
87                 seqs[i] = av.getAlignment().getSequenceAt(i);\r
88                 if(seqs[i].getLength()!=length)\r
89                {\r
90                  sameLength = false;\r
91                  break;\r
92                }\r
93 \r
94             }\r
95         }\r
96 \r
97         if (!sameLength)\r
98         {\r
99           JOptionPane.showMessageDialog(Desktop.desktop,\r
100                                         "The sequences must be aligned before calculating PCA.\n" +\r
101                                         "Try using the Pad function in the edit menu,\n" +\r
102                                         "or one of the multiple sequence alignment web services.",\r
103                                         "Sequences not aligned",\r
104                                         JOptionPane.WARNING_MESSAGE);\r
105 \r
106           return;\r
107         }\r
108 \r
109 \r
110         Desktop.addInternalFrame(this, "Principal component analysis",\r
111                                400, 400);\r
112 \r
113 \r
114         rc = new RotatableCanvas(av);\r
115         this.getContentPane().add(rc, BorderLayout.CENTER);\r
116         Thread worker = new Thread(this);\r
117         worker.start();\r
118     }\r
119 \r
120     public void bgcolour_actionPerformed(ActionEvent e)\r
121     {\r
122       Color col = JColorChooser.showDialog(this, "Select Background Colour",\r
123                 rc.bgColour);\r
124 \r
125       if(col!=null)\r
126         rc.bgColour = col;\r
127       rc.repaint();\r
128     }\r
129 \r
130 \r
131 \r
132 \r
133     /**\r
134      * DOCUMENT ME!\r
135      */\r
136     public void run()\r
137     {\r
138       try{\r
139         pca = new PCA(seqs);\r
140         pca.run();\r
141 \r
142         // Now find the component coordinates\r
143         int ii = 0;\r
144 \r
145         while ( (ii < seqs.length) && (seqs[ii] != null))\r
146         {\r
147           ii++;\r
148         }\r
149 \r
150         double[][] comps = new double[ii][ii];\r
151 \r
152         for (int i = 0; i < ii; i++)\r
153         {\r
154           if (pca.getEigenvalue(i) > 1e-4)\r
155           {\r
156             comps[i] = pca.component(i);\r
157           }\r
158         }\r
159 \r
160         //////////////////\r
161         xCombobox.setSelectedIndex(0);\r
162         yCombobox.setSelectedIndex(1);\r
163         zCombobox.setSelectedIndex(2);\r
164 \r
165         top = pca.getM().rows - 1;\r
166 \r
167         Vector points = new Vector();\r
168         float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);\r
169 \r
170         for (int i = 0; i < pca.getM().rows; i++)\r
171         {\r
172           SequencePoint sp = new SequencePoint(seqs[i], scores[i]);\r
173           points.addElement(sp);\r
174         }\r
175 \r
176         rc.setPoints(points, pca.getM().rows);\r
177         rc.repaint();\r
178         seqs = null;\r
179       }\r
180      catch(OutOfMemoryError er)\r
181       { JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
182                                               "Out of memory calculating PCA!!"\r
183                                               +\r
184                                               "\nSee help files for increasing Java Virtual Machine memory."\r
185                                               , "Out of memory",\r
186                                               JOptionPane.WARNING_MESSAGE);\r
187         System.out.println("PCAPanel: "+er);\r
188         System.gc();\r
189 \r
190       }\r
191 \r
192     }\r
193 \r
194     /**\r
195      * DOCUMENT ME!\r
196      */\r
197     void doDimensionChange()\r
198     {\r
199         if (top == 0)\r
200         {\r
201             return;\r
202         }\r
203 \r
204         int dim1 = top - xCombobox.getSelectedIndex();\r
205         int dim2 = top - yCombobox.getSelectedIndex();\r
206         int dim3 = top - zCombobox.getSelectedIndex();\r
207 \r
208         float[][] scores = pca.getComponents(dim1, dim2, dim3, 100);\r
209 \r
210         for (int i = 0; i < pca.getM().rows; i++)\r
211         {\r
212             ((SequencePoint) rc.points.elementAt(i)).coord = scores[i];\r
213         }\r
214 \r
215         rc.img = null;\r
216         rc.rotmat.setIdentity();\r
217         rc.initAxes();\r
218         rc.paint(rc.getGraphics());\r
219     }\r
220 \r
221     /**\r
222      * DOCUMENT ME!\r
223      *\r
224      * @param e DOCUMENT ME!\r
225      */\r
226     protected void xCombobox_actionPerformed(ActionEvent e)\r
227     {\r
228         doDimensionChange();\r
229     }\r
230 \r
231     /**\r
232      * DOCUMENT ME!\r
233      *\r
234      * @param e DOCUMENT ME!\r
235      */\r
236     protected void yCombobox_actionPerformed(ActionEvent e)\r
237     {\r
238         doDimensionChange();\r
239     }\r
240 \r
241     /**\r
242      * DOCUMENT ME!\r
243      *\r
244      * @param e DOCUMENT ME!\r
245      */\r
246     protected void zCombobox_actionPerformed(ActionEvent e)\r
247     {\r
248         doDimensionChange();\r
249     }\r
250 \r
251 \r
252     public void outputValues_actionPerformed(ActionEvent e)\r
253     {\r
254       CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
255       Desktop.addInternalFrame(cap, "PCA details", 500,\r
256                 500);\r
257 \r
258       cap.setText(pca.getDetails());\r
259      }\r
260 \r
261     public void showLabels_actionPerformed(ActionEvent e)\r
262     {\r
263       rc.showLabels(showLabels.getState());\r
264     }\r
265 \r
266     public void print_actionPerformed(ActionEvent e)\r
267     {\r
268       PCAPrinter printer = new PCAPrinter();\r
269       printer.start();\r
270     }\r
271 \r
272 \r
273     class PCAPrinter extends Thread implements Printable\r
274     {\r
275       public void run()\r
276       {\r
277         PrinterJob printJob = PrinterJob.getPrinterJob();\r
278         PageFormat pf = printJob.pageDialog(printJob.defaultPage());\r
279 \r
280         printJob.setPrintable(this, pf);\r
281 \r
282         if (printJob.printDialog())\r
283         {\r
284           try\r
285           {\r
286             printJob.print();\r
287           }\r
288           catch (Exception PrintException)\r
289           {\r
290             PrintException.printStackTrace();\r
291           }\r
292         }\r
293       }\r
294 \r
295       public int print(Graphics pg, PageFormat pf, int pi)\r
296           throws PrinterException\r
297       {\r
298         pg.translate( (int) pf.getImageableX(), (int) pf.getImageableY());\r
299 \r
300         rc.drawBackground(pg, rc.bgColour);\r
301         rc.drawScene(pg);\r
302         if (rc.drawAxes == true)\r
303         {\r
304           rc.drawAxes(pg);\r
305         }\r
306 \r
307         if (pi == 0)\r
308           return Printable.PAGE_EXISTS;\r
309         else\r
310           return Printable.NO_SUCH_PAGE;\r
311       }\r
312     }\r
313 \r
314 \r
315 \r
316 \r
317     /**\r
318      * DOCUMENT ME!\r
319      *\r
320      * @param e DOCUMENT ME!\r
321      */\r
322     public void eps_actionPerformed(ActionEvent e)\r
323     {\r
324       boolean accurateText = true;\r
325 \r
326       String renderStyle = jalview.bin.Cache.getDefault("EPS_RENDERING",\r
327           "Prompt each time");\r
328 \r
329   // If we need to prompt, and if the GUI is visible then\r
330   // Prompt for EPS rendering style\r
331       if (renderStyle.equalsIgnoreCase("Prompt each time")\r
332           && !\r
333           (System.getProperty("java.awt.headless") != null\r
334            && System.getProperty("java.awt.headless").equals("true")))\r
335       {\r
336         EPSOptions eps = new EPSOptions();\r
337         renderStyle = eps.getValue();\r
338 \r
339         if (renderStyle == null || eps.cancelled)\r
340           return;\r
341 \r
342       }\r
343 \r
344       if (renderStyle.equalsIgnoreCase("text"))\r
345       {\r
346         accurateText = false;\r
347       }\r
348 \r
349       int width = rc.getWidth();\r
350       int height = rc.getHeight();\r
351 \r
352       try\r
353       {\r
354         jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(\r
355             jalview.bin.Cache.getProperty(\r
356                 "LAST_DIRECTORY"), new String[]\r
357             {"eps"},\r
358             new String[]\r
359             {"Encapsulated Postscript"},\r
360             "Encapsulated Postscript");\r
361         chooser.setFileView(new jalview.io.JalviewFileView());\r
362         chooser.setDialogTitle("Create EPS file from PCA");\r
363         chooser.setToolTipText("Save");\r
364 \r
365         int value = chooser.showSaveDialog(this);\r
366 \r
367         if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
368         {\r
369           return;\r
370         }\r
371 \r
372         jalview.bin.Cache.setProperty("LAST_DIRECTORY",\r
373                                       chooser.getSelectedFile().getParent());\r
374 \r
375         FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
376         EpsGraphics2D pg = new EpsGraphics2D("PCA", out, 0, 0, width,\r
377                                              height);\r
378 \r
379         pg.setAccurateTextMode(accurateText);\r
380 \r
381         rc.drawBackground(pg, rc.bgColour);\r
382         rc.drawScene(pg);\r
383 \r
384         if (rc.drawAxes == true)\r
385         {\r
386           rc.drawAxes(pg);\r
387         }\r
388 \r
389 \r
390         pg.flush();\r
391         pg.close();\r
392       }\r
393       catch (Exception ex)\r
394       {\r
395         ex.printStackTrace();\r
396       }\r
397     }\r
398 \r
399     /**\r
400      * DOCUMENT ME!\r
401      *\r
402      * @param e DOCUMENT ME!\r
403      */\r
404     public void png_actionPerformed(ActionEvent e)\r
405     {\r
406       int width = rc.getWidth();\r
407       int height = rc.getHeight();\r
408 \r
409       try\r
410       {\r
411         jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(\r
412             jalview.bin.Cache.getProperty(\r
413                 "LAST_DIRECTORY"), new String[]\r
414             {"png"},\r
415             new String[]\r
416             {"Portable network graphics"},\r
417             "Portable network graphics");\r
418 \r
419         chooser.setFileView(new jalview.io.JalviewFileView());\r
420         chooser.setDialogTitle("Create PNG image from PCA");\r
421         chooser.setToolTipText("Save");\r
422 \r
423         int value = chooser.showSaveDialog(this);\r
424 \r
425         if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
426         {\r
427           return;\r
428         }\r
429 \r
430         jalview.bin.Cache.setProperty("LAST_DIRECTORY",\r
431                                       chooser.getSelectedFile().getParent());\r
432 \r
433         FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
434 \r
435         BufferedImage bi = new BufferedImage(width, height,\r
436                                              BufferedImage.TYPE_INT_RGB);\r
437         Graphics big = bi.getGraphics();\r
438 \r
439         big.drawImage(rc.img,0,0,this);\r
440 \r
441         ImageIO.write(bi, "png", out);\r
442         out.close();\r
443       }\r
444       catch (Exception ex)\r
445       {\r
446         ex.printStackTrace();\r
447       }\r
448     }\r
449 \r
450   }\r