X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2FAlignmentViewport.java;h=0e3bb9e923077371053715aa0e677adfa0914453;hb=8307be83ae28064b8f606f6c7a77dd186485a0fa;hp=18c2aed5ccb2db613bdf425967e1a97d79e4207a;hpb=d7aec3514299dcd8633cc420bf62cbafd3f247de;p=jalview.git diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 18c2aed..0e3bb9e 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -23,7 +23,9 @@ package jalview.viewmodel; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.analysis.Conservation; import jalview.analysis.TreeModel; -import jalview.api.AlignCalcManagerI; +import jalview.api.AlignCalcManagerI2; +import jalview.api.AlignCalcWorkerI; +import jalview.api.AlignExportSettingsI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeaturesDisplayedI; @@ -31,6 +33,7 @@ import jalview.api.ViewStyleI; import jalview.commands.CommandI; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentExportData; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.Annotation; @@ -54,7 +57,7 @@ import jalview.util.MapList; import jalview.util.MappingUtils; import jalview.util.MessageManager; import jalview.viewmodel.styles.ViewStyle; -import jalview.workers.AlignCalcManager; +import jalview.workers.AlignCalcManager2; import jalview.workers.ComplementConsensusThread; import jalview.workers.ConsensusThread; import jalview.workers.InformationThread; @@ -71,6 +74,9 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; /** * base class holding visualization and analysis attributes and common logic for @@ -82,6 +88,8 @@ import java.util.Map; public abstract class AlignmentViewport implements AlignViewportI, CommandListener, VamsasSource { + public static final String PROPERTY_ALIGNMENT = "alignment"; + public static final String PROPERTY_SEQUENCE = "sequence"; protected ViewportRanges ranges; protected ViewStyleI viewStyle = new ViewStyle(); @@ -98,47 +106,22 @@ public abstract class AlignmentViewport protected Deque redoList = new ArrayDeque<>(); - protected String sequenceSetID; - + /** + * alignment displayed in the viewport. Please use get/setter + */ + protected AlignmentI alignment; + /* * probably unused indicator that view is of a dataset rather than an * alignment */ - protected boolean isDataset = false; - - private Map hiddenRepSequences; - - protected ColumnSelection colSel = new ColumnSelection(); - - public boolean autoCalculateConsensus = true; - - protected boolean autoCalculateStrucConsensus = true; - - protected boolean ignoreGapsInConsensusCalculation = false; protected boolean ignoreBelowBackGroundFrequencyCalculation = false; protected boolean infoLetterHeight = false; - protected ResidueShaderI residueShading = new ResidueShader(); - - protected AlignmentAnnotation consensus; - - protected AlignmentAnnotation complementConsensus; - protected AlignmentAnnotation occupancy; - - protected AlignmentAnnotation strucConsensus; - - protected AlignmentAnnotation conservation; - - protected AlignmentAnnotation quality; - - /** - * alignment displayed in the viewport - */ - private AlignmentI alignment; - + /** * results of alignment consensus analysis for visible portion of view */ @@ -149,19 +132,6 @@ public abstract class AlignmentViewport */ protected ProfilesI hmmProfiles; - /** - * results of cDNA complement consensus visible portion of view - */ - protected Hashtable[] hcomplementConsensus; - - /** - * results of secondary structure base pair consensus for visible portion of - * view - */ - protected Hashtable[] hStrucConsensus; - - protected Conservation hconservation; - public AlignmentViewport(AlignmentI al) { setAlignment(al); @@ -641,6 +611,15 @@ public abstract class AlignmentViewport return alignment.getGapCharacter(); } + protected String sequenceSetID; + + /** + * probably unused indicator that view is of a dataset rather than an + * alignment + */ + protected boolean isDataset = false; + + public void setDataset(boolean b) { isDataset = b; @@ -651,6 +630,38 @@ public abstract class AlignmentViewport return isDataset; } + private Map hiddenRepSequences; + + protected ColumnSelection colSel = new ColumnSelection(); + + protected boolean autoCalculateConsensusAndConservation = true; + + public boolean getAutoCalculateConsensusAndConservation() + { // BH 2019.07.24 + return autoCalculateConsensusAndConservation; + } + + public void setAutoCalculateConsensusAndConservation(boolean b) + { + autoCalculateConsensusAndConservation = b; + } + + protected boolean autoCalculateStrucConsensus = true; + + public boolean getAutoCalculateStrucConsensus() + { // BH 2019.07.24 + return autoCalculateStrucConsensus; + } + + public void setAutoCalculateStrucConsensus(boolean b) + { + autoCalculateStrucConsensus = b; + } + protected boolean ignoreGapsInConsensusCalculation = false; + + protected ResidueShaderI residueShading = new ResidueShader(); + + @Override public void setGlobalColourScheme(ColourSchemeI cs) { @@ -702,7 +713,8 @@ public abstract class AlignmentViewport * retain any colour thresholds per group while * changing choice of colour scheme (JAL-2386) */ - sg.setColourScheme(cs); + sg.setColourScheme( + cs == null ? null : cs.getInstance(this, sg)); if (cs != null) { sg.getGroupColourScheme().alignmentChanged(sg, @@ -723,6 +735,43 @@ public abstract class AlignmentViewport { return residueShading; } + + + protected AlignmentAnnotation consensus; + + protected AlignmentAnnotation complementConsensus; + + protected AlignmentAnnotation gapcounts; + + protected AlignmentAnnotation strucConsensus; + + protected AlignmentAnnotation conservation; + + protected AlignmentAnnotation quality; + + protected AlignmentAnnotation[] groupConsensus; + + protected AlignmentAnnotation[] groupConservation; + + /** + * results of alignment consensus analysis for visible portion of view + */ + protected ProfilesI hconsensus = null; + + /** + * results of cDNA complement consensus visible portion of view + */ + protected Hashtable[] hcomplementConsensus = null; + + /** + * results of secondary structure base pair consensus for visible portion of + * view + */ + protected Hashtable[] hStrucConsensus = null; + + protected Conservation hconservation = null; + + @Override public void setConservation(Conservation cons) { @@ -742,21 +791,22 @@ public abstract class AlignmentViewport } @Override - public void setConsensusProfiles(ProfilesI hconsensus) + public void setSequenceConsensusHash(ProfilesI hconsensus) { - this.consensusProfiles = hconsensus; + this.hconsensus = hconsensus; } @Override - public void setComplementConsensusHash(Hashtable[] hconsensus) + public void setComplementConsensusHash( + Hashtable[] hconsensus) { this.hcomplementConsensus = hconsensus; } @Override - public ProfilesI getConsensusProfiles() + public ProfilesI getSequenceConsensusHash() { - return consensusProfiles; + return hconsensus; } @Override @@ -772,19 +822,20 @@ public abstract class AlignmentViewport } @Override - public Hashtable[] getComplementConsensusHash() + public Hashtable[] getComplementConsensusHash() { return hcomplementConsensus; } @Override - public Hashtable[] getRnaStructureConsensusHash() + public Hashtable[] getRnaStructureConsensusHash() { return hStrucConsensus; } @Override - public void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus) + public void setRnaStructureConsensusHash( + Hashtable[] hStrucConsensus) { this.hStrucConsensus = hStrucConsensus; @@ -809,9 +860,9 @@ public abstract class AlignmentViewport } @Override - public AlignmentAnnotation getOccupancyAnnotation() + public AlignmentAnnotation getAlignmentGapAnnotation() { - return occupancy; + return gapcounts; } @Override @@ -826,7 +877,7 @@ public abstract class AlignmentViewport return strucConsensus; } - protected AlignCalcManagerI calculator = new AlignCalcManager(); + protected AlignCalcManagerI2 calculator = new AlignCalcManager2(); /** * trigger update of conservation annotation @@ -836,12 +887,12 @@ public abstract class AlignmentViewport // see note in mantis : issue number 8585 if (alignment.isNucleotide() || (conservation == null && quality == null) - || !autoCalculateConsensus) + || !autoCalculateConsensusAndConservation) { return; } - if (calculator.getRegisteredWorkersOfClass( - jalview.workers.ConservationThread.class) == null) + if (calculator.getWorkersOfClass( + jalview.workers.ConservationThread.class).isEmpty()) { calculator.registerWorker( new jalview.workers.ConservationThread(this, ap)); @@ -854,12 +905,11 @@ public abstract class AlignmentViewport public void updateConsensus(final AlignmentViewPanel ap) { // see note in mantis : issue number 8585 - if (consensus == null || !autoCalculateConsensus) + if (consensus == null || !autoCalculateConsensusAndConservation) { return; } - if (calculator - .getRegisteredWorkersOfClass(ConsensusThread.class) == null) + if (calculator.getWorkersOfClass(ConsensusThread.class).isEmpty()) { calculator.registerWorker(new ConsensusThread(this, ap)); } @@ -890,11 +940,9 @@ public abstract class AlignmentViewport } if (doConsensus) { - if (calculator.getRegisteredWorkersOfClass( - ComplementConsensusThread.class) == null) + if (calculator.getWorkersOfClass(ComplementConsensusThread.class).isEmpty()) { - calculator - .registerWorker(new ComplementConsensusThread(this, ap)); + calculator.registerWorker(new ComplementConsensusThread(this, ap)); } } } @@ -903,13 +951,11 @@ public abstract class AlignmentViewport @Override public void initInformationWorker(final AlignmentViewPanel ap) { - if (calculator - .getRegisteredWorkersOfClass(InformationThread.class) == null) + if (calculator.getWorkersOfClass(InformationThread.class).isEmpty()) { calculator.registerWorker(new InformationThread(this, ap)); } } - // --------START Structure Conservation public void updateStrucConsensus(final AlignmentViewPanel ap) { @@ -925,8 +971,7 @@ public abstract class AlignmentViewport { return; } - if (calculator.getRegisteredWorkersOfClass( - StrucConsensusThread.class) == null) + if (calculator.getWorkersOfClass(StrucConsensusThread.class).isEmpty()) { calculator.registerWorker(new StrucConsensusThread(this, ap)); } @@ -945,7 +990,7 @@ public abstract class AlignmentViewport { return false; } - if (calculator.workingInvolvedWith(alignmentAnnotation)) + if (calculator.isWorkingWithAnnotation(alignmentAnnotation)) { // System.err.println("grey out ("+alignmentAnnotation.label+")"); return true; @@ -953,6 +998,20 @@ public abstract class AlignmentViewport return false; } + private ScheduledExecutorService serviceExecutor = Executors.newSingleThreadScheduledExecutor(); + + /** + * Get a default scheduled executor service which can be used by + * services and calculators to run parallel jobs associated with this + * viewport. + * + * @return default service executor of that viewport + */ + public ScheduledExecutorService getServiceExecutor() + { + return serviceExecutor; + } + public void setAlignment(AlignmentI align) { this.alignment = align; @@ -974,15 +1033,22 @@ public abstract class AlignmentViewport conservation = null; quality = null; consensusProfiles = null; + groupConsensus = null; + groupConservation = null; + hconsensus = null; hconservation = null; hcomplementConsensus = null; - occupancy = null; + gapcounts = null; + calculator.shutdown(); calculator = null; + serviceExecutor.shutdown(); + serviceExecutor = null; residueShading = null; // may hold a reference to Consensus changeSupport = null; ranges = null; currentTree = null; selectionGroup = null; + colSel = null; setAlignment(null); } @@ -995,7 +1061,7 @@ public abstract class AlignmentViewport } @Override - public AlignCalcManagerI getCalcManager() + public AlignCalcManagerI2 getCalcManager() { return calculator; } @@ -1069,9 +1135,15 @@ public abstract class AlignmentViewport // TODO: decouple settings setting from calculation when refactoring // annotation update method from alignframe to viewport this.showSequenceLogo = showSequenceLogo; - calculator.updateAnnotationFor(ConsensusThread.class); - calculator.updateAnnotationFor(ComplementConsensusThread.class); - calculator.updateAnnotationFor(StrucConsensusThread.class); + for (AlignCalcWorkerI worker : calculator.getWorkers()) + { + if (worker.getClass().equals(ConsensusThread.class) || + worker.getClass().equals(ComplementConsensusThread.class) || + worker.getClass().equals(StrucConsensusThread.class)) + { + worker.updateAnnotation(); + } + } } this.showSequenceLogo = showSequenceLogo; } @@ -1087,7 +1159,6 @@ public abstract class AlignmentViewport } this.hmmShowSequenceLogo = showHMMSequenceLogo; } - /** * @param showConsensusHistogram * the showConsensusHistogram to set @@ -1310,6 +1381,7 @@ public abstract class AlignmentViewport ignoreGapsInConsensusCalculation = b; if (ap != null) { + updateConsensus(ap); if (residueShading != null) { residueShading.setThreshold(residueShading.getThreshold(), @@ -1358,21 +1430,22 @@ public abstract class AlignmentViewport * checks current colsel against record of last hash value, and optionally * updates record. * - * @param b + * @param updateHash * update the record of last hash value * @return true if colsel changed since last call (when b is true) */ - public boolean isColSelChanged(boolean b) + public boolean isColSelChanged(boolean updateHash) { int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode(); if (hc != -1 && hc != colselhash) { - if (b) + if (updateHash) { colselhash = hc; } return true; } + notifySequence(); return false; } @@ -1393,7 +1466,6 @@ public abstract class AlignmentViewport { return infoLetterHeight; } - // property change stuff // JBPNote Prolly only need this in the applet version. private PropertyChangeSupport changeSupport = new PropertyChangeSupport( @@ -1445,21 +1517,6 @@ public abstract class AlignmentViewport } } - /** - * Property change listener for changes in alignment - * - * @param prop - * DOCUMENT ME! - * @param oldvalue - * DOCUMENT ME! - * @param newvalue - * DOCUMENT ME! - */ - public void firePropertyChange(String prop, Object oldvalue, - Object newvalue) - { - changeSupport.firePropertyChange(prop, oldvalue, newvalue); - } // common hide/show column stuff @@ -1525,9 +1582,9 @@ public abstract class AlignmentViewport ranges.setStartEndSeq(startSeq, endSeq + tmp.size()); - firePropertyChange("alignment", null, alignment.getSequences()); // used to set hasHiddenRows/hiddenRepSequences here, after the property // changed event + notifySequence(); sendSelection(); } } @@ -1555,7 +1612,7 @@ public abstract class AlignmentViewport ranges.setStartEndSeq(startSeq, endSeq + tmp.size()); - firePropertyChange("alignment", null, alignment.getSequences()); + notifyAlignment(); sendSelection(); } } @@ -1589,7 +1646,7 @@ public abstract class AlignmentViewport setSequenceAnnotationsVisible(seq[i], false); } ranges.setStartSeq(startSeq); - firePropertyChange("alignment", null, alignment.getSequences()); + notifyAlignment(); } } @@ -1736,6 +1793,7 @@ public abstract class AlignmentViewport public void invertColumnSelection() { colSel.invertColumnSelection(0, alignment.getWidth(), alignment); + isColSelChanged(true); } @Override @@ -1896,7 +1954,7 @@ public abstract class AlignmentViewport } } while (end < max); - int[][] startEnd = new int[regions.size()][2]; + // int[][] startEnd = new int[regions.size()][2]; return regions; } @@ -1953,6 +2011,18 @@ public abstract class AlignmentViewport { alignment.padGaps(); } + if (autoCalculateConsensusAndConservation) + { + updateConsensus(ap); + } + if (hconsensus != null && autoCalculateConsensusAndConservation) + { + updateConservation(ap); + } + if (autoCalculateStrucConsensus) + { + updateStrucConsensus(ap); + } // Reset endRes of groups if beyond alignment width int alWidth = alignment.getWidth(); @@ -1987,7 +2057,7 @@ public abstract class AlignmentViewport { rs.alignmentChanged(alignment, hiddenRepSequences); - rs.setConsensus(consensusProfiles); + rs.setConsensus(hconsensus); if (rs.conservationApplied()) { rs.setConservation(Conservation.calculateConservation("All", @@ -2012,7 +2082,7 @@ public abstract class AlignmentViewport // depending on if the user wants to see the annotation or not in a // specific alignment - if (consensusProfiles == null && !isDataset) + if (hconsensus == null && !isDataset) { if (!alignment.isNucleotide()) { @@ -2027,8 +2097,7 @@ public abstract class AlignmentViewport MessageManager.getString("label.consensus_descr"), new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); initConsensus(consensus); - - initOccupancy(); + initGapCounts(); initComplementConsensus(); } @@ -2087,20 +2156,20 @@ public abstract class AlignmentViewport // these should be extracted from the view model - style and settings for // derived annotation - private void initOccupancy() + private void initGapCounts() { if (showOccupancy) { - occupancy = new AlignmentAnnotation("Occupancy", + gapcounts = new AlignmentAnnotation("Occupancy", MessageManager.getString("label.occupancy_descr"), new Annotation[1], 0f, alignment.getHeight(), AlignmentAnnotation.BAR_GRAPH); - occupancy.hasText = true; - occupancy.autoCalculated = true; - occupancy.scaleColLabel = true; - occupancy.graph = AlignmentAnnotation.BAR_GRAPH; + gapcounts.hasText = true; + gapcounts.autoCalculated = true; + gapcounts.scaleColLabel = true; + gapcounts.graph = AlignmentAnnotation.BAR_GRAPH; - alignment.addAnnotation(occupancy); + alignment.addAnnotation(gapcounts); } } @@ -2242,7 +2311,7 @@ public abstract class AlignmentViewport * TODO reorder the annotation rows according to group/sequence ordering on * alignment */ - boolean sortg = true; + // boolean sortg = true; // remove old automatic annotation // add any new annotation @@ -2355,7 +2424,7 @@ public abstract class AlignmentViewport public void clearSequenceColours() { sequenceColours.clear(); - }; + } @Override public AlignViewportI getCodingComplement() @@ -2808,6 +2877,30 @@ public abstract class AlignmentViewport viewStyle.setProteinFontAsCdna(b); } + @Override + public void setShowComplementFeatures(boolean b) + { + viewStyle.setShowComplementFeatures(b); + } + + @Override + public boolean isShowComplementFeatures() + { + return viewStyle.isShowComplementFeatures(); + } + + @Override + public void setShowComplementFeaturesOnTop(boolean b) + { + viewStyle.setShowComplementFeaturesOnTop(b); + } + + @Override + public boolean isShowComplementFeaturesOnTop() + { + return viewStyle.isShowComplementFeaturesOnTop(); + } + /** * @return true if view should scroll to show the highlighted region of a * sequence @@ -3049,7 +3142,6 @@ public abstract class AlignmentViewport } return false; } - @Override public void setCurrentTree(TreeModel tree) { @@ -3063,6 +3155,36 @@ public abstract class AlignmentViewport } @Override + public AlignmentExportData getAlignExportData(AlignExportSettingsI options) + { + AlignmentI alignmentToExport = null; + String[] omitHidden = null; + alignmentToExport = null; + + if (hasHiddenColumns() && !options.isExportHiddenColumns()) + { + omitHidden = getViewAsString(false, + options.isExportHiddenSequences()); + } + + int[] alignmentStartEnd = new int[2]; + if (hasHiddenRows() && options.isExportHiddenSequences()) + { + alignmentToExport = getAlignment().getHiddenSequences() + .getFullAlignment(); + } + else + { + alignmentToExport = getAlignment(); + } + alignmentStartEnd = getAlignment().getHiddenColumns() + .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); + AlignmentExportData ed = new AlignmentExportData(alignmentToExport, + omitHidden, alignmentStartEnd); + return ed; + } + + @Override public boolean isNormaliseSequenceLogo() { return normaliseSequenceLogo; @@ -3083,4 +3205,142 @@ public abstract class AlignmentViewport { hmmNormaliseSequenceLogo = state; } + /** + * flag set to indicate if structure views might be out of sync with sequences + * in the alignment + */ + + private boolean needToUpdateStructureViews = false; + + @Override + public boolean isUpdateStructures() + { + return needToUpdateStructureViews; + } + + @Override + public void setUpdateStructures(boolean update) + { + needToUpdateStructureViews = update; + } + + @Override + public boolean needToUpdateStructureViews() + { + boolean update = needToUpdateStructureViews; + needToUpdateStructureViews = false; + return update; + } + + @Override + public void addSequenceGroup(SequenceGroup sequenceGroup) + { + alignment.addGroup(sequenceGroup); + + Color col = sequenceGroup.idColour; + if (col != null) + { + col = col.brighter(); + + for (SequenceI sq : sequenceGroup.getSequences()) + { + setSequenceColour(sq, col); + } + } + + if (codingComplement != null) + { + SequenceGroup mappedGroup = MappingUtils + .mapSequenceGroup(sequenceGroup, this, codingComplement); + if (mappedGroup.getSequences().size() > 0) + { + codingComplement.getAlignment().addGroup(mappedGroup); + + if (col != null) + { + for (SequenceI seq : mappedGroup.getSequences()) + { + codingComplement.setSequenceColour(seq, col); + } + } + } + // propagate the structure view update flag according to our own setting + codingComplement.setUpdateStructures(needToUpdateStructureViews); + } + } + + @Override + public Iterator getViewAsVisibleContigs(boolean selectedRegionOnly) + { + int start = 0; + int end = 0; + if (selectedRegionOnly && selectionGroup != null) + { + start = selectionGroup.getStartRes(); + end = selectionGroup.getEndRes() + 1; + } + else + { + end = alignment.getWidth(); + } + return (alignment.getHiddenColumns().getVisContigsIterator(start, end, + false)); + } + /** + * Filters out sequences with an eValue higher than the specified value. The + * filtered sequences are hidden or deleted. Sequences with no eValues are also + * filtered out. + * + * @param eValue + * @param delete + */ + public void filterByEvalue(double eValue) + { + for (SequenceI seq : alignment.getSequencesArray()) + { + if ((seq.getAnnotation("Search Scores") == null + || seq.getAnnotation("Search Scores")[0].getEValue() > eValue) + && seq.getHMM() == null) + { + hideSequence(new SequenceI[] { seq }); + } + } + } + + /** + * Filters out sequences with an score lower than the specified value. The + * filtered sequences are hidden or deleted. + * + * @param score + * @param delete + */ + public void filterByScore(double score) + { + for (SequenceI seq : alignment.getSequencesArray()) + { + if ((seq.getAnnotation("Search Scores") == null + || seq.getAnnotation("Search Scores")[0] + .getBitScore() < score) + && seq.getHMM() == null) + { + hideSequence(new SequenceI[] { seq }); + } + } + } + + /** + * Notify TreePanel and AlignmentPanel of some sort of alignment change. + */ + public void notifyAlignment() + { + changeSupport.firePropertyChange(PROPERTY_ALIGNMENT, null, alignment.getSequences()); + } + + /** + * Notify AlignmentPanel of a sequence column selection or visibility changes. + */ + public void notifySequence() + { + changeSupport.firePropertyChange(PROPERTY_SEQUENCE, null, null); + } }