*/
package jalview.gui;
+import static jalview.math.RotatableMatrix.Axis.X;
+import static jalview.math.RotatableMatrix.Axis.Y;
+import static jalview.math.RotatableMatrix.Axis.Z;
+
import jalview.analysis.Conservation;
+import jalview.analysis.PCA;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
import jalview.api.FeatureColourI;
import jalview.api.ViewStyleI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityParamsI;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.GraphLine;
import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Point;
import jalview.datamodel.RnaViewerModel;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import jalview.io.FileFormat;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
import jalview.renderer.ResidueShaderI;
import jalview.schemabinding.version2.AlcodMap;
import jalview.schemabinding.version2.AlcodonFrame;
import jalview.schemabinding.version2.Annotation;
import jalview.schemabinding.version2.AnnotationColours;
import jalview.schemabinding.version2.AnnotationElement;
+import jalview.schemabinding.version2.Axis;
import jalview.schemabinding.version2.CalcIdParam;
-import jalview.schemabinding.version2.Colour;
import jalview.schemabinding.version2.CompoundMatcher;
+import jalview.schemabinding.version2.D;
import jalview.schemabinding.version2.DBRef;
+import jalview.schemabinding.version2.DoubleMatrix;
+import jalview.schemabinding.version2.E;
+import jalview.schemabinding.version2.EigenMatrix;
import jalview.schemabinding.version2.Features;
import jalview.schemabinding.version2.Group;
import jalview.schemabinding.version2.HiddenColumns;
import jalview.schemabinding.version2.MatchCondition;
import jalview.schemabinding.version2.MatcherSet;
import jalview.schemabinding.version2.OtherData;
+import jalview.schemabinding.version2.PairwiseMatrix;
+import jalview.schemabinding.version2.PcaData;
+import jalview.schemabinding.version2.PcaViewer;
import jalview.schemabinding.version2.PdbentryItem;
import jalview.schemabinding.version2.Pdbids;
import jalview.schemabinding.version2.Property;
import jalview.schemabinding.version2.RnaViewer;
+import jalview.schemabinding.version2.Row;
import jalview.schemabinding.version2.SecondaryStructure;
+import jalview.schemabinding.version2.SeqPointMax;
+import jalview.schemabinding.version2.SeqPointMin;
import jalview.schemabinding.version2.Sequence;
+import jalview.schemabinding.version2.SequencePoint;
import jalview.schemabinding.version2.SequenceSet;
import jalview.schemabinding.version2.SequenceSetProperties;
import jalview.schemabinding.version2.Setting;
import jalview.schemabinding.version2.StructureState;
import jalview.schemabinding.version2.ThresholdLine;
import jalview.schemabinding.version2.Tree;
+import jalview.schemabinding.version2.TridiagonalMatrix;
import jalview.schemabinding.version2.UserColours;
import jalview.schemabinding.version2.Viewport;
import jalview.schemabinding.version2.types.ColourThreshTypeType;
import jalview.util.jarInputStreamProvider;
import jalview.util.matcher.Condition;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.PCAModel;
import jalview.viewmodel.ViewportRanges;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
private static final String UTF_8 = "UTF-8";
+ /**
+ * prefix for recovering datasets for alignments with multiple views where
+ * non-existent dataset IDs were written for some views
+ */
+ private static final String UNIQSEQSETID = "uniqueSeqSetId.";
+
// use this with nextCounter() to make unique names for entities
private int counter = 0;
{
TreePanel tp = (TreePanel) frames[t];
- if (tp.treeCanvas.av.getAlignment() == jal)
+ if (tp.getTreeCanvas().getViewport().getAlignment() == jal)
{
Tree tree = new Tree();
tree.setTitle(tp.getTitle());
tree.setCurrentTree((av.getCurrentTree() == tp.getTree()));
tree.setNewick(tp.getTree().print());
- tree.setThreshold(tp.treeCanvas.threshold);
+ tree.setThreshold(tp.getTreeCanvas().getThreshold());
tree.setFitToWindow(tp.fitToWindow.getState());
tree.setFontName(tp.getTreeFont().getName());
tree.setXpos(tp.getX());
tree.setYpos(tp.getY());
tree.setId(makeHashCode(tp, null));
+ tree.setLinkToAllViews(tp.getTreeCanvas().applyToAllViews);
jms.addTree(tree);
}
}
}
}
+ /*
+ * save PCA viewers
+ */
+ if (!storeDS && Desktop.desktop != null)
+ {
+ for (JInternalFrame frame : Desktop.desktop.getAllFrames())
+ {
+ if (frame instanceof PCAPanel)
+ {
+ PCAPanel panel = (PCAPanel) frame;
+ if (panel.av.getAlignment() == jal)
+ {
+ savePCA(panel, jms);
+ }
+ }
+ }
+ }
+
// SAVE ANNOTATIONS
/**
* store forward refs from an annotationRow to any groups
{
view.setComplementId(av.getCodingComplement().getViewId());
}
- view.setViewName(av.viewName);
+ view.setViewName(av.getViewName());
view.setGatheredViews(av.isGatherViewsHere());
Rectangle size = ap.av.getExplodedGeometry();
}
else
{
- ArrayList<int[]> hiddenRegions = hidden.getHiddenColumnsCopy();
- for (int[] region : hiddenRegions)
+ Iterator<int[]> hiddenRegions = hidden.iterator();
+ while (hiddenRegions.hasNext())
{
+ int[] region = hiddenRegions.next();
HiddenColumns hc = new HiddenColumns();
hc.setStart(region[0]);
hc.setEnd(region[1]);
}
/**
+ * Writes PCA viewer attributes and computed values to an XML model object and adds it to the JalviewModel. Any exceptions are reported by logging.
+ */
+ protected void savePCA(PCAPanel panel, JalviewModelSequence jms)
+ {
+ try
+ {
+ PcaViewer viewer = new PcaViewer();
+ viewer.setHeight(panel.getHeight());
+ viewer.setWidth(panel.getWidth());
+ viewer.setXpos(panel.getX());
+ viewer.setYpos(panel.getY());
+ viewer.setTitle(panel.getTitle());
+ PCAModel pcaModel = panel.getPcaModel();
+ viewer.setScoreModelName(pcaModel.getScoreModelName());
+ viewer.setXDim(panel.getSelectedDimensionIndex(X));
+ viewer.setYDim(panel.getSelectedDimensionIndex(Y));
+ viewer.setZDim(panel.getSelectedDimensionIndex(Z));
+ viewer.setBgColour(panel.getRotatableCanvas().getBackgroundColour().getRGB());
+ viewer.setScaleFactor(panel.getRotatableCanvas().getScaleFactor());
+ float[] spMin = panel.getRotatableCanvas().getSeqMin();
+ SeqPointMin spmin = new SeqPointMin();
+ spmin.setXPos(spMin[0]);
+ spmin.setYPos(spMin[1]);
+ spmin.setZPos(spMin[2]);
+ viewer.setSeqPointMin(spmin);
+ float[] spMax = panel.getRotatableCanvas().getSeqMax();
+ SeqPointMax spmax = new SeqPointMax();
+ spmax.setXPos(spMax[0]);
+ spmax.setYPos(spMax[1]);
+ spmax.setZPos(spMax[2]);
+ viewer.setSeqPointMax(spmax);
+ viewer.setShowLabels(panel.getRotatableCanvas().isShowLabels());
+ viewer.setLinkToAllViews(panel.getRotatableCanvas().isApplyToAllViews());
+ SimilarityParamsI sp = pcaModel.getSimilarityParameters();
+ viewer.setIncludeGaps(sp.includeGaps());
+ viewer.setMatchGaps(sp.matchGaps());
+ viewer.setIncludeGappedColumns(sp.includeGappedColumns());
+ viewer.setDenominateByShortestLength(sp.denominateByShortestLength());
+
+ /*
+ * sequence points on display
+ */
+ for (jalview.datamodel.SequencePoint spt : pcaModel
+ .getSequencePoints())
+ {
+ SequencePoint point = new SequencePoint();
+ point.setSequenceRef(seqHash(spt.getSequence()));
+ point.setXPos(spt.coord.x);
+ point.setYPos(spt.coord.y);
+ point.setZPos(spt.coord.z);
+ viewer.addSequencePoint(point);
+ }
+
+ /*
+ * (end points of) axes on display
+ */
+ for (Point p : panel.getRotatableCanvas().getAxisEndPoints())
+ {
+ Axis axis = new Axis();
+ axis.setXPos(p.x);
+ axis.setYPos(p.y);
+ axis.setZPos(p.z);
+ viewer.addAxis(axis);
+ }
+
+ /*
+ * raw PCA data (note we are not restoring PCA inputs here -
+ * alignment view, score model, similarity parameters)
+ */
+ PcaData data = new PcaData();
+ viewer.setPcaData(data);
+ PCA pca = pcaModel.getPcaData();
+
+ PairwiseMatrix pm = new PairwiseMatrix();
+ saveDoubleMatrix(pca.getPairwiseScores(), pm);
+ data.setPairwiseMatrix(pm);
+
+ TridiagonalMatrix tm = new TridiagonalMatrix();
+ saveDoubleMatrix(pca.getTridiagonal(), tm);
+ data.setTridiagonalMatrix(tm);
+
+ EigenMatrix eigenMatrix = new EigenMatrix();
+ data.setEigenMatrix(eigenMatrix);
+ saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix);
+
+ jms.addPcaViewer(viewer);
+ } catch (Throwable t)
+ {
+ Cache.log.error("Error saving PCA: " + t.getMessage());
+ }
+ }
+
+ /**
+ * Stores values from a matrix into an XML element, including (if present) the
+ * D or E vectors
+ *
+ * @param m
+ * @param xmlMatrix
+ * @see #loadDoubleMatrix(DoubleMatrix)
+ */
+ protected void saveDoubleMatrix(MatrixI m, DoubleMatrix xmlMatrix)
+ {
+ xmlMatrix.setRows(m.height());
+ xmlMatrix.setColumns(m.width());
+ for (int i = 0; i < m.height(); i++)
+ {
+ Row row = new Row();
+ for (int j = 0; j < m.width(); j++)
+ {
+ row.addV(m.getValue(i, j));
+ }
+ xmlMatrix.addRow(row);
+ }
+ if (m.getD() != null)
+ {
+ D dVector = new D();
+ dVector.setV(m.getD());
+ xmlMatrix.setD(dVector);
+ }
+ if (m.getE() != null)
+ {
+ E eVector = new E();
+ eVector.setV(m.getE());
+ xmlMatrix.setE(eVector);
+ }
+ }
+
+ /**
+ * Loads XML matrix data into a new Matrix object, including the D and/or E
+ * vectors (if present)
+ *
+ * @param mData
+ * @return
+ * @see Jalview2XML#saveDoubleMatrix(MatrixI, DoubleMatrix)
+ */
+ protected MatrixI loadDoubleMatrix(DoubleMatrix mData)
+ {
+ int rows = mData.getRows();
+ double[][] vals = new double[rows][];
+
+ for (int i = 0; i < rows; i++)
+ {
+ vals[i] = mData.getRow(i).getV();
+ }
+
+ MatrixI m = new Matrix(vals);
+
+ if (mData.getD() != null) {
+ m.setD(mData.getD().getV());
+ }
+ if (mData.getE() != null)
+ {
+ m.setE(mData.getE().getV());
+ }
+
+ return m;
+ }
+
+ /**
* Save any Varna viewers linked to this sequence. Writes an rnaViewer element
* for each viewer, with
* <ul>
: null;
// ////////////////////////////////
+ // INITIALISE ALIGNMENT SEQUENCESETID AND VIEWID
+ //
+ //
+ // If we just load in the same jar file again, the sequenceSetId
+ // will be the same, and we end up with multiple references
+ // to the same sequenceSet. We must modify this id on load
+ // so that each load of the file gives a unique id
+
+ /**
+ * used to resolve correct alignment dataset for alignments with multiple
+ * views
+ */
+ String uniqueSeqSetId = null;
+ String viewId = null;
+ if (view != null)
+ {
+ uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
+ viewId = (view.getId() == null ? null
+ : view.getId() + uniqueSetSuffix);
+ }
+
+ // ////////////////////////////////
// LOAD SEQUENCES
List<SequenceI> hiddenSeqs = null;
// finally, verify all data in vamsasSet is actually present in al
// passing on flag indicating if it is actually a stored dataset
- recoverDatasetFor(vamsasSet, al, isdsal);
+ recoverDatasetFor(vamsasSet, al, isdsal, uniqueSeqSetId);
}
if (referenceseqForView != null)
// ///////////////////////////////
// LOAD VIEWPORT
- // If we just load in the same jar file again, the sequenceSetId
- // will be the same, and we end up with multiple references
- // to the same sequenceSet. We must modify this id on load
- // so that each load of the file gives a unique id
- String uniqueSeqSetId = view.getSequenceSetId() + uniqueSetSuffix;
- String viewId = (view.getId() == null ? null
- : view.getId() + uniqueSetSuffix);
AlignFrame af = null;
AlignViewport av = null;
// now check to see if we really need to create a new viewport.
if (loadTreesAndStructures)
{
loadTrees(jms, view, af, av, ap);
+ loadPCAViewers(jms, ap);
loadPDBStructures(jprovider, jseqs, af, ap);
loadRnaViewers(jprovider, jseqs, ap);
}
tp.setTitle(tree.getTitle());
tp.setBounds(new Rectangle(tree.getXpos(), tree.getYpos(),
tree.getWidth(), tree.getHeight()));
- tp.av = av; // af.viewport; // TODO: verify 'associate with all
+ tp.setViewport(av); // af.viewport; // TODO: verify 'associate with all
// views'
// works still
- tp.treeCanvas.av = av; // af.viewport;
- tp.treeCanvas.ap = ap; // af.alignPanel;
-
+ tp.getTreeCanvas().setViewport(av); // af.viewport;
+ tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel;
}
if (tp == null)
{
tp.showBootstrap(tree.getShowBootstrap());
tp.showDistances(tree.getShowDistances());
- tp.treeCanvas.threshold = tree.getThreshold();
+ tp.getTreeCanvas().setThreshold(tree.getThreshold());
+ tp.getTreeCanvas().applyToAllViews = tree.isLinkToAllViews();
if (tree.getCurrentTree())
{
if (view.getViewName() != null)
{
- af.viewport.viewName = view.getViewName();
+ af.viewport.setViewName(view.getViewName());
af.setInitialTabVisible();
}
af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(),
}
private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
- boolean ignoreUnrefed)
+ boolean ignoreUnrefed, String uniqueSeqSetId)
{
jalview.datamodel.AlignmentI ds = getDatasetFor(
vamsasSet.getDatasetId());
Vector dseqs = null;
if (ds == null)
{
+ if (!ignoreUnrefed)
+ {
+ // try to resolve the dataset via uniqueSeqSetId
+ ds = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId);
+ if (ds != null)
+ {
+ addDatasetRef(vamsasSet.getDatasetId(), ds);
+ }
+ }
+ }
+ if (ds == null)
+ {
// create a list of new dataset sequences
dseqs = new Vector();
}
if (al.getDataset() == null && !ignoreUnrefed)
{
al.setDataset(ds);
+ // register dataset for the alignment's uniqueSeqSetId for legacy projects
+ addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds);
}
}
initSeqRefs();
JalviewModel jm = saveState(ap, null, null, null);
+ addDatasetRef(jm.getVamsasModel().getSequenceSet()[0].getDatasetId(),
+ ap.getAlignment().getDataset());
+
uniqueSetSuffix = "";
jm.getJalviewModelSequence().getViewport(0).setId(null);
// we don't overwrite the view we just copied
}
/**
+ * Loads any saved PCA viewers
+ *
+ * @param jms
+ * @param ap
+ */
+ protected void loadPCAViewers(JalviewModelSequence jms, AlignmentPanel ap)
+ {
+ try
+ {
+ for (int t = 0; t < jms.getPcaViewerCount(); t++)
+ {
+ PcaViewer viewer = jms.getPcaViewer(t);
+ String modelName = viewer.getScoreModelName();
+ SimilarityParamsI params = new SimilarityParams(
+ viewer.isIncludeGappedColumns(),
+ viewer.isMatchGaps(), viewer.isIncludeGaps(),
+ viewer.isDenominateByShortestLength());
+
+ /*
+ * create the panel (without computing the PCA)
+ */
+ PCAPanel panel = new PCAPanel(ap, modelName, params);
+
+ panel.setTitle(viewer.getTitle());
+ panel.setBounds(new Rectangle(viewer.getXpos(), viewer.getYpos(),
+ viewer.getWidth(), viewer.getHeight()));
+
+ boolean showLabels = viewer.isShowLabels();
+ panel.setShowLabels(showLabels);
+ panel.getRotatableCanvas().setShowLabels(showLabels);
+ panel.getRotatableCanvas().setBgColour(new Color(viewer.getBgColour()));
+ panel.getRotatableCanvas().setApplyToAllViews(viewer.isLinkToAllViews());
+
+ /*
+ * load PCA output data
+ */
+ ScoreModelI scoreModel = ScoreModels.getInstance()
+ .getScoreModel(modelName, ap);
+ PCA pca = new PCA(null, scoreModel, params);
+ PcaData pcaData = viewer.getPcaData();
+
+ MatrixI pairwise = loadDoubleMatrix(pcaData.getPairwiseMatrix());
+ pca.setPairwiseScores(pairwise);
+
+ MatrixI triDiag = loadDoubleMatrix(pcaData.getTridiagonalMatrix());
+ pca.setTridiagonal(triDiag);
+
+ MatrixI result = loadDoubleMatrix(pcaData.getEigenMatrix());
+ pca.setEigenmatrix(result);
+
+ panel.getPcaModel().setPCA(pca);
+
+ /*
+ * we haven't saved the input data! (JAL-2647 to do)
+ */
+ panel.setInputData(null);
+
+ /*
+ * add the sequence points for the PCA display
+ */
+ List<jalview.datamodel.SequencePoint> seqPoints = new ArrayList<>();
+ for (SequencePoint sp : viewer.getSequencePoint())
+ {
+ String seqId = sp.getSequenceRef();
+ SequenceI seq = seqRefIds.get(seqId);
+ if (seq == null)
+ {
+ throw new IllegalStateException(
+ "Unmatched seqref for PCA: " + seqId);
+ }
+ Point pt = new Point(sp.getXPos(), sp.getYPos(), sp.getZPos());
+ jalview.datamodel.SequencePoint seqPoint = new jalview.datamodel.SequencePoint(
+ seq, pt);
+ seqPoints.add(seqPoint);
+ }
+ panel.getRotatableCanvas().setPoints(seqPoints, seqPoints.size());
+
+ /*
+ * set min-max ranges and scale after setPoints (which recomputes them)
+ */
+ panel.getRotatableCanvas().setScaleFactor(viewer.getScaleFactor());
+ SeqPointMin spMin = viewer.getSeqPointMin();
+ float[] min = new float[] { spMin.getXPos(), spMin.getYPos(),
+ spMin.getZPos() };
+ SeqPointMax spMax = viewer.getSeqPointMax();
+ float[] max = new float[] { spMax.getXPos(), spMax.getYPos(),
+ spMax.getZPos() };
+ panel.getRotatableCanvas().setSeqMinMax(min, max);
+
+ // todo: hold points list in PCAModel only
+ panel.getPcaModel().setSequencePoints(seqPoints);
+
+ panel.setSelectedDimensionIndex(viewer.getXDim(), X);
+ panel.setSelectedDimensionIndex(viewer.getYDim(), Y);
+ panel.setSelectedDimensionIndex(viewer.getZDim(), Z);
+
+ // is this duplication needed?
+ panel.setTop(seqPoints.size() - 1);
+ panel.getPcaModel().setTop(seqPoints.size() - 1);
+
+ /*
+ * add the axes' end points for the display
+ */
+ for (int i = 0; i < 3; i++)
+ {
+ Axis axis = viewer.getAxis(i);
+ panel.getRotatableCanvas().getAxisEndPoints()[i] = new Point(axis.getXPos(),
+ axis.getYPos(), axis.getZPos());
+ }
+
+ Desktop.addInternalFrame(panel, MessageManager.formatMessage(
+ "label.calc_title", "PCA", modelName), 475, 450);
+ }
+ } catch (Exception ex)
+ {
+ Cache.log.error("Error loading PCA: " + ex.toString());
+ }
+ }
+
+ /**
* Populates an XML model of the feature colour scheme for one feature type
*
* @param featureType