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