From 55c883270e9f64da9562a24f09dfe5f2f079e59a Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 15 Jun 2012 15:54:28 +0100 Subject: [PATCH] JAL-535 refactored core code from PCA viewer to viewmodel. --- src/jalview/api/RotatableCanvasI.java | 17 +++ src/jalview/appletgui/RotatableCanvas.java | 3 +- src/jalview/gui/PCAPanel.java | 144 ++++----------------- src/jalview/gui/RotatableCanvas.java | 3 +- src/jalview/viewmodel/PCAModel.java | 190 ++++++++++++++++++++++++++++ 5 files changed, 236 insertions(+), 121 deletions(-) create mode 100644 src/jalview/api/RotatableCanvasI.java create mode 100644 src/jalview/viewmodel/PCAModel.java diff --git a/src/jalview/api/RotatableCanvasI.java b/src/jalview/api/RotatableCanvasI.java new file mode 100644 index 0000000..0d3d184 --- /dev/null +++ b/src/jalview/api/RotatableCanvasI.java @@ -0,0 +1,17 @@ +package jalview.api; + +import jalview.datamodel.SequencePoint; + +import java.util.Vector; + +/** + * interface implemented by RotatatableCanvas GUI elements (such as point clouds and simple structure views) + * @author jimp + * + */ +public interface RotatableCanvasI +{ + + void setPoints(Vector points, int rows); + +} diff --git a/src/jalview/appletgui/RotatableCanvas.java b/src/jalview/appletgui/RotatableCanvas.java index ce03ef0..177e5ad 100755 --- a/src/jalview/appletgui/RotatableCanvas.java +++ b/src/jalview/appletgui/RotatableCanvas.java @@ -22,12 +22,13 @@ import java.util.*; import java.awt.*; import java.awt.event.*; +import jalview.api.RotatableCanvasI; import jalview.datamodel.*; import jalview.math.*; import jalview.util.*; public class RotatableCanvas extends Panel implements MouseListener, - MouseMotionListener, KeyListener + MouseMotionListener, KeyListener, RotatableCanvasI { RotatableMatrix idmat = new RotatableMatrix(3, 3); diff --git a/src/jalview/gui/PCAPanel.java b/src/jalview/gui/PCAPanel.java index 4c8a251..eb7806f 100755 --- a/src/jalview/gui/PCAPanel.java +++ b/src/jalview/gui/PCAPanel.java @@ -27,6 +27,7 @@ import javax.swing.*; import jalview.analysis.*; import jalview.datamodel.*; import jalview.jbgui.*; +import jalview.viewmodel.PCAModel; /** * DOCUMENT ME! @@ -37,24 +38,14 @@ import jalview.jbgui.*; public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator { - PCA pca; - - int top; RotatableCanvas rc; AlignmentPanel ap; AlignViewport av; - - AlignmentView seqstrings; - - SequenceI[] seqs; - - /** - * use the identity matrix for calculating similarity between sequences. - */ - private boolean nucleotide=false; + PCAModel pcaModel; + int top=0; /** * Creates a new PCAPanel object. @@ -71,8 +62,9 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator boolean sameLength = true; - seqstrings = av.getAlignmentView(av.getSelectionGroup() != null); - nucleotide=av.getAlignment().isNucleotide(); + AlignmentView seqstrings = av.getAlignmentView(av.getSelectionGroup() != null); + boolean nucleotide=av.getAlignment().isNucleotide(); + SequenceI[] seqs; if (av.getSelectionGroup() == null) { seqs = av.getAlignment().getSequencesArray(); @@ -105,9 +97,9 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator return; } - + pcaModel = new PCAModel(seqstrings, seqs, nucleotide); PaintRefresher.Register(this, av.getSequenceSetId()); - + rc = new RotatableCanvas(ap); this.getContentPane().add(rc, BorderLayout.CENTER); Thread worker = new Thread(this); @@ -142,48 +134,17 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator try { calcSettings.setEnabled(false); - - pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide); - 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++) - { - if (pca.getEigenvalue(i) > 1e-4) - { - comps[i] = pca.component(i); - } - } - + pcaModel.run(); // //////////////// xCombobox.setSelectedIndex(0); yCombobox.setSelectedIndex(1); zCombobox.setSelectedIndex(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++) - { - SequencePoint sp = new SequencePoint(seqs[i], scores[i]); - points.addElement(sp); - } - - rc.setPoints(points, pca.getM().rows); + + pcaModel.updateRc(rc); // rc.invalidate(); - nuclSetting.setSelected(nucleotide); - protSetting.setSelected(!nucleotide); + nuclSetting.setSelected(pcaModel.isNucleotide()); + protSetting.setSelected(!pcaModel.isNucleotide()); + top=pcaModel.getTop(); } catch (OutOfMemoryError er) { @@ -204,9 +165,9 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator @Override protected void nuclSetting_actionPerfomed(ActionEvent arg0) { - if (!nucleotide) + if (!pcaModel.isNucleotide()) { - nucleotide=true; + pcaModel.setNucleotide(true); Thread worker = new Thread(this); worker.start(); } @@ -216,9 +177,9 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator protected void protSetting_actionPerfomed(ActionEvent arg0) { - if (nucleotide) + if (pcaModel.isNucleotide()) { - nucleotide=false; + pcaModel.setNucleotide(false); Thread worker = new Thread(this); worker.start(); } @@ -236,14 +197,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator 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]; - } - + pcaModel.updateRcView(dim1, dim2, dim3); rc.img = null; rc.rotmat.setIdentity(); rc.initAxes(); @@ -288,7 +242,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator CutAndPasteTransfer cap = new CutAndPasteTransfer(); try { - cap.setText(pca.getDetails()); + cap.setText(pcaModel.getDetails()); Desktop.addInternalFrame(cap, "PCA details", 500, 500); } catch (OutOfMemoryError oom) { @@ -312,7 +266,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator { // this was cut'n'pasted from the equivalent TreePanel method - we should // make this an abstract function of all jalview analysis windows - if (seqstrings == null) + if (pcaModel.getSeqtrings() == null) { jalview.bin.Cache.log .info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action."); @@ -334,7 +288,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator { } ; - Object[] alAndColsel = seqstrings.getAlignmentAndColumnSelection(gc); + Object[] alAndColsel = pcaModel.getSeqtrings().getAlignmentAndColumnSelection(gc); if (alAndColsel != null && alAndColsel[0] != null) { @@ -548,7 +502,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator CutAndPasteTransfer cap = new CutAndPasteTransfer(); try { - cap.setText(getPointsasCsv(false)); + cap.setText(pcaModel.getPointsasCsv(false, xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(), zCombobox.getSelectedIndex())); Desktop.addInternalFrame(cap, "Points for " + getTitle(), 500, 500); } catch (OutOfMemoryError oom) { @@ -557,55 +511,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator } } - private String getPointsasCsv(boolean transformed) - { - StringBuffer csv = new StringBuffer(); - csv.append("\"Sequence\""); - if (transformed) - { - csv.append(","); - csv.append(xCombobox.getSelectedIndex()); - csv.append(","); - csv.append(yCombobox.getSelectedIndex()); - csv.append(","); - csv.append(zCombobox.getSelectedIndex()); - } - else - { - for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++) - { - csv.append("," + d); - } - } - csv.append("\n"); - for (int s = 0; s < seqs.length; s++) - { - csv.append("\"" + seqs[s].getName() + "\""); - double fl[]; - if (!transformed) - { - // output pca in correct order - fl = pca.component(s); - for (int d = fl.length - 1; d >= 0; d--) - { - csv.append(","); - csv.append(fl[d]); - } - } - else - { - // output current x,y,z coords for points - fl = rc.getPointPosition(s); - for (int d = 0; d < fl.length; d++) - { - csv.append(","); - csv.append(fl[d]); - } - } - csv.append("\n"); - } - return csv.toString(); - } + /* * (non-Javadoc) @@ -619,7 +525,7 @@ public class PCAPanel extends GPCAPanel implements Runnable, IProgressIndicator CutAndPasteTransfer cap = new CutAndPasteTransfer(); try { - cap.setText(getPointsasCsv(true)); + cap.setText(pcaModel.getPointsasCsv(true, xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(), zCombobox.getSelectedIndex())); Desktop.addInternalFrame(cap, "Transformed points for " + getTitle(), 500, 500); } catch (OutOfMemoryError oom) diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 458a29d..266eedb 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -23,6 +23,7 @@ import java.awt.*; import java.awt.event.*; import javax.swing.*; +import jalview.api.RotatableCanvasI; import jalview.datamodel.*; import jalview.math.*; @@ -33,7 +34,7 @@ import jalview.math.*; * @version $Revision$ */ public class RotatableCanvas extends JPanel implements MouseListener, - MouseMotionListener, KeyListener + MouseMotionListener, KeyListener, RotatableCanvasI { RotatableMatrix idmat = new RotatableMatrix(3, 3); diff --git a/src/jalview/viewmodel/PCAModel.java b/src/jalview/viewmodel/PCAModel.java new file mode 100644 index 0000000..30f8783 --- /dev/null +++ b/src/jalview/viewmodel/PCAModel.java @@ -0,0 +1,190 @@ +package jalview.viewmodel; + +import java.util.Vector; + +import jalview.analysis.PCA; +import jalview.datamodel.AlignmentView; +import jalview.datamodel.SequenceI; +import jalview.datamodel.SequencePoint; +import jalview.api.RotatableCanvasI; + +public class PCAModel +{ + + public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2, + boolean nucleotide2) + { + seqstrings=seqstrings2; + seqs=seqs2; + nucleotide=nucleotide2; + } + + PCA pca; + + int top; + + AlignmentView seqstrings; + + SequenceI[] seqs; + + /** + * use the identity matrix for calculating similarity between sequences. + */ + private boolean nucleotide=false; + + private Vector points; + + public void run() + { + + pca = new PCA(seqstrings.getSequenceStrings(' '), nucleotide); + 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++) + { + if (pca.getEigenvalue(i) > 1e-4) + { + comps[i] = pca.component(i); + } + } + + top = pca.getM().rows - 1; + + points = new Vector(); + float[][] scores = pca.getComponents(top - 1, top - 2, top - 3, 100); + + for (int i = 0; i < pca.getM().rows; i++) + { + SequencePoint sp = new SequencePoint(seqs[i], scores[i]); + points.addElement(sp); + } + + } + + public void updateRc(RotatableCanvasI rc) + { + rc.setPoints(points, pca.getM().rows); + } + + public boolean isNucleotide() + { + return nucleotide; + } + public void setNucleotide(boolean nucleotide) + { + this.nucleotide=nucleotide; + } + + /** + * + * + * @return index of principle dimension of PCA + */ + public int getTop() + { + return top; + } + + /** + * update the 2d coordinates for the list of points to the given dimensions + * Principal dimension is getTop(). Next greated eigenvector is getTop()-1. + * Note - pca.getComponents starts counting the spectrum from zero rather than one, so getComponents(dimN ...) == updateRcView(dimN+1 ..) + * @param dim1 + * @param dim2 + * @param dim3 + */ + public void updateRcView(int dim1, int dim2, int dim3) + { + float[][] scores = pca.getComponents(dim1-1, dim2-1, dim3-1, 100); + + for (int i = 0; i < pca.getM().rows; i++) + { + ((SequencePoint) points.elementAt(i)).coord = scores[i]; + } + } + + public String getDetails() + { + return pca.getDetails(); + } + + public AlignmentView getSeqtrings() + { + return seqstrings; + } + public String getPointsasCsv(boolean transformed, int xdim, int ydim, int zdim) + { + StringBuffer csv = new StringBuffer(); + csv.append("\"Sequence\""); + if (transformed) + { + csv.append(","); + csv.append(xdim); + csv.append(","); + csv.append(ydim); + csv.append(","); + csv.append(zdim); + } + else + { + for (int d = 1, dmax = pca.component(1).length; d <= dmax; d++) + { + csv.append("," + d); + } + } + csv.append("\n"); + for (int s = 0; s < seqs.length; s++) + { + csv.append("\"" + seqs[s].getName() + "\""); + double fl[]; + if (!transformed) + { + // output pca in correct order + fl = pca.component(s); + for (int d = fl.length - 1; d >= 0; d--) + { + csv.append(","); + csv.append(fl[d]); + } + } + else + { + // output current x,y,z coords for points + fl = getPointPosition(s); + for (int d = 0; d < fl.length; d++) + { + csv.append(","); + csv.append(fl[d]); + } + } + csv.append("\n"); + } + return csv.toString(); + } + + /** + * + * @return x,y,z positions of point s (index into points) under current + * transform. + */ + public double[] getPointPosition(int s) + { + double pts[] = new double[3]; + float[] p = points.elementAt(s).coord; + pts[0] = p[0]; + pts[1] = p[1]; + pts[2] = p[2]; + return pts; + } + +} -- 1.7.10.2