2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
23 import java.awt.event.*;
24 import java.awt.print.*;
27 import jalview.analysis.*;
28 import jalview.datamodel.*;
29 import jalview.jbgui.*;
37 public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator
50 AlignmentView seqstrings;
55 * use the identity matrix for calculating similarity between sequences.
57 private boolean nucleotide=false;
60 * Creates a new PCAPanel object.
67 public PCAPanel(AlignmentPanel ap)
72 boolean sameLength = true;
74 seqstrings = av.getAlignmentView(av.getSelectionGroup() != null);
75 nucleotide=av.getAlignment().isNucleotide();
76 if (av.getSelectionGroup() == null)
78 seqs = av.getAlignment().getSequencesArray();
82 seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
84 SeqCigar sq[] = seqstrings.getSequences();
85 int length = sq[0].getWidth();
87 for (int i = 0; i < seqs.length; i++)
89 if (sq[i].getWidth() != length)
101 "The sequences must be aligned before calculating PCA.\n"
102 + "Try using the Pad function in the edit menu,\n"
103 + "or one of the multiple sequence alignment web services.",
104 "Sequences not aligned", JOptionPane.WARNING_MESSAGE);
109 PaintRefresher.Register(this, av.getSequenceSetId());
111 rc = new RotatableCanvas(ap);
112 this.getContentPane().add(rc, BorderLayout.CENTER);
113 Thread worker = new Thread(this);
117 public void bgcolour_actionPerformed(ActionEvent e)
119 Color col = JColorChooser.showDialog(this, "Select Background Colour",
134 long progId=System.currentTimeMillis();
135 IProgressIndicator progress=this;
136 String message="Recalculating PCA";
137 if (getParent()==null) {
138 progress=ap.alignFrame;
139 message = "Calculating PCA";
141 progress.setProgressBar(message, progId);
144 calcSettings.setEnabled(false);
146 pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide);
149 // Now find the component coordinates
152 while ((ii < seqs.length) && (seqs[ii] != null))
157 double[][] comps = new double[ii][ii];
159 for (int i = 0; i < ii; i++)
161 if (pca.getEigenvalue(i) > 1e-4)
163 comps[i] = pca.component(i);
168 xCombobox.setSelectedIndex(0);
169 yCombobox.setSelectedIndex(1);
170 zCombobox.setSelectedIndex(2);
172 top = pca.getM().rows - 1;
174 Vector points = new Vector();
175 float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
177 for (int i = 0; i < pca.getM().rows; i++)
179 SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
180 points.addElement(sp);
183 rc.setPoints(points, pca.getM().rows);
185 nuclSetting.setSelected(nucleotide);
186 protSetting.setSelected(!nucleotide);
188 } catch (OutOfMemoryError er)
190 new OOMWarning("calculating PCA", er);
194 progress.setProgressBar("", progId);
196 calcSettings.setEnabled(true);
198 if (getParent()==null)
201 Desktop.addInternalFrame(this, "Principal component analysis", 475, 450);
205 protected void nuclSetting_actionPerfomed(ActionEvent arg0)
210 Thread worker = new Thread(this);
216 protected void protSetting_actionPerfomed(ActionEvent arg0)
222 Thread worker = new Thread(this);
229 void doDimensionChange()
236 int dim1 = top - xCombobox.getSelectedIndex();
237 int dim2 = top - yCombobox.getSelectedIndex();
238 int dim3 = top - zCombobox.getSelectedIndex();
240 float[][] scores = pca.getComponents(dim1, dim2, dim3, 100);
242 for (int i = 0; i < pca.getM().rows; i++)
244 ((SequencePoint) rc.points.elementAt(i)).coord = scores[i];
248 rc.rotmat.setIdentity();
250 rc.paint(rc.getGraphics());
259 protected void xCombobox_actionPerformed(ActionEvent e)
270 protected void yCombobox_actionPerformed(ActionEvent e)
281 protected void zCombobox_actionPerformed(ActionEvent e)
286 public void outputValues_actionPerformed(ActionEvent e)
288 CutAndPasteTransfer cap = new CutAndPasteTransfer();
291 cap.setText(pca.getDetails());
292 Desktop.addInternalFrame(cap, "PCA details", 500, 500);
293 } catch (OutOfMemoryError oom)
295 new OOMWarning("opening PCA details", oom);
300 public void showLabels_actionPerformed(ActionEvent e)
302 rc.showLabels(showLabels.getState());
305 public void print_actionPerformed(ActionEvent e)
307 PCAPrinter printer = new PCAPrinter();
311 public void originalSeqData_actionPerformed(ActionEvent e)
313 // this was cut'n'pasted from the equivalent TreePanel method - we should
314 // make this an abstract function of all jalview analysis windows
315 if (seqstrings == null)
317 jalview.bin.Cache.log
318 .info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
321 // decide if av alignment is sufficiently different to original data to
322 // warrant a new window to be created
323 // create new alignmnt window with hidden regions (unhiding hidden regions
324 // yields unaligned seqs)
325 // or create a selection box around columns in alignment view
326 // test Alignment(SeqCigar[])
330 // we try to get the associated view's gap character
331 // but this may fail if the view was closed...
332 gc = av.getGapCharacter();
333 } catch (Exception ex)
337 Object[] alAndColsel = seqstrings.getAlignmentAndColumnSelection(gc);
339 if (alAndColsel != null && alAndColsel[0] != null)
341 // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
343 Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
344 Alignment dataset = (av != null && av.getAlignment() != null) ? av
345 .getAlignment().getDataset() : null;
348 al.setDataset(dataset);
354 AlignFrame af = new AlignFrame(al,
355 (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
356 AlignFrame.DEFAULT_HEIGHT);
358 // >>>This is a fix for the moment, until a better solution is
360 // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());
362 // af.addSortByOrderMenuItem(ServiceName + " Ordering",
365 Desktop.addInternalFrame(af, "Original Data for " + this.title,
366 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
370 * CutAndPasteTransfer cap = new CutAndPasteTransfer(); for (int i = 0; i <
371 * seqs.length; i++) { cap.appendText(new jalview.util.Format("%-" + 15 +
372 * "s").form( seqs[i].getName())); cap.appendText(" " + seqstrings[i] +
375 * Desktop.addInternalFrame(cap, "Original Data", 400, 400);
379 class PCAPrinter extends Thread implements Printable
383 PrinterJob printJob = PrinterJob.getPrinterJob();
384 PageFormat pf = printJob.pageDialog(printJob.defaultPage());
386 printJob.setPrintable(this, pf);
388 if (printJob.printDialog())
393 } catch (Exception PrintException)
395 PrintException.printStackTrace();
400 public int print(Graphics pg, PageFormat pf, int pi)
401 throws PrinterException
403 pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());
405 rc.drawBackground(pg, rc.bgColour);
407 if (rc.drawAxes == true)
414 return Printable.PAGE_EXISTS;
418 return Printable.NO_SUCH_PAGE;
429 public void eps_actionPerformed(ActionEvent e)
431 makePCAImage(jalview.util.ImageMaker.EPS);
440 public void png_actionPerformed(ActionEvent e)
442 makePCAImage(jalview.util.ImageMaker.PNG);
445 void makePCAImage(int type)
447 int width = rc.getWidth();
448 int height = rc.getHeight();
450 jalview.util.ImageMaker im;
452 if (type == jalview.util.ImageMaker.PNG)
454 im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.PNG,
455 "Make PNG image from PCA", width, height, null, null);
459 im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.EPS,
460 "Make EPS file from PCA", width, height, null,
464 if (im.getGraphics() != null)
466 rc.drawBackground(im.getGraphics(), Color.black);
467 rc.drawScene(im.getGraphics());
468 if (rc.drawAxes == true)
470 rc.drawAxes(im.getGraphics());
476 public void viewMenu_menuSelected()
478 buildAssociatedViewMenu();
481 void buildAssociatedViewMenu()
483 AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(av
484 .getSequenceSetId());
485 if (aps.length == 1 && rc.av == aps[0].av)
487 associateViewsMenu.setVisible(false);
491 associateViewsMenu.setVisible(true);
493 if ((viewMenu.getItem(viewMenu.getItemCount() - 2) instanceof JMenuItem))
495 viewMenu.insertSeparator(viewMenu.getItemCount() - 1);
498 associateViewsMenu.removeAll();
500 JRadioButtonMenuItem item;
501 ButtonGroup buttonGroup = new ButtonGroup();
502 int i, iSize = aps.length;
503 final PCAPanel thisPCAPanel = this;
504 for (i = 0; i < iSize; i++)
506 final AlignmentPanel ap = aps[i];
507 item = new JRadioButtonMenuItem(ap.av.viewName, ap.av == rc.av);
508 buttonGroup.add(item);
509 item.addActionListener(new ActionListener()
511 public void actionPerformed(ActionEvent evt)
513 rc.applyToAllViews = false;
516 PaintRefresher.Register(thisPCAPanel, ap.av.getSequenceSetId());
520 associateViewsMenu.add(item);
523 final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem("All Views");
525 buttonGroup.add(itemf);
527 itemf.setSelected(rc.applyToAllViews);
528 itemf.addActionListener(new ActionListener()
530 public void actionPerformed(ActionEvent evt)
532 rc.applyToAllViews = itemf.isSelected();
535 associateViewsMenu.add(itemf);
543 * jalview.jbgui.GPCAPanel#outputPoints_actionPerformed(java.awt.event.ActionEvent
546 protected void outputPoints_actionPerformed(ActionEvent e)
548 CutAndPasteTransfer cap = new CutAndPasteTransfer();
551 cap.setText(getPointsasCsv(false));
552 Desktop.addInternalFrame(cap, "Points for " + getTitle(), 500, 500);
553 } catch (OutOfMemoryError oom)
555 new OOMWarning("exporting PCA points", oom);
560 private String getPointsasCsv(boolean transformed)
562 StringBuffer csv = new StringBuffer();
563 csv.append("\"Sequence\"");
567 csv.append(xCombobox.getSelectedIndex());
569 csv.append(yCombobox.getSelectedIndex());
571 csv.append(zCombobox.getSelectedIndex());
575 for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++)
581 for (int s = 0; s < seqs.length; s++)
583 csv.append("\"" + seqs[s].getName() + "\"");
587 // output pca in correct order
588 fl = pca.component(s);
589 for (int d = fl.length - 1; d >= 0; d--)
597 // output current x,y,z coords for points
598 fl = rc.getPointPosition(s);
599 for (int d = 0; d < fl.length; d++)
607 return csv.toString();
614 * jalview.jbgui.GPCAPanel#outputProjPoints_actionPerformed(java.awt.event
617 protected void outputProjPoints_actionPerformed(ActionEvent e)
619 CutAndPasteTransfer cap = new CutAndPasteTransfer();
622 cap.setText(getPointsasCsv(true));
623 Desktop.addInternalFrame(cap, "Transformed points for " + getTitle(),
625 } catch (OutOfMemoryError oom)
627 new OOMWarning("exporting transformed PCA points", oom);
632 // methods for implementing IProgressIndicator
633 // need to refactor to a reusable stub class
634 Hashtable progressBars, progressBarHandlers;
639 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
642 public void setProgressBar(String message, long id)
644 if (progressBars == null)
646 progressBars = new Hashtable();
647 progressBarHandlers = new Hashtable();
650 JPanel progressPanel;
651 Long lId = new Long(id);
652 GridLayout layout = (GridLayout) statusPanel.getLayout();
653 if (progressBars.get(lId) != null)
655 progressPanel = (JPanel) progressBars.get(new Long(id));
656 statusPanel.remove(progressPanel);
657 progressBars.remove(lId);
658 progressPanel = null;
661 statusBar.setText(message);
663 if (progressBarHandlers.contains(lId))
665 progressBarHandlers.remove(lId);
667 layout.setRows(layout.getRows() - 1);
671 progressPanel = new JPanel(new BorderLayout(10, 5));
673 JProgressBar progressBar = new JProgressBar();
674 progressBar.setIndeterminate(true);
676 progressPanel.add(new JLabel(message), BorderLayout.WEST);
677 progressPanel.add(progressBar, BorderLayout.CENTER);
679 layout.setRows(layout.getRows() + 1);
680 statusPanel.add(progressPanel);
682 progressBars.put(lId, progressPanel);
685 // setMenusForViewport();
690 public void registerHandler(final long id,
691 final IProgressIndicatorHandler handler)
693 if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
696 "call setProgressBar before registering the progress bar's handler.");
698 progressBarHandlers.put(new Long(id), handler);
699 final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
700 if (handler.canCancel())
702 JButton cancel = new JButton("Cancel");
703 final IProgressIndicator us = this;
704 cancel.addActionListener(new ActionListener()
708 public void actionPerformed(ActionEvent e)
710 handler.cancelActivity(id);
713 + ((JLabel) progressPanel.getComponent(0))
717 progressPanel.add(cancel, BorderLayout.EAST);
723 * @return true if any progress bars are still active
726 public boolean operationInProgress()
728 if (progressBars != null && progressBars.size() > 0)
735 protected void resetButton_actionPerformed(ActionEvent e)
738 top=0; // ugly - prevents dimensionChanged events from being processed
739 xCombobox.setSelectedIndex(0);
740 yCombobox.setSelectedIndex(1);
742 zCombobox.setSelectedIndex(2);