Merge branch 'kjvdh/features/PhylogenyViewer_tabbedsupport' into merge/2_11_2/kjvdh...
[jalview.git] / src / jalview / appletgui / PCAPanel.java
old mode 100755 (executable)
new mode 100644 (file)
index 6568b5b..fe9d69b
@@ -1,46 +1,65 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
- * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- * 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  * PURPOSE.  See the GNU General Public License for more details.
  * 
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.appletgui;
 
-import java.util.*;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import jalview.analysis.*;
-import jalview.datamodel.*;
-
-public class PCAPanel extends EmbmenuFrame implements Runnable,
-        ActionListener, ItemListener
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.analysis.ScoreModelI;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.SequenceI;
+import jalview.util.MessageManager;
+import jalview.viewmodel.PCAModel;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.CheckboxMenuItem;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+public class PCAPanel extends EmbmenuFrame
+        implements Runnable, ActionListener, ItemListener
 {
-  PCA pca;
-
-  int top;
-
   RotatableCanvas rc;
 
   AlignViewport av;
 
-  SequenceI[] seqs;
+  PCAModel pcaModel;
 
-  AlignmentView seqstrings;
+  int top = 0;
 
-  public PCAPanel(AlignViewport av)
+  public PCAPanel(AlignViewport viewport)
   {
     try
     {
@@ -57,15 +76,20 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
       zCombobox.addItem("dim " + i);
     }
 
-    this.av = av;
-    seqstrings = av.getAlignmentView(av.getSelectionGroup() != null);
-    if (av.getSelectionGroup() == null)
+    this.av = viewport;
+    boolean selected = viewport.getSelectionGroup() != null
+            && viewport.getSelectionGroup().getSize() > 0;
+    AlignmentView seqstrings = viewport.getAlignmentView(selected);
+    boolean nucleotide = viewport.getAlignment().isNucleotide();
+    SequenceI[] seqs;
+    if (!selected)
     {
-      seqs = av.getAlignment().getSequencesArray();
+      seqs = viewport.getAlignment().getSequencesArray();
     }
     else
     {
-      seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
+      seqs = viewport.getSelectionGroup()
+              .getSequencesInOrder(viewport.getAlignment());
     }
     SeqCigar sq[] = seqstrings.getSequences();
     int length = sq[0].getWidth();
@@ -80,62 +104,55 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
       }
     }
 
-    rc = new RotatableCanvas(av);
+    ScoreModelI scoreModel = ScoreModels.getInstance()
+            .getDefaultModel(!nucleotide);
+    pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+            SimilarityParams.SeqSpace);
+
+    rc = new RotatableCanvas(viewport);
     embedMenuIfNeeded(rc);
     add(rc, BorderLayout.CENTER);
 
-    jalview.bin.JalviewLite.addFrame(this, "Principal component analysis",
-            400, 400);
+    jalview.bin.JalviewLite.addFrame(this,
+            MessageManager.getString("label.principal_component_analysis"),
+            475, 400);
 
-    Thread worker = new Thread(this);
+    Thread worker = new Thread(this, "PCACalcThread");
     worker.start();
   }
 
   /**
    * DOCUMENT ME!
    */
+  @Override
   public void run()
   {
-    pca = new PCA(seqstrings.getSequenceStrings(' '));
-    pca.run();
-
-    // Now find the component coordinates
-    int ii = 0;
-
-    while ((ii < seqs.length) && (seqs[ii] != null))
-    {
-      ii++;
-    }
-
-    double[][] comps = new double[ii][ii];
-
-    for (int i = 0; i < ii; i++)
+    // TODO progress indicator
+    calcSettings.setEnabled(false);
+    rc.setEnabled(false);
+    try
     {
-      if (pca.getEigenvalue(i) > 1e-4)
-      {
-        comps[i] = pca.component(i);
-      }
-    }
-
-    // ////////////////
-    xCombobox.select(0);
-    yCombobox.select(1);
-    zCombobox.select(2);
-
-    top = pca.getM().rows - 1;
-
-    Vector points = new Vector();
-    float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100);
-
-    for (int i = 0; i < pca.getM().rows; i++)
+      nuclSetting.setState(pcaModel.isNucleotide());
+      protSetting.setState(!pcaModel.isNucleotide());
+      pcaModel.calculate();
+      // ////////////////
+      xCombobox.select(0);
+      yCombobox.select(1);
+      zCombobox.select(2);
+
+      pcaModel.updateRc(rc);
+      // rc.invalidate();
+      top = pcaModel.getTop();
+    } catch (OutOfMemoryError x)
     {
-      SequencePoint sp = new SequencePoint(seqs[i], scores[i]);
-      points.addElement(sp);
+      System.err.println("Out of memory when calculating PCA.");
+      return;
     }
+    calcSettings.setEnabled(true);
 
-    rc.setPoints(points, pca.getM().rows);
+    // TODO revert progress indicator
+    rc.setEnabled(true);
     rc.repaint();
-    seqs = null;
     this.repaint();
   }
 
@@ -149,31 +166,32 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     int dim1 = top - xCombobox.getSelectedIndex();
     int dim2 = top - yCombobox.getSelectedIndex();
     int dim3 = top - zCombobox.getSelectedIndex();
-
-    float[][] scores = pca.getComponents(dim1, dim2, dim3, 100);
-    for (int i = 0; i < pca.getM().rows; i++)
-    {
-      ((SequencePoint) rc.points.elementAt(i)).coord = scores[i];
-    }
-
-    rc.img = null;
-    rc.rotmat.setIdentity();
-    rc.initAxes();
+    pcaModel.updateRcView(dim1, dim2, dim3);
+    rc.resetView();
     rc.paint(rc.getGraphics());
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == inputData)
     {
       showOriginalData();
     }
