X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fproject%2FJalview2XML.java;h=d80fd86abd19705526623106ded1522d55ef4873;hb=21fcce633c77a700ee488806f60b5e4dc8f6895b;hp=8c3175fe10b0d38475da4bffbee79bc4255f95c5;hpb=2574bf4ab96840e3e064a0e4de521973fd299edc;p=jalview.git diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java index 8c3175f..d80fd86 100644 --- a/src/jalview/project/Jalview2XML.java +++ b/src/jalview/project/Jalview2XML.java @@ -20,9 +20,20 @@ */ package jalview.project; +import static jalview.math.RotatableMatrix.Axis.X; +import static jalview.math.RotatableMatrix.Axis.Y; +import static jalview.math.RotatableMatrix.Axis.Z; + +import jalview.analysis.AnnotationSorter; +import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; 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; @@ -31,6 +42,7 @@ import jalview.datamodel.AlignmentAnnotation; 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; @@ -49,18 +61,21 @@ import jalview.gui.AppVarna; import jalview.gui.ChimeraViewFrame; import jalview.gui.Desktop; import jalview.gui.FeatureRenderer; -import jalview.gui.Jalview2XML_V1; import jalview.gui.JvOptionPane; import jalview.gui.OOMWarning; +import jalview.gui.PCAPanel; import jalview.gui.PaintRefresher; import jalview.gui.SplitFrame; import jalview.gui.StructureViewer; import jalview.gui.StructureViewer.ViewerType; import jalview.gui.StructureViewerBase; import jalview.gui.TreePanel; +import jalview.io.BackupFiles; import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.NewickFile; +import jalview.math.Matrix; +import jalview.math.MatrixI; import jalview.renderer.ResidueShaderI; import jalview.schemes.AnnotationColourGradient; import jalview.schemes.ColourSchemeI; @@ -77,6 +92,8 @@ import jalview.util.StringUtils; import jalview.util.jarInputStreamProvider; import jalview.util.matcher.Condition; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.AlignmentViewport.AutoAnnotation; +import jalview.viewmodel.PCAModel; import jalview.viewmodel.ViewportRanges; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import jalview.viewmodel.seqfeatures.FeaturesDisplayed; @@ -92,6 +109,8 @@ import jalview.xml.binding.jalview.Annotation; import jalview.xml.binding.jalview.Annotation.ThresholdLine; import jalview.xml.binding.jalview.AnnotationColourScheme; import jalview.xml.binding.jalview.AnnotationElement; +import jalview.xml.binding.jalview.DoubleMatrix; +import jalview.xml.binding.jalview.DoubleVector; import jalview.xml.binding.jalview.Feature; import jalview.xml.binding.jalview.Feature.OtherData; import jalview.xml.binding.jalview.FeatureMatcherSet.CompoundMatcher; @@ -106,6 +125,11 @@ import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids; import jalview.xml.binding.jalview.JalviewModel.JSeq.Pdbids.StructureState; import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer; import jalview.xml.binding.jalview.JalviewModel.JSeq.RnaViewer.SecondaryStructure; +import jalview.xml.binding.jalview.JalviewModel.PcaViewer; +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.Axis; +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMax; +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SeqPointMin; +import jalview.xml.binding.jalview.JalviewModel.PcaViewer.SequencePoint; import jalview.xml.binding.jalview.JalviewModel.Tree; import jalview.xml.binding.jalview.JalviewModel.UserColours; import jalview.xml.binding.jalview.JalviewModel.Viewport; @@ -118,6 +142,7 @@ import jalview.xml.binding.jalview.MapListType.MapListTo; import jalview.xml.binding.jalview.Mapping; import jalview.xml.binding.jalview.NoValueColour; import jalview.xml.binding.jalview.ObjectFactory; +import jalview.xml.binding.jalview.PcaDataType; import jalview.xml.binding.jalview.Pdbentry.Property; import jalview.xml.binding.jalview.Sequence; import jalview.xml.binding.jalview.Sequence.DBRef; @@ -175,17 +200,21 @@ import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; /** - * Write out the current jalview desktop state as a Jalview XML stream. - * - * Note: the vamsas objects referred to here are primitive versions of the - * VAMSAS project schema elements - they are not the same and most likely never - * will be :) - * - * @author $author$ - * @version $Revision: 1.134 $ + * Provides methods to read in or write out the Jalview desktop state as a + * Jalview XML model, as one or more entries in a .jar archive. The jar file may + * include additional data file entries, such as + * */ public class Jalview2XML { + private static final String TRUE = "true"; + + private static final String FALSE = "false"; + private static final String VIEWER_PREFIX = "viewer_"; private static final String RNA_PREFIX = "rna_"; @@ -529,24 +558,30 @@ public class Jalview2XML public void saveState(File statefile) { FileOutputStream fos = null; + try { + fos = new FileOutputStream(statefile); + JarOutputStream jout = new JarOutputStream(fos); saveState(jout); + fos.close(); } catch (Exception e) { + Cache.log.error("Couln't write Jalview state to " + statefile, e); // TODO: inform user of the problem - they need to know if their data was // not saved ! if (errorMessage == null) { - errorMessage = "Couldn't write Jalview Archive to output file '" + errorMessage = "Did't write Jalview Archive to output file '" + statefile + "' - See console error log for details"; } else { - errorMessage += "(output file was '" + statefile + "')"; + errorMessage += "(Didn't write Jalview Archive to output file '" + + statefile + ")"; } e.printStackTrace(); } finally @@ -716,7 +751,11 @@ public class Jalview2XML { try { - FileOutputStream fos = new FileOutputStream(jarFile); + // create backupfiles object and get new temp filename destination + BackupFiles backupfiles = new BackupFiles(jarFile); + FileOutputStream fos = new FileOutputStream( + backupfiles.getTempFilePath()); + JarOutputStream jout = new JarOutputStream(fos); List frames = new ArrayList<>(); @@ -738,7 +777,12 @@ public class Jalview2XML } ; jout.close(); - return true; + boolean success = true; + + backupfiles.setWriteSuccess(success); + success = backupfiles.rollBackupsAndRenameTempFile(); + + return success; } catch (Exception ex) { errorMessage = "Couldn't Write alignment view to Jalview Archive - see error output for details"; @@ -1215,6 +1259,9 @@ public class Jalview2XML tree.setXpos(tp.getX()); tree.setYpos(tp.getY()); tree.setId(makeHashCode(tp, null)); + tree.setLinkToAllViews( + tp.getTreeCanvas().isApplyToAllViews()); + // jms.addTree(tree); object.getTree().add(tree); } @@ -1223,6 +1270,24 @@ public class Jalview2XML } } + /* + * save PCA viewers + */ + if (!storeDS && Desktop.desktop != null) + { + for (JInternalFrame frame : Desktop.desktop.getAllFrames()) + { + if (frame instanceof PCAPanel) + { + PCAPanel panel = (PCAPanel) frame; + if (panel.getAlignViewport().getAlignment() == jal) + { + savePCA(panel, object); + } + } + } + } + // SAVE ANNOTATIONS /** * store forward refs from an annotationRow to any groups @@ -1421,6 +1486,8 @@ public class Jalview2XML view.setRenderGaps(av.isRenderGaps()); view.setShowAnnotation(av.isShowAnnotation()); view.setShowBoxes(av.getShowBoxes()); + view.setShowAutocalcAbove(av.isShowAutocalculatedAbove()); + view.setSortAnnotationsBy(av.getSortAnnotationsBy().name()); view.setShowColourText(av.getColourText()); view.setShowFullId(av.getShowJVSuffix()); view.setRightAlignIds(av.isRightAlignIds()); @@ -1630,6 +1697,196 @@ public class Jalview2XML } /** + * 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, JalviewModel object) + { + 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.getSequencePoint().add(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.getAxis().add(axis); + } + + /* + * raw PCA data (note we are not restoring PCA inputs here - + * alignment view, score model, similarity parameters) + */ + PcaDataType data = new PcaDataType(); + viewer.setPcaData(data); + PCA pca = pcaModel.getPcaData(); + + DoubleMatrix pm = new DoubleMatrix(); + saveDoubleMatrix(pca.getPairwiseScores(), pm); + data.setPairwiseMatrix(pm); + + DoubleMatrix tm = new DoubleMatrix(); + saveDoubleMatrix(pca.getTridiagonal(), tm); + data.setTridiagonalMatrix(tm); + + DoubleMatrix eigenMatrix = new DoubleMatrix(); + data.setEigenMatrix(eigenMatrix); + saveDoubleMatrix(pca.getEigenmatrix(), eigenMatrix); + + object.getPcaViewer().add(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++) + { + DoubleVector row = new DoubleVector(); + for (int j = 0; j < m.width(); j++) + { + row.getV().add(m.getValue(i, j)); + } + xmlMatrix.getRow().add(row); + } + if (m.getD() != null) + { + DoubleVector dVector = new DoubleVector(); + for (double d : m.getD()) + { + dVector.getV().add(d); + } + xmlMatrix.setD(dVector); + } + if (m.getE() != null) + { + DoubleVector eVector = new DoubleVector(); + for (double e : m.getE()) + { + eVector.getV().add(e); + } + 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++) + { + List dVector = mData.getRow().get(i).getV(); + vals[i] = new double[dVector.size()]; + int dvi = 0; + for (Double d : dVector) + { + vals[i][dvi++] = d; + } + } + + MatrixI m = new Matrix(vals); + + if (mData.getD() != null) + { + List dVector = mData.getD().getV(); + double[] vec = new double[dVector.size()]; + int dvi = 0; + for (Double d : dVector) + { + vec[dvi++] = d; + } + m.setD(vec); + } + if (mData.getE() != null) + { + List dVector = mData.getE().getV(); + double[] vec = new double[dVector.size()]; + int dvi = 0; + for (Double d : dVector) + { + vec[dvi++] = d; + } + m.setE(vec); + } + + return m; + } + + /** * Save any Varna viewers linked to this sequence. Writes an rnaViewer element * for each viewer, with *
    @@ -2649,16 +2906,7 @@ public class Jalview2XML ex.printStackTrace(System.err); if (attemptversion1parse) { - // Is Version 1 Jar file? - try - { - af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(jprovider); - } catch (Exception ex2) - { - System.err.println("Exception whilst loading as jalviewXMLV1:"); - ex2.printStackTrace(); - af = null; - } + // used to attempt to parse as V1 castor-generated xml } if (Desktop.instance != null) { @@ -3380,7 +3628,7 @@ public class Jalview2XML // //////////////////////////////// // LOAD ANNOTATIONS - List autoAlan = new ArrayList<>(); + List addedAnnotation = new ArrayList<>(); /* * store any annotations which forward reference a group's ID @@ -3399,17 +3647,14 @@ public class Jalview2XML * test if annotation is automatically calculated for this view only */ boolean autoForView = false; - if (annotation.getLabel().equals("Quality") - || annotation.getLabel().equals("Conservation") - || annotation.getLabel().equals("Consensus")) + if (annotation.getLabel().equals(AutoAnnotation.QUALITY.label) + || annotation.getLabel() + .equals(AutoAnnotation.CONSERVATION.label) + || annotation.getLabel() + .equals(AutoAnnotation.CONSENSUS.label)) { // Kludge for pre 2.5 projects which lacked the autocalculated flag autoForView = true; - // JAXB has no has() test; schema defaults value to false - // if (!annotation.hasAutoCalculated()) - // { - // annotation.setAutoCalculated(true); - // } } if (autoForView || annotation.isAutoCalculated()) { @@ -3431,7 +3676,7 @@ public class Jalview2XML } al.addAnnotation(jda); - + addedAnnotation.add(jda); continue; } // Construct new annotation from model. @@ -3471,7 +3716,11 @@ public class Jalview2XML } } } - jalview.datamodel.AlignmentAnnotation jaa = null; + + /* + * construct the Jalview AlignmentAnnotation, add to alignment + */ + AlignmentAnnotation jaa = null; if (annotation.isGraph()) { @@ -3569,9 +3818,10 @@ public class Jalview2XML jaa.autoCalculated = true; // means annotation will be marked for // update at end of load. } - if (annotation.getGraphHeight() != null) + Integer graphHeight = annotation.getGraphHeight(); + if (graphHeight != null) { - jaa.graphHeight = annotation.getGraphHeight().intValue(); + jaa.graphHeight = graphHeight.intValue(); } jaa.belowAlignment = annotation.isBelowAlignment(); jaa.setCalcId(annotation.getCalcId()); @@ -3583,17 +3833,16 @@ public class Jalview2XML jaa.setProperty(prop.getName(), prop.getValue()); } } - if (jaa.autoCalculated) + if (!jaa.autoCalculated) { - autoAlan.add(new JvAnnotRow(i, jaa)); - } - else - // if (!autoForView) - { - // add autocalculated group annotation and any user created annotation - // for the view + // TODO ensure Consensus etc is enabled if found in project? + /* + * add autocalculated group annotation and any user created annotation + * for the view + */ al.addAnnotation(jaa); } + addedAnnotation.add(jaa); } } // /////////////////////// @@ -3620,7 +3869,7 @@ public class Jalview2XML } else { - cs = ColourSchemeProperty.getColourScheme(al, + cs = ColourSchemeProperty.getColourScheme(null, al, jGroup.getColour()); } } @@ -3785,10 +4034,25 @@ public class Jalview2XML if (isnewview) { - af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view, - uniqueSeqSetId, viewId, autoAlan); + Map originalPreferences = null; + try + { + originalPreferences = setAutocalcPreferences(jalviewModel); + af = loadViewport(file, jseqs, hiddenSeqs, al, jalviewModel, view, + uniqueSeqSetId, viewId); + } finally + { + restoreAutocalcPreferences(originalPreferences); + } + + /* + * resort annotations to their order in the project + * (also sets height and visibility for autocalc'd annotation) + */ av = af.getViewport(); + new AnnotationSorter(av).sort(addedAnnotation); ap = af.alignPanel; + ap.adjustAnnotationHeight(); } /* @@ -3799,6 +4063,7 @@ public class Jalview2XML if (loadTreesAndStructures) { loadTrees(jalviewModel, view, af, av, ap); + loadPCAViewers(jalviewModel, ap); loadPDBStructures(jprovider, jseqs, af, ap); loadRnaViewers(jprovider, jseqs, ap); } @@ -3807,6 +4072,93 @@ public class Jalview2XML } /** + * Restores previously captured preferences (or deletes the preference if the + * map entry value is null) + * + * @param originalPreferences + */ + private void restoreAutocalcPreferences( + Map originalPreferences) + { + for (Entry entry : originalPreferences.entrySet()) + { + String key = entry.getKey(); + String value = entry.getValue(); + if (value == null) + { + Cache.removeProperty(key); + } + else + { + Cache.setProperty(key, value); + } + } + } + + /** + * Inspects saved annotations and temporarily sets preferences for whether + * autocalculated annotations should be created for Conservation, Consensus, + * Quality, Occupancy. Returns a map containing the original values (which may + * be null if property is not set, or is set to null). + * + * @param jalviewModel + * @return + */ + private Map setAutocalcPreferences( + JalviewModel jalviewModel) + { + Map original = Cache.getProperties( + AutoAnnotation.OCCUPANCY.preferenceKey, + AutoAnnotation.CONSERVATION.preferenceKey, + AutoAnnotation.QUALITY.preferenceKey, + AutoAnnotation.CONSENSUS.preferenceKey); + + Cache.setProperty(AutoAnnotation.OCCUPANCY.preferenceKey, FALSE); + Cache.setProperty(AutoAnnotation.CONSERVATION.preferenceKey, FALSE); + Cache.setProperty(AutoAnnotation.QUALITY.preferenceKey, FALSE); + Cache.setProperty(AutoAnnotation.CONSENSUS.preferenceKey, FALSE); + + List sequenceSet = jalviewModel.getVamsasModel() + .getSequenceSet(); + + /* + * expect sequenceSet to have just one entry + */ + if (sequenceSet.size() != 1) + { + System.err.println( + "Unexpected sequenceSet size: " + sequenceSet.size()); + return original; + } + List anns = sequenceSet.get(0).getAnnotation(); + for (Annotation ann : anns) + { + if (ann.isAutoCalculated()) + { + String label = ann.getLabel(); + if (AutoAnnotation.CONSERVATION.label.equals(label)) + { + Cache.setProperty(AutoAnnotation.CONSERVATION.preferenceKey, + TRUE); + } + else if (AutoAnnotation.QUALITY.label.equals(label)) + { + Cache.setProperty(AutoAnnotation.QUALITY.preferenceKey, TRUE); + } + else if (AutoAnnotation.CONSENSUS.label.equals(label)) + { + Cache.setProperty(AutoAnnotation.CONSENSUS.preferenceKey, TRUE); + } + else if (AutoAnnotation.OCCUPANCY.label.equals(label)) + { + Cache.setProperty(AutoAnnotation.OCCUPANCY.preferenceKey, TRUE); + } + } + } + return original; + } + + /** * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna * panel is restored from separate jar entries, two (gapped and trimmed) per * sequence and secondary structure. @@ -3947,8 +4299,8 @@ public class Jalview2XML // TODO: verify 'associate with all views' works still tp.getTreeCanvas().setViewport(av); // af.viewport; tp.getTreeCanvas().setAssociatedPanel(ap); // af.alignPanel; - } + tp.getTreeCanvas().setApplyToAllViews(tree.isLinkToAllViews()); if (tp == null) { warn("There was a problem recovering stored Newick tree: \n" @@ -4334,7 +4686,7 @@ public class Jalview2XML { if (val.contains("e")) // eh? what can it be? { - if (val.trim().equals("true")) + if (val.trim().equals(TRUE)) { val = "1"; } @@ -4595,7 +4947,7 @@ public class Jalview2XML AlignFrame loadViewport(String file, List JSEQ, List hiddenSeqs, AlignmentI al, JalviewModel jm, Viewport view, String uniqueSeqSetId, - String viewId, List autoAlan) + String viewId) { AlignFrame af = null; af = new AlignFrame(al, safeInt(view.getWidth()), @@ -4676,9 +5028,8 @@ public class Jalview2XML viewport.setColourText(safeBoolean(view.isShowColourText())); - viewport - .setConservationSelected( - safeBoolean(view.isConservationSelected())); + viewport.setConservationSelected( + safeBoolean(view.isConservationSelected())); viewport.setIncrement(safeInt(view.getConsThreshold())); viewport.setShowJVSuffix(safeBoolean(view.isShowFullId())); viewport.setRightAlignIds(safeBoolean(view.isRightAlignIds())); @@ -4694,10 +5045,27 @@ public class Jalview2XML viewport.setWrapAlignment(safeBoolean(view.isWrapAlignment())); viewport.setShowAnnotation(safeBoolean(view.isShowAnnotation())); - viewport.setShowBoxes(safeBoolean(view.isShowBoxes())); + Boolean autocalcFirst = view.isShowAutocalcAbove(); + if (autocalcFirst != null) + { + af.setShowAutoCalculatedAbove(autocalcFirst.booleanValue()); + } + String sortBy = view.getSortAnnotationsBy(); + if (sortBy != null) + { + try + { + viewport.setSortAnnotationsBy( + SequenceAnnotationOrder.valueOf(sortBy)); + } catch (IllegalArgumentException e) + { + Cache.log.error( + "Invalid annotation sort specifier in project: " + sortBy); + } + } + viewport.setShowBoxes(safeBoolean(view.isShowBoxes())); viewport.setShowText(safeBoolean(view.isShowText())); - viewport.setTextColour(new Color(safeInt(view.getTextCol1()))); viewport.setTextColour2(new Color(safeInt(view.getTextCol2()))); viewport.setThresholdTextColour(safeInt(view.getTextColThreshold())); @@ -4731,25 +5099,27 @@ public class Jalview2XML } else { - cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour()); + cs = ColourSchemeProperty.getColourScheme(af.getViewport(), al, + view.getBgColour()); } } + /* + * turn off 'alignment colour applies to all groups' + * while restoring global colour scheme + */ + viewport.setColourAppliesToAllGroups(false); viewport.setGlobalColourScheme(cs); viewport.getResidueShading().setThreshold(pidThreshold, view.isIgnoreGapsinConsensus()); viewport.getResidueShading() .setConsensus(viewport.getSequenceConsensusHash()); - viewport.setColourAppliesToAllGroups(false); - if (safeBoolean(view.isConservationSelected()) && cs != null) { viewport.getResidueShading() .setConservationInc(safeInt(view.getConsThreshold())); } - af.changeColour(cs); - viewport.setColourAppliesToAllGroups(true); viewport @@ -4825,7 +5195,8 @@ public class Jalview2XML float min = safeFloat(safeFloat(setting.getMin())); float max = setting.getMax() == null ? 1f : setting.getMax().floatValue(); - FeatureColourI gc = new FeatureColour(minColour, maxColour, + FeatureColourI gc = new FeatureColour(maxColour, minColour, + maxColour, noValueColour, min, max); if (setting.getAttributeName().size() > 0) { @@ -4933,7 +5304,6 @@ public class Jalview2XML safeInt(view.getWidth()), safeInt(view.getHeight())); // recompute any autoannotation af.alignPanel.updateAnnotation(false, true); - reorderAutoannotation(af, al, autoAlan); af.alignPanel.alignmentChanged(); } else @@ -5027,7 +5397,7 @@ public class Jalview2XML else { cs = new AnnotationColourGradient(matchedAnnotation, - ColourSchemeProperty.getColourScheme(al, + ColourSchemeProperty.getColourScheme(af.getViewport(), al, viewAnnColour.getColourScheme()), safeInt(viewAnnColour.getAboveThreshold())); } @@ -5060,106 +5430,6 @@ public class Jalview2XML return cs; } - private void reorderAutoannotation(AlignFrame af, AlignmentI al, - List autoAlan) - { - // copy over visualization settings for autocalculated annotation in the - // view - if (al.getAlignmentAnnotation() != null) - { - /** - * Kludge for magic autoannotation names (see JAL-811) - */ - String[] magicNames = new String[] { "Consensus", "Quality", - "Conservation" }; - JvAnnotRow nullAnnot = new JvAnnotRow(-1, null); - Hashtable visan = new Hashtable<>(); - for (String nm : magicNames) - { - visan.put(nm, nullAnnot); - } - for (JvAnnotRow auan : autoAlan) - { - visan.put(auan.template.label - + (auan.template.getCalcId() == null ? "" - : "\t" + auan.template.getCalcId()), - auan); - } - int hSize = al.getAlignmentAnnotation().length; - List reorder = new ArrayList<>(); - // work through any autoCalculated annotation already on the view - // removing it if it should be placed in a different location on the - // annotation panel. - List remains = new ArrayList<>(visan.keySet()); - for (int h = 0; h < hSize; h++) - { - jalview.datamodel.AlignmentAnnotation jalan = al - .getAlignmentAnnotation()[h]; - if (jalan.autoCalculated) - { - String k; - JvAnnotRow valan = visan.get(k = jalan.label); - if (jalan.getCalcId() != null) - { - valan = visan.get(k = jalan.label + "\t" + jalan.getCalcId()); - } - - if (valan != null) - { - // delete the auto calculated row from the alignment - al.deleteAnnotation(jalan, false); - remains.remove(k); - hSize--; - h--; - if (valan != nullAnnot) - { - if (jalan != valan.template) - { - // newly created autoannotation row instance - // so keep a reference to the visible annotation row - // and copy over all relevant attributes - if (valan.template.graphHeight >= 0) - - { - jalan.graphHeight = valan.template.graphHeight; - } - jalan.visible = valan.template.visible; - } - reorder.add(new JvAnnotRow(valan.order, jalan)); - } - } - } - } - // Add any (possibly stale) autocalculated rows that were not appended to - // the view during construction - for (String other : remains) - { - JvAnnotRow othera = visan.get(other); - if (othera != nullAnnot && othera.template.getCalcId() != null - && othera.template.getCalcId().length() > 0) - { - reorder.add(othera); - } - } - // now put the automatic annotation in its correct place - int s = 0, srt[] = new int[reorder.size()]; - JvAnnotRow[] rws = new JvAnnotRow[reorder.size()]; - for (JvAnnotRow jvar : reorder) - { - rws[s] = jvar; - srt[s++] = jvar.order; - } - reorder.clear(); - jalview.util.QuickSort.sort(srt, rws); - // and re-insert the annotation at its correct position - for (JvAnnotRow jvar : rws) - { - al.addAnnotation(jvar.template, jvar.order); - } - af.alignPanel.adjustAnnotationHeight(); - } - } - Hashtable skipList = null; /** @@ -5220,21 +5490,47 @@ public class Jalview2XML { jalview.datamodel.AlignmentI ds = getDatasetFor( vamsasSet.getDatasetId()); + AlignmentI xtant_ds = ds; + if (xtant_ds == null) + { + // good chance we are about to create a new dataset, but check if we've + // seen some of the dataset sequence IDs before. + // TODO: skip this check if we are working with project generated by + // version 2.11 or later + xtant_ds = checkIfHasDataset(vamsasSet.getSequence()); + if (xtant_ds != null) + { + ds = xtant_ds; + addDatasetRef(vamsasSet.getDatasetId(), ds); + } + } Vector dseqs = null; - if (ds == null) + if (!ignoreUnrefed) { - if (!ignoreUnrefed) + // recovering an alignment View + AlignmentI seqSetDS = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId); + if (seqSetDS != null) { - // try to resolve the dataset via uniqueSeqSetId - ds = getDatasetFor(UNIQSEQSETID + uniqueSeqSetId); - if (ds != null) + if (ds != null && ds != seqSetDS) { - addDatasetRef(vamsasSet.getDatasetId(), ds); + warn("JAL-3171 regression: Overwriting a dataset reference for an alignment" + + " - CDS/Protein crossreference data may be lost"); + if (xtant_ds != null) + { + // This can only happen if the unique sequence set ID was bound to a + // dataset that did not contain any of the sequences in the view + // currently being restored. + warn("JAL-3171 SERIOUS! TOTAL CONFUSION - please consider contacting the Jalview Development team so they can investigate why your project caused this message to be displayed."); + } } + ds = seqSetDS; + addDatasetRef(vamsasSet.getDatasetId(), ds); } } if (ds == null) { + // try even harder to restore dataset + AlignmentI xtantDS = checkIfHasDataset(vamsasSet.getSequence()); // create a list of new dataset sequences dseqs = new Vector(); } @@ -5260,9 +5556,55 @@ public class Jalview2XML // register dataset for the alignment's uniqueSeqSetId for legacy projects addDatasetRef(UNIQSEQSETID + uniqueSeqSetId, ds); } + updateSeqDatasetBinding(vamsasSet.getSequence(), ds); + } + + /** + * XML dataset sequence ID to materialised dataset reference + */ + HashMap seqToDataset = new HashMap<>(); + + /** + * @return the first materialised dataset reference containing a dataset + * sequence referenced in the given view + * @param list + * - sequences from the view + */ + AlignmentI checkIfHasDataset(List list) + { + for (Sequence restoredSeq : list) + { + AlignmentI datasetFor = seqToDataset.get(restoredSeq.getDsseqid()); + if (datasetFor != null) + { + return datasetFor; + } + } + return null; } /** + * Register ds as the containing dataset for the dataset sequences referenced + * by sequences in list + * + * @param list + * - sequences in a view + * @param ds + */ + void updateSeqDatasetBinding(List list, AlignmentI ds) + { + for (Sequence restoredSeq : list) + { + AlignmentI prevDS = seqToDataset.put(restoredSeq.getDsseqid(), ds); + if (prevDS != null && prevDS != ds) + { + warn("Dataset sequence appears in many datasets: " + + restoredSeq.getDsseqid()); + // TODO: try to merge! + } + } + } + /** * * @param vamsasSeq * sequence definition to create/merge dataset sequence for @@ -5521,15 +5863,16 @@ public class Jalview2XML jalview.datamodel.Mapping jmap = new jalview.datamodel.Mapping(dsto, fr, fto, m.getMapFromUnit().intValue(), m.getMapToUnit().intValue()); - // if (m.getMappingChoice() != null) - // { - // MappingChoice mc = m.getMappingChoice(); + + /* + * (optional) choice of dseqFor or Sequence + */ if (m.getDseqFor() != null) { String dsfor = m.getDseqFor(); if (seqRefIds.containsKey(dsfor)) { - /** + /* * recover from hash */ jmap.setTo(seqRefIds.get(dsfor)); @@ -5539,9 +5882,9 @@ public class Jalview2XML frefedSequence.add(newMappingRef(dsfor, jmap)); } } - else + else if (m.getSequence() != null) { - /** + /* * local sequence definition */ Sequence ms = m.getSequence(); @@ -5863,6 +6206,128 @@ public class Jalview2XML } /** + * Loads any saved PCA viewers + * + * @param jms + * @param ap + */ + protected void loadPCAViewers(JalviewModel model, AlignmentPanel ap) + { + try + { + List pcaviewers = model.getPcaViewer(); + for (PcaViewer viewer : pcaviewers) + { + 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); + PcaDataType 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 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().get(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 @@ -6125,7 +6590,7 @@ public class Jalview2XML noValueColour = maxcol; } - colour = new FeatureColour(mincol, maxcol, noValueColour, + colour = new FeatureColour(maxcol, mincol, maxcol, noValueColour, safeFloat(colourModel.getMin()), safeFloat(colourModel.getMax())); final List attributeName = colourModel.getAttributeName();