-    else
+    if (evt.getSource() == resetButton)
+    {
+      xCombobox.select(0);
+      yCombobox.select(1);
+      zCombobox.select(2);
+      doDimensionChange();
+    }
+    if (evt.getSource() == values)
     {
       values_actionPerformed();
     }
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     if (evt.getSource() == xCombobox)
@@ -188,6 +206,32 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     {
       zCombobox_actionPerformed();
     }
+    else if (evt.getSource() == labels)
+    {
+      labels_itemStateChanged(evt);
+    }
+    else if (evt.getSource() == nuclSetting)
+    {
+      if (!pcaModel.isNucleotide())
+      {
+        pcaModel.setNucleotide(true);
+        ScoreModelI scoreModel = ScoreModels.getInstance()
+                .getDefaultModel(false);
+        pcaModel.setScoreModel(scoreModel);
+        new Thread(this, "PCARecalcThread").start();
+      }
+    }
+    else if (evt.getSource() == protSetting)
+    {
+      if (pcaModel.isNucleotide())
+      {
+        pcaModel.setNucleotide(false);
+        ScoreModelI scoreModel = ScoreModels.getInstance()
+                .getDefaultModel(true);
+        pcaModel.setScoreModel(scoreModel);
+        new Thread(this, "PCARecalcThread").start();
+      }
+    }
   }
 
   protected void xCombobox_actionPerformed()
@@ -211,9 +255,10 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, null);
     Frame frame = new Frame();
     frame.add(cap);
-    jalview.bin.JalviewLite.addFrame(frame, "PCA details", 500, 500);
+    jalview.bin.JalviewLite.addFrame(frame,
+            MessageManager.getString("label.pca_details"), 500, 500);
 
-    cap.setText(pca.getDetails());
+    cap.setText(pcaModel.getDetails());
   }
 
   void showOriginalData()
@@ -234,15 +279,17 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     {
     }
     ;
-    Object[] alAndColsel = seqstrings.getAlignmentAndColumnSelection(gc);
+    Object[] alAndColsel = pcaModel.getInputData()
+            .getAlignmentAndHiddenColumns(gc);
 
     if (alAndColsel != null && alAndColsel[0] != null)
     {
       Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
-      AlignFrame af = new AlignFrame(al, av.applet,
-              "Original Data for PCA", false);
+      AlignFrame af = new AlignFrame(al, av.applet, "Original Data for PCA",
+              false);
 
-      af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
+      af.viewport.getAlignment()
+              .setHiddenColumns((HiddenColumns) alAndColsel[1]);
     }
   }
 
@@ -265,6 +312,8 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
 
   protected Choice zCombobox = new Choice();
 
+  protected Button resetButton = new Button();
+
   FlowLayout flowLayout1 = new FlowLayout();
 
   BorderLayout borderLayout1 = new BorderLayout();
@@ -275,8 +324,14 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
 
   Menu menu2 = new Menu();
 
+  Menu calcSettings = new Menu();
+
   protected CheckboxMenuItem labels = new CheckboxMenuItem();
 
+  protected CheckboxMenuItem protSetting = new CheckboxMenuItem();
+
+  protected CheckboxMenuItem nuclSetting = new CheckboxMenuItem();
+
   MenuItem values = new MenuItem();
 
   MenuItem inputData = new MenuItem();
@@ -298,14 +353,23 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     yCombobox.addItemListener(this);
     xCombobox.setFont(new java.awt.Font("Verdana", 0, 12));
     xCombobox.addItemListener(this);
+    resetButton.setFont(new java.awt.Font("Verdana", 0, 12));
+    resetButton.setLabel(MessageManager.getString("action.reset"));
+    resetButton.addActionListener(this);
     this.setMenuBar(menuBar1);
-    menu1.setLabel("File");
-    menu2.setLabel("View");
-    labels.setLabel("Labels");
+    menu1.setLabel(MessageManager.getString("action.file"));
+    menu2.setLabel(MessageManager.getString("action.view"));
+    calcSettings.setLabel(MessageManager.getString("action.change_params"));
+    labels.setLabel(MessageManager.getString("label.labels"));
     labels.addItemListener(this);
-    values.setLabel("Output Values...");
+    values.setLabel(MessageManager.getString("label.output_values"));
     values.addActionListener(this);
-    inputData.setLabel("Input Data...");
+    inputData.setLabel(MessageManager.getString("label.input_data"));
+    nuclSetting
+            .setLabel(MessageManager.getString("label.nucleotide_matrix"));
+    nuclSetting.addItemListener(this);
+    protSetting.setLabel(MessageManager.getString("label.protein_matrix"));
+    protSetting.addItemListener(this);
     this.add(jPanel2, BorderLayout.SOUTH);
     jPanel2.add(jLabel1, null);
     jPanel2.add(xCombobox, null);
@@ -313,11 +377,15 @@ public class PCAPanel extends EmbmenuFrame implements Runnable,
     jPanel2.add(yCombobox, null);
     jPanel2.add(jLabel3, null);
     jPanel2.add(zCombobox, null);
+    jPanel2.add(resetButton, null);
     menuBar1.add(menu1);
     menuBar1.add(menu2);
+    menuBar1.add(calcSettings);
     menu2.add(labels);
     menu1.add(values);
     menu1.add(inputData);
+    calcSettings.add(nuclSetting);
+    calcSettings.add(protSetting);
     inputData.addActionListener(this);
   }