From: gmungoc Date: Wed, 7 Mar 2018 10:35:12 +0000 (+0000) Subject: JAL-2629 storage and lifecycle of alignment/group HMM annotations revised X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=4389a166735bf1203894abdf3cf7dd57c4856dbc;p=jalview.git JAL-2629 storage and lifecycle of alignment/group HMM annotations revised --- diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index 04f34dd..3e59274 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -194,10 +194,10 @@ public class AAFrequency * @param end * The alignment column on which the last profile is based. * @param saveFullProfile - * Flag for saving the counts for each profile + * if true, all residue counts are saved (enables profile logo) * @param removeBelowBackground - * Flag for removing any characters with a match emission probability - * less than its background frequency + * if true, symbols with a match emission probability less than + * background frequency are ignored * @return */ public static ProfilesI calculateHMMProfiles(final HiddenMarkovModel hmm, @@ -384,12 +384,13 @@ public class AAFrequency } float value = hmm.getInformationContent(column); - if (!Float.isNaN(value)) + boolean isNaN = Float.isNaN(value); + if (!isNaN) { max = Math.max(max, value); } - String description = Float.isNaN(value) ? null + String description = isNaN ? null : String.format("%.4f bits", value); information.annotations[column] = new Annotation( Character.toString(Character @@ -403,9 +404,9 @@ public class AAFrequency } /** - * Derive the gap count annotation row. + * Derive the occupancy count annotation * - * @param gaprow + * @param occupancy * the annotation row to add annotations to * @param profiles * the source consensus data @@ -414,11 +415,11 @@ public class AAFrequency * @param endCol * end column (exclusive) */ - public static void completeGapAnnot(AlignmentAnnotation gaprow, + public static void completeOccupancyAnnot(AlignmentAnnotation occupancy, ProfilesI profiles, int startCol, int endCol, long nseq) { - if (gaprow == null || gaprow.annotations == null - || gaprow.annotations.length < endCol) + if (occupancy == null || occupancy.annotations == null + || occupancy.annotations.length < endCol) { /* * called with a bad alignment annotation row @@ -427,8 +428,8 @@ public class AAFrequency return; } // always set ranges again - gaprow.graphMax = nseq; - gaprow.graphMin = 0; + occupancy.graphMax = nseq; + occupancy.graphMin = 0; double scale = 0.8 / nseq; for (int i = startCol; i < endCol; i++) { @@ -439,7 +440,7 @@ public class AAFrequency * happens if sequences calculated over were * shorter than alignment width */ - gaprow.annotations[i] = null; + occupancy.annotations[i] = null; return; } @@ -447,7 +448,8 @@ public class AAFrequency String description = "" + gapped; - gaprow.annotations[i] = new Annotation("", description, '\0', gapped, + occupancy.annotations[i] = new Annotation("", description, '\0', + gapped, jalview.util.ColorUtils.bleachColour(Color.DARK_GRAY, (float) scale * gapped)); } diff --git a/src/jalview/api/AlignCalcWorkerI.java b/src/jalview/api/AlignCalcWorkerI.java index 85157c4..1387cba 100644 --- a/src/jalview/api/AlignCalcWorkerI.java +++ b/src/jalview/api/AlignCalcWorkerI.java @@ -39,8 +39,8 @@ public interface AlignCalcWorkerI extends Runnable /** * Updates the display of calculated annotation values (does not recalculate - * the values). This allows ßquick redraw of annotations when display settings - * are changed. + * the values). This allows a quick redraw of annotations when display + * settings are changed. */ void updateAnnotation(); diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index ea921c7..bcee815 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -106,7 +106,7 @@ public interface AlignViewportI extends ViewStyleI ColumnSelection getColumnSelection(); - ProfilesI getSequenceConsensusHash(); + ProfilesI getConsensusProfiles(); /** * Get consensus data table for the cDNA complement of this alignment (if any) @@ -139,7 +139,7 @@ public interface AlignViewportI extends ViewStyleI * * @return */ - AlignmentAnnotation getAlignmentGapAnnotation(); + AlignmentAnnotation getOccupancyAnnotation(); /** * get the container for cDNA complement consensus annotation @@ -178,7 +178,7 @@ public interface AlignViewportI extends ViewStyleI * * @param hconsensus */ - void setSequenceConsensusHash(ProfilesI hconsensus); + void setConsensusProfiles(ProfilesI hconsensus); /** * Set the cDNA complement consensus for the viewport @@ -495,20 +495,9 @@ public interface AlignViewportI extends ViewStyleI @Override void setProteinFontAsCdna(boolean b); - void setSequenceInformationHashes(List info); + void setHmmProfiles(ProfilesI info); - List getSequenceInformationHashes(); - - ProfilesI getSequenceInformationHash(int index); - - List getInformationAnnotations(); - - void setSequenceInformationHash(ProfilesI info, int index); - - /** - * Initiates the information annotation for all uninitiated sequences. - */ - void initInformation(); + ProfilesI getHmmProfiles(); /** * Updates all information annotations. diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index 7ce6837..b0d6f85 100644 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -207,7 +207,7 @@ public class AlignViewport extends AlignmentViewport colour)); if (residueShading != null) { - residueShading.setConsensus(hconsensus); + residueShading.setConsensus(consensusProfiles); } } diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index c049326..ac01109 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -538,7 +538,7 @@ public class AnnotationLabels extends Panel MessageManager.getString("label.ignore_gaps_consensus"), (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef - .getIgnoreGapsConsensus() + .isIgnoreGapsConsensus() : ap.av.isIgnoreGapsConsensus()); final AlignmentAnnotation aaa = aa[selectedRow]; cbmi.addItemListener(new ItemListener() diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 8ce597d..2bb5d83 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -69,7 +69,7 @@ public class OverviewPanel extends Panel implements Runnable, od = new OverviewDimensionsShowHidden(av.getRanges(), (av.isShowAnnotation() - && av.getSequenceConsensusHash() != null)); + && av.getConsensusProfiles() != null)); oviewCanvas = new OverviewCanvas(od, av); setLayout(new BorderLayout()); diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index d74bbb7..86ee370 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -1497,7 +1497,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, } // always do this - annotation has own state // but defer colourscheme update until hidden sequences are passed in - boolean vischange = stretchGroup.recalcConservation(true); + boolean vischange = stretchGroup.recalcAnnotations(true); // here we rely on stretchGroup == av.getSelection() needOverviewUpdate |= vischange && av.isSelectionDefinedGroup() && afterDrag; diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 7f42d98..eb641d1 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -51,6 +51,8 @@ public class Alignment implements AlignmentI protected List sequences; + private SequenceI hmmConsensus; + protected List groups; protected char gapCharacter = '-'; @@ -1922,23 +1924,15 @@ public class Alignment implements AlignmentI hiddenCols = cols; } - /** - * Returns all HMM consensus sequences. This will not return real sequences - * with HMMs. - */ @Override - public List getHMMConsensusSequences() + public SequenceI getHmmConsensus() { - List seqs = new ArrayList<>(); + return hmmConsensus; + } - for (int position = 0; position < sequences.size(); position++) - { - SequenceI seq = sequences.get(position); - if (seq.isHMMConsensusSequence()) - { - seqs.add(seq); - } - } - return seqs; + @Override + public void setHmmConsensus(SequenceI hmmConsensus) + { + this.hmmConsensus = hmmConsensus; } } diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index 268751e..93b6f16 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -94,76 +94,6 @@ public class AlignmentAnnotation private long invalidrnastruc = -2; /** - * Updates the _rnasecstr field Determines the positions that base pair and - * the positions of helices based on secondary structure from a Stockholm file - * - * @param rnaAnnotation - */ - private void _updateRnaSecStr(CharSequence rnaAnnotation) - { - try - { - _rnasecstr = Rna.getHelixMap(rnaAnnotation); - invalidrnastruc = -1; - } catch (WUSSParseException px) - { - // DEBUG System.out.println(px); - invalidrnastruc = px.getProblemPos(); - } - if (invalidrnastruc > -1) - { - return; - } - - if (_rnasecstr != null && _rnasecstr.length > 0) - { - // show all the RNA secondary structure annotation symbols. - isrna = true; - showAllColLabels = true; - scaleColLabel = true; - _markRnaHelices(); - } - // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup()); - - } - - private void _markRnaHelices() - { - int mxval = 0; - // Figure out number of helices - // Length of rnasecstr is the number of pairs of positions that base pair - // with each other in the secondary structure - for (int x = 0; x < _rnasecstr.length; x++) - { - - /* - * System.out.println(this.annotation._rnasecstr[x] + " Begin" + - * this.annotation._rnasecstr[x].getBegin()); - */ - // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup()); - int val = 0; - try - { - val = Integer.valueOf(_rnasecstr[x].getFeatureGroup()); - if (mxval < val) - { - mxval = val; - } - } catch (NumberFormatException q) - { - } - ; - - annotations[_rnasecstr[x].getBegin()].value = val; - annotations[_rnasecstr[x].getEnd()].value = val; - - // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val; - // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val; - } - setScore(mxval); - } - - /** * map of positions in the associated annotation */ private Map sequenceMapping; @@ -282,6 +212,245 @@ public class AlignmentAnnotation } /** + * Copy constructor creates a new independent annotation row with the same + * associated sequenceRef + * + * @param annotation + */ + public AlignmentAnnotation(AlignmentAnnotation annotation) + { + setAnnotationId(); + this.label = new String(annotation.label); + if (annotation.description != null) + { + this.description = new String(annotation.description); + } + this.graphMin = annotation.graphMin; + this.graphMax = annotation.graphMax; + this.graph = annotation.graph; + this.graphHeight = annotation.graphHeight; + this.graphGroup = annotation.graphGroup; + this.groupRef = annotation.groupRef; + this.editable = annotation.editable; + this.autoCalculated = annotation.autoCalculated; + this.hasIcons = annotation.hasIcons; + this.hasText = annotation.hasText; + this.height = annotation.height; + this.label = annotation.label; + this.padGaps = annotation.padGaps; + this.visible = annotation.visible; + this.centreColLabels = annotation.centreColLabels; + this.scaleColLabel = annotation.scaleColLabel; + this.showAllColLabels = annotation.showAllColLabels; + this.calcId = annotation.calcId; + if (annotation.properties != null) + { + properties = new HashMap<>(); + for (Map.Entry val : annotation.properties.entrySet()) + { + properties.put(val.getKey(), val.getValue()); + } + } + if (this.hasScore = annotation.hasScore) + { + this.score = annotation.score; + } + if (annotation.threshold != null) + { + threshold = new GraphLine(annotation.threshold); + } + Annotation[] ann = annotation.annotations; + if (annotation.annotations != null) + { + this.annotations = new Annotation[ann.length]; + for (int i = 0; i < ann.length; i++) + { + if (ann[i] != null) + { + annotations[i] = new Annotation(ann[i]); + if (_linecolour != null) + { + _linecolour = annotations[i].colour; + } + } + } + } + if (annotation.sequenceRef != null) + { + this.sequenceRef = annotation.sequenceRef; + if (annotation.sequenceMapping != null) + { + Integer p = null; + sequenceMapping = new HashMap<>(); + Iterator pos = annotation.sequenceMapping.keySet() + .iterator(); + while (pos.hasNext()) + { + // could optimise this! + p = pos.next(); + Annotation a = annotation.sequenceMapping.get(p); + if (a == null) + { + continue; + } + if (ann != null) + { + for (int i = 0; i < ann.length; i++) + { + if (ann[i] == a) + { + sequenceMapping.put(p, annotations[i]); + } + } + } + } + } + else + { + this.sequenceMapping = null; + } + } + // TODO: check if we need to do this: JAL-952 + // if (this.isrna=annotation.isrna) + { + // _rnasecstr=new SequenceFeature[annotation._rnasecstr]; + } + validateRangeAndDisplay(); // construct hashcodes, etc. + } + + /** + * copy constructor with edit based on the hidden columns marked in colSel + * + * @param alignmentAnnotation + * @param colSel + */ + public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, + HiddenColumns hidden) + { + this(alignmentAnnotation); + if (annotations == null) + { + return; + } + hidden.makeVisibleAnnotation(this); + } + + /** + * Creates a new AlignmentAnnotation object. + * + * @param label + * DOCUMENT ME! + * @param description + * DOCUMENT ME! + * @param annotations + * DOCUMENT ME! + * @param min + * DOCUMENT ME! + * @param max + * DOCUMENT ME! + * @param winLength + * DOCUMENT ME! + */ + public AlignmentAnnotation(String label, String description, + Annotation[] annotations, float min, float max, int graphType) + { + setAnnotationId(); + // graphs are not editable + editable = graphType == 0; + + this.label = label; + this.description = description; + this.annotations = annotations; + graph = graphType; + graphMin = min; + graphMax = max; + validateRangeAndDisplay(); + } + + /** + * Score only annotation + * + * @param label + * @param description + * @param score + */ + public AlignmentAnnotation(String label, String description, double score) + { + this(label, description, null); + setScore(score); + } + + /** + * Updates the _rnasecstr field Determines the positions that base pair and + * the positions of helices based on secondary structure from a Stockholm file + * + * @param rnaAnnotation + */ + private void _updateRnaSecStr(CharSequence rnaAnnotation) + { + try + { + _rnasecstr = Rna.getHelixMap(rnaAnnotation); + invalidrnastruc = -1; + } catch (WUSSParseException px) + { + // DEBUG System.out.println(px); + invalidrnastruc = px.getProblemPos(); + } + if (invalidrnastruc > -1) + { + return; + } + + if (_rnasecstr != null && _rnasecstr.length > 0) + { + // show all the RNA secondary structure annotation symbols. + isrna = true; + showAllColLabels = true; + scaleColLabel = true; + _markRnaHelices(); + } + // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup()); + + } + + private void _markRnaHelices() + { + int mxval = 0; + // Figure out number of helices + // Length of rnasecstr is the number of pairs of positions that base pair + // with each other in the secondary structure + for (int x = 0; x < _rnasecstr.length; x++) + { + + /* + * System.out.println(this.annotation._rnasecstr[x] + " Begin" + + * this.annotation._rnasecstr[x].getBegin()); + */ + // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup()); + int val = 0; + try + { + val = Integer.valueOf(_rnasecstr[x].getFeatureGroup()); + if (mxval < val) + { + mxval = val; + } + } catch (NumberFormatException q) + { + } + ; + + annotations[_rnasecstr[x].getBegin()].value = val; + annotations[_rnasecstr[x].getEnd()].value = val; + + // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val; + // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val; + } + setScore(mxval); + } + + /** * Checks if annotation labels represent secondary structures * */ @@ -521,38 +690,6 @@ public class AlignmentAnnotation } /** - * Creates a new AlignmentAnnotation object. - * - * @param label - * DOCUMENT ME! - * @param description - * DOCUMENT ME! - * @param annotations - * DOCUMENT ME! - * @param min - * DOCUMENT ME! - * @param max - * DOCUMENT ME! - * @param winLength - * DOCUMENT ME! - */ - public AlignmentAnnotation(String label, String description, - Annotation[] annotations, float min, float max, int graphType) - { - setAnnotationId(); - // graphs are not editable - editable = graphType == 0; - - this.label = label; - this.description = description; - this.annotations = annotations; - graph = graphType; - graphMin = min; - graphMax = max; - validateRangeAndDisplay(); - } - - /** * checks graphMin and graphMax, secondary structure symbols, sets graphType * appropriately, sets null labels to the empty string if appropriate. */ @@ -633,113 +770,6 @@ public class AlignmentAnnotation } /** - * Copy constructor creates a new independent annotation row with the same - * associated sequenceRef - * - * @param annotation - */ - public AlignmentAnnotation(AlignmentAnnotation annotation) - { - setAnnotationId(); - this.label = new String(annotation.label); - if (annotation.description != null) - { - this.description = new String(annotation.description); - } - this.graphMin = annotation.graphMin; - this.graphMax = annotation.graphMax; - this.graph = annotation.graph; - this.graphHeight = annotation.graphHeight; - this.graphGroup = annotation.graphGroup; - this.groupRef = annotation.groupRef; - this.editable = annotation.editable; - this.autoCalculated = annotation.autoCalculated; - this.hasIcons = annotation.hasIcons; - this.hasText = annotation.hasText; - this.height = annotation.height; - this.label = annotation.label; - this.padGaps = annotation.padGaps; - this.visible = annotation.visible; - this.centreColLabels = annotation.centreColLabels; - this.scaleColLabel = annotation.scaleColLabel; - this.showAllColLabels = annotation.showAllColLabels; - this.calcId = annotation.calcId; - if (annotation.properties != null) - { - properties = new HashMap<>(); - for (Map.Entry val : annotation.properties.entrySet()) - { - properties.put(val.getKey(), val.getValue()); - } - } - if (this.hasScore = annotation.hasScore) - { - this.score = annotation.score; - } - if (annotation.threshold != null) - { - threshold = new GraphLine(annotation.threshold); - } - Annotation[] ann = annotation.annotations; - if (annotation.annotations != null) - { - this.annotations = new Annotation[ann.length]; - for (int i = 0; i < ann.length; i++) - { - if (ann[i] != null) - { - annotations[i] = new Annotation(ann[i]); - if (_linecolour != null) - { - _linecolour = annotations[i].colour; - } - } - } - } - if (annotation.sequenceRef != null) - { - this.sequenceRef = annotation.sequenceRef; - if (annotation.sequenceMapping != null) - { - Integer p = null; - sequenceMapping = new HashMap<>(); - Iterator pos = annotation.sequenceMapping.keySet() - .iterator(); - while (pos.hasNext()) - { - // could optimise this! - p = pos.next(); - Annotation a = annotation.sequenceMapping.get(p); - if (a == null) - { - continue; - } - if (ann != null) - { - for (int i = 0; i < ann.length; i++) - { - if (ann[i] == a) - { - sequenceMapping.put(p, annotations[i]); - } - } - } - } - } - else - { - this.sequenceMapping = null; - } - } - // TODO: check if we need to do this: JAL-952 - // if (this.isrna=annotation.isrna) - { - // _rnasecstr=new SequenceFeature[annotation._rnasecstr]; - } - validateRangeAndDisplay(); // construct hashcodes, etc. - } - - /** * clip the annotation to the columns given by startRes and endRes (inclusive) * and prune any existing sequenceMapping to just those columns. * @@ -1097,36 +1127,6 @@ public class AlignmentAnnotation return hasScore || !Double.isNaN(score); } - /** - * Score only annotation - * - * @param label - * @param description - * @param score - */ - public AlignmentAnnotation(String label, String description, double score) - { - this(label, description, null); - setScore(score); - } - - /** - * copy constructor with edit based on the hidden columns marked in colSel - * - * @param alignmentAnnotation - * @param colSel - */ - public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, - HiddenColumns hidden) - { - this(alignmentAnnotation); - if (annotations == null) - { - return; - } - hidden.makeVisibleAnnotation(this); - } - public void setPadGaps(boolean padgaps, char gapchar) { this.padGaps = padgaps; diff --git a/src/jalview/datamodel/SequenceCollectionI.java b/src/jalview/datamodel/SequenceCollectionI.java index 4203b16..ee4b844 100644 --- a/src/jalview/datamodel/SequenceCollectionI.java +++ b/src/jalview/datamodel/SequenceCollectionI.java @@ -72,9 +72,14 @@ public interface SequenceCollectionI boolean isNucleotide(); /** - * Returns all HMM consensus sequences (possibly an empty list) + * Returns the HMM consensus sequence (if any) for the collection, or null * * @return */ - List getHMMConsensusSequences(); + SequenceI getHmmConsensus(); + + /** + * Sets the HMM consensus sequence for the collection + */ + void setHmmConsensus(SequenceI hmmSeq); } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 676f318..5e5a988 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -45,128 +45,120 @@ import java.util.Map; public class SequenceGroup implements AnnotatedCollectionI { // TODO ideally this event notification functionality should be separated into - // a - // subclass of ViewportProperties similarly to ViewportRanges. Done here as - // quick fix for JAL-2665 + // a subclass of ViewportProperties similarly to ViewportRanges. + // Done here as a quick fix for JAL-2665 public static final String SEQ_GROUP_CHANGED = "Sequence group changed"; - protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); + private String groupName; - public void addPropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.addPropertyChangeListener(listener); - } + private String description; - public void removePropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.removePropertyChangeListener(listener); - } - // end of event notification functionality initialisation + private AnnotatedCollectionI context; - String groupName; + private Conservation conservationData; - String description; + private ProfilesI consensusProfiles; - Conservation conserve; + private ProfilesI hmmProfiles; - boolean displayBoxes = true; + private boolean displayBoxes = true; - boolean displayText = true; + private boolean displayText = true; - boolean colourText = false; + private boolean colourText = false; - /** - * True if the group is defined as a group on the alignment, false if it is - * just a selection. + /* + * true if the group is defined as a group on the alignment, false if it is + * just a selection */ - boolean isDefined = false; + private boolean isDefined; - /** + /* * after Olivier's non-conserved only character display */ - boolean showNonconserved = false; + private boolean showNonconserved; - /** - * group members + /* + * sequences in the group */ private List sequences = new ArrayList<>(); - /** + /* * representative sequence for this group (if any) */ - private SequenceI seqrep = null; + private SequenceI seqrep; - int width = -1; + /* + * HMM consensus sequence for group (if any) + */ + private SequenceI hmmConsensus; - /** - * Colourscheme applied to group if any + private int width = -1; + + /* + * colour scheme applied to group if any */ public ResidueShaderI cs; // start column (base 0) - int startRes = 0; + private int startRes; // end column (base 0) - int endRes = 0; + private int endRes; public Color outlineColour = Color.black; - public Color idColour = null; + public Color idColour; - public int thresholdTextColour = 0; + public int thresholdTextColour; public Color textColour = Color.black; public Color textColour2 = Color.white; - /** - * consensus calculation property + /* + * properties for consensus annotation */ private boolean ignoreGapsInConsensus = true; - private boolean ignoreBelowBackground = true; + private boolean showSequenceLogo; - private boolean infoLetterHeight = false; + private boolean normaliseSequenceLogo; - /** - * consensus calculation property - */ - private boolean showSequenceLogo = false; + private boolean showConsensusHistogram; - /** - * flag indicating if logo should be rendered normalised + /* + * properties for HMM information annotation */ - private boolean normaliseSequenceLogo; + private boolean hmmIgnoreBelowBackground = true; + + private boolean hmmUseInfoLetterHeight; + + private boolean showHMMSequenceLogo; + + private boolean hmmNormaliseSequenceLogo; + + private boolean hmmShowHistogram; /* * visibility of rows or represented rows covered by group */ - private boolean hidereps = false; + private boolean hidereps; /* * visibility of columns intersecting this group */ - private boolean hidecols = false; - - AlignmentAnnotation consensus = null; - - AlignmentAnnotation conservation = null; - - AlignmentAnnotation information = null; - - private boolean showConsensusHistogram; - - private AnnotatedCollectionI context; + private boolean hidecols; - private boolean showHMMSequenceLogo; + private AlignmentAnnotation consensus; - private boolean normaliseHMMSequenceLogo; + private AlignmentAnnotation conservation; - private boolean showInformationHistogram; + private AlignmentAnnotation hmmInformation; /** - * Creates a new SequenceGroup object. + * Constructor, assigning a generated default name of "JGroup:" with object + * hashcode appended */ public SequenceGroup() { @@ -237,8 +229,8 @@ public class SequenceGroup implements AnnotatedCollectionI normaliseSequenceLogo = seqsel.normaliseSequenceLogo; showConsensusHistogram = seqsel.showConsensusHistogram; showHMMSequenceLogo = seqsel.showHMMSequenceLogo; - normaliseHMMSequenceLogo = seqsel.normaliseHMMSequenceLogo; - showInformationHistogram = seqsel.showInformationHistogram; + hmmNormaliseSequenceLogo = seqsel.hmmNormaliseSequenceLogo; + hmmShowHistogram = seqsel.hmmShowHistogram; idColour = seqsel.idColour; outlineColour = seqsel.outlineColour; seqrep = seqsel.seqrep; @@ -247,9 +239,9 @@ public class SequenceGroup implements AnnotatedCollectionI thresholdTextColour = seqsel.thresholdTextColour; width = seqsel.width; ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus; - ignoreBelowBackground = seqsel.ignoreBelowBackground; - infoLetterHeight = seqsel.infoLetterHeight; - if (seqsel.conserve != null) + hmmIgnoreBelowBackground = seqsel.hmmIgnoreBelowBackground; + hmmUseInfoLetterHeight = seqsel.hmmUseInfoLetterHeight; + if (seqsel.conservationData != null) { recalcConservation(); // safer than // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ?? @@ -257,6 +249,19 @@ public class SequenceGroup implements AnnotatedCollectionI } } + protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( + this); + + public void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + public boolean isShowSequenceLogo() { return showSequenceLogo; @@ -508,7 +513,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public Conservation getConservation() { - return conserve; + return conservationData; } /** @@ -519,7 +524,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public void setConservation(Conservation c) { - conserve = c; + conservationData = c; } /** @@ -580,21 +585,22 @@ public class SequenceGroup implements AnnotatedCollectionI */ public boolean recalcConservation() { - return recalcConservation(false); + return recalcAnnotations(false); } /** - * calculate residue conservation for group - but only if necessary. returns - * true if the calculation resulted in a visible change to group + * Recalculates column consensus, conservation, and HMM annotation for the + * group (as applicable). Returns true if the calculation resulted in a + * visible change to group. * * @param defer * when set, colourschemes for this group are not refreshed after * recalculation */ - public boolean recalcConservation(boolean defer) + public boolean recalcAnnotations(boolean defer) { if (cs == null && consensus == null && conservation == null - && information == null) + && hmmInformation == null) { return false; } @@ -605,14 +611,14 @@ public class SequenceGroup implements AnnotatedCollectionI { ProfilesI cnsns = AAFrequency.calculate(sequences, startRes, endRes + 1, showSequenceLogo); - if (information != null) + if (hmmInformation != null) { - HiddenMarkovModel hmm = information.sequenceRef.getHMM(); + HiddenMarkovModel hmm = hmmInformation.sequenceRef.getHMM(); ProfilesI info = AAFrequency.calculateHMMProfiles(hmm, (endRes + 1) - startRes, startRes, endRes + 1, - showHMMSequenceLogo, ignoreBelowBackground, - infoLetterHeight); + showHMMSequenceLogo, hmmIgnoreBelowBackground, + hmmUseInfoLetterHeight); _updateInformationRow(info, sequences.size()); upd = true; } @@ -688,10 +694,6 @@ public class SequenceGroup implements AnnotatedCollectionI c.completeAnnotations(conservation, null, startRes, endRes + 1); } - public ProfilesI consensusData = null; - - public ProfilesI informationData = null; - private void _updateConsensusRow(ProfilesI cnsns, long nseq) { if (consensus == null) @@ -700,7 +702,7 @@ public class SequenceGroup implements AnnotatedCollectionI } consensus.label = "Consensus for " + getName(); consensus.description = "Percent Identity"; - consensusData = cnsns; + consensusProfiles = cnsns; // preserve width if already set int aWidth = (consensus.annotations != null) ? (endRes < consensus.annotations.length @@ -725,23 +727,23 @@ public class SequenceGroup implements AnnotatedCollectionI */ private void _updateInformationRow(ProfilesI cnsns, long nseq) { - if (information == null) + if (hmmInformation == null) { - getInformation(); + createInformationAnnotation(); } - information.description = MessageManager + hmmInformation.description = MessageManager .getString("label.information_description"); - informationData = cnsns; + setHmmProfiles(cnsns); // preserve width if already set - int aWidth = (information.annotations != null) - ? (endRes < information.annotations.length - ? information.annotations.length : endRes + 1) + int aWidth = (hmmInformation.annotations != null) + ? (endRes < hmmInformation.annotations.length + ? hmmInformation.annotations.length : endRes + 1) : endRes + 1; - information.annotations = null; - information.annotations = new Annotation[aWidth]; // should be alignment + hmmInformation.annotations = null; + hmmInformation.annotations = new Annotation[aWidth]; // should be alignment // width - information.setCalcId(InformationThread.HMM_CALC_ID); - AAFrequency.completeInformation(information, cnsns, startRes, + hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); + AAFrequency.completeInformation(hmmInformation, cnsns, startRes, endRes + 1, nseq, 0f); } @@ -1199,26 +1201,19 @@ public class SequenceGroup implements AnnotatedCollectionI } /** - * Answers the Hidden Markov Model annotation for this group (creating it if - * necessary) - * - * @return + * Creates the Hidden Markov Model annotation for this group */ - public AlignmentAnnotation getInformation() + void createInformationAnnotation() { - if (information == null) - { - information = new AlignmentAnnotation("", "", new Annotation[1], 0f, - 6.25f, AlignmentAnnotation.BAR_GRAPH); - information.hasText = true; - information.autoCalculated = false; - information.groupRef = this; - information.label = getName(); - information.description = MessageManager - .getString("label.information_description"); - information.setCalcId(InformationThread.HMM_CALC_ID); - } - return information; + hmmInformation = new AlignmentAnnotation("", "", new Annotation[1], 0f, + 6.25f, AlignmentAnnotation.BAR_GRAPH); + hmmInformation.hasText = true; + hmmInformation.autoCalculated = false; + hmmInformation.groupRef = this; + hmmInformation.label = getName(); + hmmInformation.description = MessageManager + .getString("label.information_description"); + hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); } /** @@ -1302,37 +1297,29 @@ public class SequenceGroup implements AnnotatedCollectionI ignoreGapsInConsensus = state; } - public boolean getIgnoreGapsConsensus() + public boolean isIgnoreGapsConsensus() { return ignoreGapsInConsensus; } public void setIgnoreBelowBackground(boolean state) { - if (this.ignoreBelowBackground != state) - { - ignoreBelowBackground = state; - } - ignoreBelowBackground = state; + hmmIgnoreBelowBackground = state; } - public boolean getIgnoreBelowBackground() + public boolean isIgnoreBelowBackground() { - return ignoreBelowBackground; + return hmmIgnoreBelowBackground; } public void setInfoLetterHeight(boolean state) { - if (this.infoLetterHeight != state) - { - infoLetterHeight = state; - } - infoLetterHeight = state; + hmmUseInfoLetterHeight = state; } - public boolean getInfoLetterHeight() + public boolean isUseInfoLetterHeight() { - return infoLetterHeight; + return hmmUseInfoLetterHeight; } /** @@ -1581,17 +1568,17 @@ public class SequenceGroup implements AnnotatedCollectionI public boolean isShowInformationHistogram() { - return showInformationHistogram; + return hmmShowHistogram; } public void setShowInformationHistogram(boolean state) { - if (showInformationHistogram != state && information != null) + if (hmmShowHistogram != state && hmmInformation != null) { - this.showInformationHistogram = state; + this.hmmShowHistogram = state; // recalcConservation(); TODO don't know what to do here next } - this.showInformationHistogram = state; + this.hmmShowHistogram = state; } @@ -1608,7 +1595,7 @@ public class SequenceGroup implements AnnotatedCollectionI public boolean isNormaliseHMMSequenceLogo() { - return normaliseHMMSequenceLogo; + return hmmNormaliseSequenceLogo; } public void setNormaliseHMMSequenceLogo(boolean state) @@ -1616,24 +1603,31 @@ public class SequenceGroup implements AnnotatedCollectionI normaliseSequenceLogo = state; } - /** - * Returns all HMM consensus sequences. This will not return real sequences - * with HMMs. - */ @Override - public List getHMMConsensusSequences() + public SequenceI getHmmConsensus() { - List seqs = new ArrayList<>(); + return hmmConsensus; + } - for (int position = 0; position < sequences.size(); position++) - { - SequenceI seq = sequences.get(position); - if (seq.isHMMConsensusSequence()) - { - seqs.add(seq); - } - } - return seqs; + @Override + public void setHmmConsensus(SequenceI hmmSeq) + { + this.hmmConsensus = hmmSeq; + } + + public ProfilesI getConsensusData() + { + return consensusProfiles; + } + + public ProfilesI getHmmProfiles() + { + return hmmProfiles; + } + + public void setHmmProfiles(ProfilesI hmmProfiles) + { + this.hmmProfiles = hmmProfiles; } } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index b218e7a..7c5375c 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -63,11 +63,11 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.ColourMenuHelper.ColourChangeListener; import jalview.gui.ViewSelectionMenu.ViewSetProvider; -import jalview.hmmer.HMMAlignThread; -import jalview.hmmer.HMMBuildThread; +import jalview.hmmer.HMMAlign; +import jalview.hmmer.HMMBuild; import jalview.hmmer.HMMERParamStore; import jalview.hmmer.HMMERPreset; -import jalview.hmmer.HMMSearchThread; +import jalview.hmmer.HMMSearch; import jalview.hmmer.HmmerCommand; import jalview.io.AlignmentProperties; import jalview.io.AnnotationFile; @@ -1037,7 +1037,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, args); if (params.showRunDialog()) { - new Thread(new HMMBuildThread(this, params.getJobParams())).start(); + new Thread(new HMMBuild(this, params.getJobParams())).start(); } alignPanel.repaint(); @@ -1057,7 +1057,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, args); if (params.showRunDialog()) { - new Thread(new HMMAlignThread(this, params.getJobParams())) + new Thread(new HMMAlign(this, params.getJobParams())) .start(); } alignPanel.repaint(); @@ -1077,7 +1077,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, args); if (params.showRunDialog()) { - new Thread(new HMMSearchThread(this, params.getJobParams())) + new Thread(new HMMSearch(this, params.getJobParams())) .start(); } alignPanel.repaint(); @@ -1090,7 +1090,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return; } - new Thread(new HMMBuildThread(this, null)) + new Thread(new HMMBuild(this, null)) .start(); } @@ -1101,7 +1101,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return; } - new Thread(new HMMAlignThread(this, null)).start(); + new Thread(new HMMAlign(this, null)).start(); } @Override @@ -1111,7 +1111,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { return; } - new Thread(new HMMSearchThread(this, null)).start(); + new Thread(new HMMSearch(this, null)).start(); } /** diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index ef95161..192d82a 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -267,7 +267,7 @@ public class AlignViewport extends AlignmentViewport // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done - if (hconsensus == null && !isDataset) + if (consensusProfiles == null && !isDataset) { if (!al.isNucleotide()) { @@ -312,7 +312,7 @@ public class AlignViewport extends AlignmentViewport if (residueShading != null) { - residueShading.setConsensus(hconsensus); + residueShading.setConsensus(consensusProfiles); } } diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index 3112fe1..dbf2ab1 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -388,6 +388,10 @@ public class AnnotationLabels extends JPanel pop.show(this, evt.getX(), evt.getY()); return; } + + final AlignmentAnnotation ann = aa[selectedRow]; + final boolean isSequenceAnnotation = ann.sequenceRef != null; + item = new JMenuItem(EDITNAME); item.addActionListener(this); pop.add(item); @@ -397,9 +401,9 @@ public class AnnotationLabels extends JPanel // JAL-1264 hide all sequence-specific annotations of this type if (selectedRow < aa.length) { - if (aa[selectedRow].sequenceRef != null) + if (isSequenceAnnotation) { - final String label = aa[selectedRow].label; + final String label = ann.label; JMenuItem hideType = new JMenuItem(); String text = MessageManager.getString("label.hide_all") + " " + label; @@ -412,15 +416,6 @@ public class AnnotationLabels extends JPanel AlignmentUtils.showOrHideSequenceAnnotations( ap.av.getAlignment(), Collections.singleton(label), null, false, false); - // for (AlignmentAnnotation ann : ap.av.getAlignment() - // .getAlignmentAnnotation()) - // { - // if (ann.sequenceRef != null && ann.label != null - // && ann.label.equals(label)) - // { - // ann.visible = false; - // } - // } ap.refresh(true); } }); @@ -443,397 +438,314 @@ public class AnnotationLabels extends JPanel // property methods if (selectedRow < aa.length) { - final String label = aa[selectedRow].label; - if (!(aa[selectedRow].autoCalculated) - && !(InformationThread.HMM_CALC_ID - .equals(aa[selectedRow].getCalcId()))) + final String label = ann.label; + if (!(ann.autoCalculated) + && !(InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))) { - if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH) + if (ann.graph == AlignmentAnnotation.NO_GRAPH) { // display formatting settings for this row. pop.addSeparator(); // av and sequencegroup need to implement same interface for item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE, - aa[selectedRow].scaleColLabel); + ann.scaleColLabel); item.addActionListener(this); pop.add(item); } } else if (label.indexOf("Consensus") > -1) { + addConsensusMenu(pop, ann); + } + else if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId())) + { + addHmmerMenu(pop, ann); + } + } + pop.show(this, evt.getX(), evt.getY()); + } - - pop.addSeparator(); - // av and sequencegroup need to implement same interface for - - final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( - MessageManager.getString("label.ignore_gaps_consensus"), - (aa[selectedRow].groupRef != null) - ? aa[selectedRow].groupRef.getIgnoreGapsConsensus() - : ap.av.isIgnoreGapsConsensus()); - final AlignmentAnnotation aaa = aa[selectedRow]; - cbmi.addActionListener(new ActionListener() + /** + * Adds context menu options for (alignment or group) Hmmer annotation + * + * @param pop + * @param ann + */ + protected void addHmmerMenu(JPopupMenu pop, final AlignmentAnnotation ann) + { + final boolean isGroupAnnotation = ann.groupRef != null; + pop.addSeparator(); + final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( + MessageManager.getString( + "label.ignore_below_background_frequency"), + isGroupAnnotation + ? ann.groupRef + .isIgnoreBelowBackground() + : ap.av.isIgnoreBelowBackground()); + cbmi.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) { - @Override - public void actionPerformed(ActionEvent e) + if (!ann.groupRef.isUseInfoLetterHeight()) { - if (aaa.groupRef != null) - { - // TODO: pass on reference to ap so the view can be updated. - aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState()); - ap.getAnnotationPanel() - .paint(ap.getAnnotationPanel().getGraphics()); - } - else - { - ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap); - } - ap.alignmentChanged(); + ann.groupRef.setIgnoreBelowBackground(cbmi.getState()); } - }); - pop.add(cbmi); - // av and sequencegroup need to implement same interface for - if (aaa.groupRef != null) + } + else if (!ap.av.isInfoLetterHeight()) { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_histogram"), - aa[selectedRow].groupRef.isShowConsensusHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setShowConsensusHistogram(chist.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_logo"), - aa[selectedRow].groupRef.isShowSequenceLogo()); - cprofl.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setshowSequenceLogo(cprofl.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofl); - final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_group_logo"), - aa[selectedRow].groupRef.isNormaliseSequenceLogo()); - cproflnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState()); - // automatically enable logo display if we're clicked - aaa.groupRef.setshowSequenceLogo(true); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cproflnorm); + ap.av.setIgnoreBelowBackground(cbmi.getState(), ap); + } + ap.alignmentChanged(); + } + }); + pop.add(cbmi); + final JCheckBoxMenuItem letterHeight = new JCheckBoxMenuItem( + MessageManager.getString("label.use_info_for_height"), + isGroupAnnotation ? ann.groupRef.isUseInfoLetterHeight() + : ap.av.isInfoLetterHeight()); + letterHeight.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) + { + ann.groupRef.setInfoLetterHeight((letterHeight.getState())); + ann.groupRef.setIgnoreBelowBackground(true); } else { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_histogram"), - av.isShowConsensusHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowConsensusHistogram(chist.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( - MessageManager.getString("label.show_logo"), - av.isShowSequenceLogo()); - cprof.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowSequenceLogo(cprof.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprof); - final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_logo"), - av.isNormaliseSequenceLogo()); - cprofnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowSequenceLogo(true); - av.setNormaliseSequenceLogo(cprofnorm.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofnorm); + ap.av.setInfoLetterHeight(letterHeight.getState(), ap); + ap.av.setIgnoreBelowBackground(true, ap); } - final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ); - consclipbrd.addActionListener(this); - pop.add(consclipbrd); + ap.alignmentChanged(); } - else if (InformationThread.HMM_CALC_ID - .equals(aa[selectedRow].getCalcId())) + }); + pop.add(letterHeight); + if (isGroupAnnotation) + { + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_histogram"), + ann.groupRef.isShowInformationHistogram()); + chist.addActionListener(new ActionListener() { - pop.addSeparator(); - final AlignmentAnnotation aaa = aa[selectedRow]; - - final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( - MessageManager.getString( - "label.ignore_below_background_frequency"), - (aa[selectedRow].groupRef != null) - ? aa[selectedRow].groupRef - .getIgnoreBelowBackground() - : ap.av.isIgnoreBelowBackground()); - - cbmi.addActionListener(new ActionListener() + @Override + public void actionPerformed(ActionEvent e) { - @Override - public void actionPerformed(ActionEvent e) - { - - if (aaa.groupRef != null) - { - // TODO: pass on reference to ap so the view can be updated. - if (aaa.groupRef.getInfoLetterHeight() == false) - { - aaa.groupRef.setIgnoreBelowBackground(cbmi.getState()); - ap.getAnnotationPanel() - .paint(ap.getAnnotationPanel().getGraphics()); - } - } - else if (ap.av.isInfoLetterHeight() == false) - { - ap.av.setIgnoreBelowBackground(cbmi.getState(), ap); - } - ap.alignmentChanged(); - } - }); - pop.add(cbmi); - final JCheckBoxMenuItem letteHeight = new JCheckBoxMenuItem( - MessageManager.getString("label.use_info_for_height"), - (aa[selectedRow].groupRef != null) - ? aa[selectedRow].groupRef.getInfoLetterHeight() - : ap.av.isInfoLetterHeight()); - - letteHeight.addActionListener(new ActionListener() + ann.groupRef.setShowInformationHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_logo"), + ann.groupRef.isShowHMMSequenceLogo()); + cprofl.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) { - @Override - public void actionPerformed(ActionEvent e) - { - if (aaa.groupRef != null) - { - // TODO: pass on reference to ap so the view can be updated. - aaa.groupRef.setInfoLetterHeight((letteHeight.getState())); - if (aaa.groupRef.getIgnoreBelowBackground() == false) - { - aaa.groupRef.setIgnoreBelowBackground(true); - } - ap.getAnnotationPanel() - .paint(ap.getAnnotationPanel().getGraphics()); - } - else - { - ap.av.setInfoLetterHeight(letteHeight.getState(), ap); - if (ap.av.isIgnoreBelowBackground() == false) - { - ap.av.setIgnoreBelowBackground(true, ap); - } - } - ap.alignmentChanged(); - } - }); - pop.add(letteHeight); - if (aaa.groupRef != null) + ann.groupRef.setshowHMMSequenceLogo(cprofl.getState()); + ap.repaint(); + } + }); + pop.add(cprofl); + final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_group_logo"), + ann.groupRef.isNormaliseHMMSequenceLogo()); + cproflnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_histogram"), - aa[selectedRow].groupRef.isShowInformationHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setShowInformationHistogram(chist.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_logo"), - aa[selectedRow].groupRef.isShowHMMSequenceLogo()); - cprofl.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setshowHMMSequenceLogo(cprofl.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofl); - final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_group_logo"), - aa[selectedRow].groupRef.isNormaliseHMMSequenceLogo()); - cproflnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { + ann.groupRef + .setNormaliseHMMSequenceLogo(cproflnorm.getState()); + // automatically enable logo display if we're clicked + ann.groupRef.setshowHMMSequenceLogo(true); + ap.repaint(); + } + }); + pop.add(cproflnorm); + } + else + { + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_histogram"), + av.isShowInformationHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowInformationHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( + MessageManager.getString("label.show_logo"), + av.isShowHMMSequenceLogo()); + cprof.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.updateInformation(ap); + av.setShowHMMSequenceLogo(cprof.getState()); + ap.repaint(); + } + }); + pop.add(cprof); + final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_logo"), + av.isNormaliseHMMSequenceLogo()); + cprofnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowHMMSequenceLogo(true); + av.setNormaliseHMMSequenceLogo(cprofnorm.getState()); + ap.repaint(); + } + }); + pop.add(cprofnorm); + } + } - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef - .setNormaliseHMMSequenceLogo(cproflnorm.getState()); - // automatically enable logo display if we're clicked - aaa.groupRef.setshowHMMSequenceLogo(true); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cproflnorm); + /** + * Adds context menu options for (alignment or group) Consensus annotation + * + * @param pop + * @param ann + */ + protected void addConsensusMenu(JPopupMenu pop, + final AlignmentAnnotation ann) + { + final boolean isGroupAnnotation = ann.groupRef != null; + pop.addSeparator(); + + final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( + MessageManager.getString("label.ignore_gaps_consensus"), + (ann.groupRef != null) + ? ann.groupRef.isIgnoreGapsConsensus() + : ap.av.isIgnoreGapsConsensus()); + cbmi.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) + { + ann.groupRef.setIgnoreGapsConsensus(cbmi.getState()); } else { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_histogram"), - av.isShowInformationHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowInformationHistogram(chist.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( - MessageManager.getString("label.show_logo"), - av.isShowHMMSequenceLogo()); - cprof.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.updateInformation(ap); - av.setShowHMMSequenceLogo(cprof.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprof); - final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_logo"), - av.isNormaliseHMMSequenceLogo()); - cprofnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowHMMSequenceLogo(true); - av.setNormaliseHMMSequenceLogo(cprofnorm.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofnorm); + ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap); } + ap.alignmentChanged(); } + }); + pop.add(cbmi); + if (isGroupAnnotation) + { + /* + * group consensus options + */ + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_histogram"), + ann.groupRef.isShowConsensusHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setShowConsensusHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_logo"), + ann.groupRef.isShowSequenceLogo()); + cprofl.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setshowSequenceLogo(cprofl.getState()); + ap.repaint(); + } + }); + pop.add(cprofl); + final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_group_logo"), + ann.groupRef.isNormaliseSequenceLogo()); + cproflnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setNormaliseSequenceLogo(cproflnorm.getState()); + // automatically enable logo display if we're clicked + ann.groupRef.setshowSequenceLogo(true); + ap.repaint(); + } + }); + pop.add(cproflnorm); } - pop.show(this, evt.getX(), evt.getY()); + else + { + /* + * alignment consensus options + */ + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_histogram"), + av.isShowConsensusHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowConsensusHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( + MessageManager.getString("label.show_logo"), + av.isShowSequenceLogo()); + cprof.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowSequenceLogo(cprof.getState()); + ap.repaint(); + } + }); + pop.add(cprof); + final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_logo"), + av.isNormaliseSequenceLogo()); + cprofnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowSequenceLogo(true); + av.setNormaliseSequenceLogo(cprofnorm.getState()); + ap.repaint(); + } + }); + pop.add(cprofnorm); + } + final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ); + consclipbrd.addActionListener(this); + pop.add(consclipbrd); } /** @@ -1147,7 +1059,6 @@ public class AnnotationLabels extends JPanel PaintRefresher.Refresh(ap, ap.av.getSequenceSetId()); ap.av.sendSelection(); } - } } return; @@ -1200,7 +1111,6 @@ public class AnnotationLabels extends JPanel hiddenColumns = av.getAlignment().getHiddenColumns() .getHiddenColumnsCopy(); - } Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset @@ -1220,7 +1130,6 @@ public class AnnotationLabels extends JPanel @Override public void paintComponent(Graphics g) { - int width = getWidth(); if (width == 0) { @@ -1235,7 +1144,6 @@ public class AnnotationLabels extends JPanel } drawComponent(g2, true, width); - } /** diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index fdc2847..730bcb0 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1223,7 +1223,7 @@ public class Jalview2XML jGroup.setTextCol2(sg.textColour2.getRGB()); jGroup.setTextColThreshold(sg.thresholdTextColour); jGroup.setShowUnconserved(sg.getShowNonconserved()); - jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); + jGroup.setIgnoreGapsinConsensus(sg.isIgnoreGapsConsensus()); jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram()); jGroup.setShowSequenceLogo(sg.isShowSequenceLogo()); jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); @@ -4560,7 +4560,7 @@ public class Jalview2XML af.viewport.getResidueShading().setThreshold(view.getPidThreshold(), view.getIgnoreGapsinConsensus()); af.viewport.getResidueShading() - .setConsensus(af.viewport.getSequenceConsensusHash()); + .setConsensus(af.viewport.getConsensusProfiles()); af.viewport.setColourAppliesToAllGroups(false); if (view.getConservationSelected() && cs != null) diff --git a/src/jalview/gui/Jalview2XML_V1.java b/src/jalview/gui/Jalview2XML_V1.java index 331e738..5cbf228 100755 --- a/src/jalview/gui/Jalview2XML_V1.java +++ b/src/jalview/gui/Jalview2XML_V1.java @@ -413,7 +413,7 @@ public class Jalview2XML_V1 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(), true); af.viewport.getResidueShading() - .setConsensus(af.viewport.getSequenceConsensusHash()); + .setConsensus(af.viewport.getConsensusProfiles()); af.viewport.setColourAppliesToAllGroups(false); af.alignPanel.updateLayout(); af.changeColour(cs); diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index fb6efe5..2b1fcda 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -1853,7 +1853,7 @@ public class SeqPanel extends JPanel // always do this - annotation has own state // but defer colourscheme update until hidden sequences are passed in - boolean vischange = stretchGroup.recalcConservation(true); + boolean vischange = stretchGroup.recalcAnnotations(true); updateOverviewAndStructs |= vischange && av.isSelectionDefinedGroup() && afterDrag; if (stretchGroup.cs != null) diff --git a/src/jalview/hmmer/HMMAlignThread.java b/src/jalview/hmmer/HMMAlign.java similarity index 88% rename from src/jalview/hmmer/HMMAlignThread.java rename to src/jalview/hmmer/HMMAlign.java index fdc1c1c..942342c 100644 --- a/src/jalview/hmmer/HMMAlignThread.java +++ b/src/jalview/hmmer/HMMAlign.java @@ -21,32 +21,20 @@ import jalview.ws.params.ArgumentI; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; import javax.swing.JInternalFrame; -public class HMMAlignThread extends HmmerCommand implements Runnable +public class HMMAlign extends HmmerCommand { static final String HMMALIGN = "hmmalign"; static final String ARG_TRIM = "--trim"; - /* - * feature settings from view that job was associated with - */ - protected FeatureRendererSettings featureSettings = null; - - AlignmentI alignment; - - AlignmentI dataset; - - List orders; - - AlignmentView msa; - - HiddenMarkovModel hmm; + private final AlignmentI dataset; - SequenceI[][] allResults; + private AlignmentView msa; /** * Constructor for the HMMAlignThread @@ -54,27 +42,30 @@ public class HMMAlignThread extends HmmerCommand implements Runnable * @param af * @param args */ - public HMMAlignThread(AlignFrame af, List args) + public HMMAlign(AlignFrame af, List args) { super(af, args); - alignment = af.getViewport().getAlignment(); if (alignment.getDataset() != null) { dataset = alignment.getDataset(); } - featureSettings = af.getFeatureRenderer().getSettings(); + else + { + dataset = null; + } } /** * Runs the HMMAlignThread: the data on the alignment or group is exported, * then the command is executed in the command line and then the data is * imported and displayed in a new frame (if true). The command is executed - * for each segemtn of the alignment. + * for each segment of the alignment. Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. */ @Override public void run() { - hmm = af.getSelectedHMM(); + HiddenMarkovModel hmm = af.getSelectedHMM(); if (hmm == null) { System.err.println("Can't run hmmalign as no HMM profile selected"); @@ -88,11 +79,12 @@ public class HMMAlignThread extends HmmerCommand implements Runnable SequenceI[][] subAlignments = msa.getVisibleContigs('-'); List allOrders = new ArrayList<>(); - allResults = new SequenceI[subAlignments.length][]; + + SequenceI[][] allResults = new SequenceI[subAlignments.length][]; int job = 0; for (SequenceI[] seqs : subAlignments) { - stashSequences(seqs); + Hashtable sequencesHash = stashSequences(seqs); try { File modelFile = createTempFile("hmm", ".hmm"); @@ -111,6 +103,7 @@ public class HMMAlignThread extends HmmerCommand implements Runnable } SequenceI[] result = importData(resultFile, allOrders); + recoverSequences(sequencesHash, result); allResults[job] = result; modelFile.delete(); alignmentFile.delete(); @@ -122,7 +115,7 @@ public class HMMAlignThread extends HmmerCommand implements Runnable job++; } - displayResults(allOrders); + displayResults(allResults, allOrders); af.setProgressBar("", msgId); } @@ -189,7 +182,6 @@ public class HMMAlignThread extends HmmerCommand implements Runnable SequenceI[] result = file.getSeqsAsArray(); AlignmentOrder msaorder = new AlignmentOrder(result); AlignmentSorter.recoverOrder(result); - recoverSequences(result); allOrders.add(msaorder); return result; @@ -206,9 +198,12 @@ public class HMMAlignThread extends HmmerCommand implements Runnable /** * Displays the results of all 'jobs' in a new frame * + * @param allResults + * * @param allOrders */ - private void displayResults(List allOrders) + private void displayResults(SequenceI[][] allResults, + List allOrders) { AlignmentOrder[] arrOrders = allOrders .toArray(new AlignmentOrder[allOrders.size()]); @@ -242,8 +237,10 @@ public class HMMAlignThread extends HmmerCommand implements Runnable AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + FeatureRendererSettings featureSettings = af.getFeatureRenderer() + .getSettings(); // initialise with same renderer settings as in parent alignframe. - alignFrame.getFeatureRenderer().transferSettings(this.featureSettings); + alignFrame.getFeatureRenderer().transferSettings(featureSettings); addSortByMenuItems(alignFrame, alorders); @@ -345,24 +342,4 @@ public class HMMAlignThread extends HmmerCommand implements Runnable } } } - - /** - * Runs hmmalign, and waits for the results to be imported before continuing - */ - public void hmmalignWaitTillComplete() - { - Thread loader = new Thread(this); - loader.start(); - - while (loader.isAlive()) - { - try - { - Thread.sleep(500); - } catch (Exception ex) - { - } - } - - } } diff --git a/src/jalview/hmmer/HMMBuildThread.java b/src/jalview/hmmer/HMMBuild.java similarity index 67% rename from src/jalview/hmmer/HMMBuildThread.java rename to src/jalview/hmmer/HMMBuild.java index 60bde84..b892e5c 100644 --- a/src/jalview/hmmer/HMMBuildThread.java +++ b/src/jalview/hmmer/HMMBuild.java @@ -5,7 +5,6 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AnnotatedCollectionI; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -22,11 +21,17 @@ import jalview.ws.params.ArgumentI; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; import java.util.List; -import javax.swing.JOptionPane; - -public class HMMBuildThread extends HmmerCommand implements Runnable +/** + * A class that runs the hmmbuild command as a separate process. + * + * @author gmcarstairs + * + */ +public class HMMBuild extends HmmerCommand { static final String ARG_AMINO = "--amino"; @@ -34,41 +39,33 @@ public class HMMBuildThread extends HmmerCommand implements Runnable static final String ARG_RNA = "--rna"; - AlignmentI alignment; - /** * Constructor * * @param alignFrame * @param args */ - public HMMBuildThread(AlignFrame alignFrame, List args) + public HMMBuild(AlignFrame alignFrame, List args) { super(alignFrame, args); } /** * Builds a HMM from an alignment (and/or groups), then imports and adds it to - * the alignment (and/or groups) + * the alignment (and/or groups). Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. */ @Override public void run() { long msgID = System.currentTimeMillis(); - if (af != null) - { - af.setProgressBar(MessageManager.getString("status.running_hmmbuild"), - msgID); - } + af.setProgressBar(MessageManager.getString("status.running_hmmbuild"), + msgID); AlignViewportI viewport = af.getViewport(); try { - if (viewport != null) - { - alignment = viewport.getAlignment(); - } - List groups = new ArrayList<>(); + List runBuildFor = new ArrayList<>(); if (params != null) { for (ArgumentI arg : params) @@ -77,25 +74,25 @@ public class HMMBuildThread extends HmmerCommand implements Runnable if (MessageManager.getString("label.hmmbuild_for").equals(name)) { String value = arg.getValue(); - if (MessageManager.getString("label.alignment").equals(value)) + if (MessageManager.getString("label.alignment") + .equals(value)) { - alignment = viewport.getAlignment(); + runBuildFor.add(alignment); } else if (MessageManager.getString("label.groups_and_alignment") .equals(value)) { - alignment = viewport.getAlignment(); - groups.addAll(viewport.getAlignment().getGroups()); + runBuildFor.add(alignment); + runBuildFor.addAll(viewport.getAlignment().getGroups()); } else if (MessageManager.getString("label.groups").equals(value)) { - alignment = null; - groups = viewport.getAlignment().getGroups(); + runBuildFor.addAll(viewport.getAlignment().getGroups()); } - else if ("label.selected_group".equals(value)) + else if (MessageManager.getString("label.selected_group") + .equals(value)) { - alignment = null; - groups.add(viewport.getSelectionGroup()); + runBuildFor.add(viewport.getSelectionGroup()); } } else if (MessageManager.getString("label.use_reference") @@ -112,60 +109,39 @@ public class HMMBuildThread extends HmmerCommand implements Runnable } } - if (alignment != null) - { - // alignment.findOrCreateAnnotation("", HMMBUILD, autoCalc, seqRef, - // groupRef); - runHMMBuild(alignment); - } - - if (alignment == null) - { - alignment = viewport.getAlignment(); - } - - for (AnnotatedCollectionI grp : groups) + /* + * run hmmbuild for alignment and/or groups as selected + */ + for (AnnotatedCollectionI grp : runBuildFor) { runHMMBuild(grp); } } finally { - if (af != null) - { - viewport.updateInformation(af.alignPanel); - af.buildColourMenu(); // enable HMMER colour schemes - af.setProgressBar("", msgID); - } + viewport.updateInformation(af.alignPanel); + af.buildColourMenu(); // to enable HMMER colour schemes + af.setProgressBar("", msgID); } } /** - * Runs hmmbuild on the alignment, or on the group if one is specified + * Runs hmmbuild on the given sequences (alignment or group) * * @param grp */ private void runHMMBuild(AnnotatedCollectionI ac) { - if (ac == null) - { - JOptionPane.showMessageDialog(af, - MessageManager.getString("warn.no_sequence_data")); - } File hmmFile = null; File alignmentFile = null; try { hmmFile = createTempFile("hmm", ".hmm"); alignmentFile = createTempFile("output", ".sto"); - SequenceI[] array; - List hmmSeqs = null; - hmmSeqs = ac.getHMMConsensusSequences(); - if (ac instanceof SequenceGroup) - { - array = ((SequenceGroup) ac) - .getSelectionAsNewSequences(alignment); - } - else + List seqs = ac.getSequences(); + List copy = new ArrayList<>(); + copy.addAll(seqs); + + if (ac instanceof Alignment) { AlignmentI al = (Alignment) ac; // todo pad gaps in an unaligned SequenceGroup as well? @@ -173,17 +149,6 @@ public class HMMBuildThread extends HmmerCommand implements Runnable { al.padGaps(); } - array = al.getSequencesArray(); - } - - if (array.length < 1) - { - if (af != null) - { - JOptionPane.showMessageDialog(af, - MessageManager.getString("warn.no_sequence_data")); - } - return; } /* @@ -191,12 +156,13 @@ public class HMMBuildThread extends HmmerCommand implements Runnable * hmm sequences and their Information annotation are also deleted * in preparation for re-adding them when recalculated */ - SequenceI[] newArr = new SequenceI[array.length - hmmSeqs.size()]; - int index = 0; - for (SequenceI seq : array) + Iterator it = copy.iterator(); + while (it.hasNext()) { + SequenceI seq = it.next(); if (seq.isHMMConsensusSequence()) { + // todo leave it to InformationThread to delete annotations? AlignmentAnnotation[] seqAnnotations = seq .getAnnotation(); if (seqAnnotations != null) @@ -210,20 +176,16 @@ public class HMMBuildThread extends HmmerCommand implements Runnable } } alignment.deleteSequence(seq); - } - else - { - newArr[index] = new Sequence(seq); - index++; + it.remove(); } } - stashSequences(newArr); + SequenceI[] copyArray = copy.toArray(new SequenceI[copy.size()]); + Hashtable sequencesHash = stashSequences(copyArray); - exportStockholm(newArr, alignmentFile, - ac != null ? ac : alignment); + exportStockholm(copyArray, alignmentFile, ac); - recoverSequences(array); + recoverSequences(sequencesHash, seqs.toArray(new SequenceI[] {})); boolean ran = runCommand(alignmentFile, hmmFile, ac); if (!ran) @@ -347,24 +309,26 @@ public class HMMBuildThread extends HmmerCommand implements Runnable HMMFile file = new HMMFile( new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE)); SequenceI[] seqs = file.getSeqsAsArray(); - SequenceI seq = seqs[0]; - seq.createDatasetSequence(); + SequenceI hmmSeq = seqs[0]; + hmmSeq.createDatasetSequence(); if (ac instanceof SequenceGroup) { SequenceGroup grp = (SequenceGroup) ac; - seq.insertCharAt(0, ac.getStartRes(), '-'); - seq.insertCharAt(ac.getEndRes() + 1, + hmmSeq.insertCharAt(0, ac.getStartRes(), '-'); + hmmSeq.insertCharAt(ac.getEndRes() + 1, alignment.getWidth() - ac.getEndRes() - 1, '-'); - seq.updateHMMMapping(); + hmmSeq.updateHMMMapping(); SequenceI topSeq = grp.getSequencesInOrder(alignment)[0]; int topIndex = alignment.findIndex(topSeq); - alignment.insertSequenceAt(topIndex, seq); - ac.setSeqrep(seq); - grp.addSequence(seq, false); + alignment.insertSequenceAt(topIndex, hmmSeq); + ac.setSeqrep(hmmSeq); + grp.addSequence(hmmSeq, false); + grp.setHmmConsensus(hmmSeq); } else { - alignment.insertSequenceAt(0, seq); + alignment.insertSequenceAt(0, hmmSeq); + alignment.setHmmConsensus(hmmSeq); } AlignViewport viewport = af.getViewport(); @@ -377,26 +341,7 @@ public class HMMBuildThread extends HmmerCommand implements Runnable if (alignPanel.alignFrame.getSelectedHMM() == null) { - alignPanel.alignFrame.setSelectedHMMSequence(seq); - } - } - } - - /** - * Runs hmmbuild, and waits for the results to be imported before continuing - */ - public void hmmbuildWaitTillComplete() - { - Thread loader = new Thread(this); - loader.start(); - - while (loader.isAlive()) - { - try - { - Thread.sleep(500); - } catch (Exception ex) - { + alignPanel.alignFrame.setSelectedHMMSequence(hmmSeq); } } } diff --git a/src/jalview/hmmer/HMMSearchThread.java b/src/jalview/hmmer/HMMSearch.java similarity index 91% rename from src/jalview/hmmer/HMMSearchThread.java rename to src/jalview/hmmer/HMMSearch.java index d974b49..caf0b37 100644 --- a/src/jalview/hmmer/HMMSearchThread.java +++ b/src/jalview/hmmer/HMMSearch.java @@ -26,7 +26,7 @@ import java.util.Scanner; import javax.swing.JOptionPane; -public class HMMSearchThread extends HmmerCommand implements Runnable +public class HMMSearch extends HmmerCommand { static final String HMMSEARCH = "hmmsearch"; @@ -43,7 +43,7 @@ public class HMMSearchThread extends HmmerCommand implements Runnable * * @param af */ - public HMMSearchThread(AlignFrame af, List args) + public HMMSearch(AlignFrame af, List args) { super(af, args); } @@ -51,7 +51,8 @@ public class HMMSearchThread extends HmmerCommand implements Runnable /** * Runs the HMMSearchThread: the data on the alignment or group is exported, * then the command is executed in the command line and then the data is - * imported and displayed in a new frame + * imported and displayed in a new frame. Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. */ @Override public void run() @@ -194,10 +195,10 @@ public class HMMSearchThread extends HmmerCommand implements Runnable { AlignmentI alignment = af.getViewport().getAlignment(); AlignmentI copy = new Alignment(alignment); - List hmms = copy.getHMMConsensusSequences(); - for (SequenceI seq : hmms) + SequenceI hmms = copy.getHmmConsensus(); + if (hmms != null) { - copy.deleteSequence(seq); + copy.deleteSequence(hmms); } StockholmFile stoFile = new StockholmFile(copy); stoFile.setSeqs(copy.getSequencesArray()); @@ -256,8 +257,8 @@ public class HMMSearchThread extends HmmerCommand implements Runnable MessageManager.getString("label.trim_termini_desc"), true, true, true, null)); } - HMMAlignThread hmmalign = new HMMAlignThread(frame, alignArgs); - hmmalign.hmmalignWaitTillComplete(); + HMMAlign hmmalign = new HMMAlign(frame, alignArgs); + hmmalign.run(); frame = null; hmmTemp.delete(); inputAlignmentTemp.delete(); @@ -271,26 +272,6 @@ public class HMMSearchThread extends HmmerCommand implements Runnable } } - /** - * Runs hmmsearch, and waits for the results to be imported before continuing - */ - public void hmmsearchWaitTillComplete() - { - Thread loader = new Thread(this); - loader.start(); - - while (loader.isAlive()) - { - try - { - Thread.sleep(500); - } catch (Exception ex) - { - } - } - - } - void readTable(File inputTableTemp) throws IOException { BufferedReader br = new BufferedReader(new FileReader(inputTableTemp)); diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java index 557598b..a25e5cd 100644 --- a/src/jalview/hmmer/HmmerCommand.java +++ b/src/jalview/hmmer/HmmerCommand.java @@ -31,19 +31,26 @@ import java.util.List; * @author TZVanaalten * */ -public class HmmerCommand +public abstract class HmmerCommand implements Runnable { public static final String HMMBUILD = "hmmbuild"; - private Hashtable hash = new Hashtable(); + protected final AlignFrame af; - protected AlignFrame af; + protected final AlignmentI alignment; - protected List params; + protected final List params; + /** + * Constructor + * + * @param alignFrame + * @param args + */ public HmmerCommand(AlignFrame alignFrame, List args) { af = alignFrame; + alignment = af.getViewport().getAlignment(); params = args; } @@ -59,23 +66,25 @@ public class HmmerCommand * * @param seqs */ - protected void stashSequences(SequenceI[] seqs) + protected Hashtable stashSequences(SequenceI[] seqs) { - hash = SeqsetUtils.uniquify(seqs, true); + return SeqsetUtils.uniquify(seqs, true); } /** * Restores the sequence data lost by uniquifying * + * @param hashtable * @param seqs */ - protected void recoverSequences(SequenceI[] seqs) + protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs) { - SeqsetUtils.deuniquify(hash, seqs); + SeqsetUtils.deuniquify(hashtable, seqs); } /** - * Runs a command as a separate process + * Runs a command as a separate process and waits for it to complete. Answers + * true if the process return status is zero, else false. * * @param command * the executable command and any arguments to it @@ -87,7 +96,7 @@ public class HmmerCommand try { ProcessBuilder pb = new ProcessBuilder(command); - pb.redirectErrorStream(true); // send syserr to sysout + pb.redirectErrorStream(true); // merge syserr to sysout final Process p = pb.start(); new Thread(new Runnable() { diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index b3aea2c..1ef7e80 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -72,11 +72,14 @@ public class AnnotationRenderer private final boolean MAC = Platform.isAMac(); - boolean av_renderHistogram = true, av_renderProfile = true, - av_normaliseProfile = false; + // todo remove these flags, read from group/viewport where needed + boolean av_renderHistogram = true; - boolean av_renderInformationHistogram = true, av_renderHMMProfile = true, - av_normaliseHMMProfile = false, av_infoHeight = false; + boolean av_renderProfile = true; + + boolean av_normaliseProfile = false; + + boolean av_infoHeight = false; ResidueShaderI profcolour = null; @@ -333,9 +336,6 @@ public class AnnotationRenderer av_renderHistogram = av.isShowConsensusHistogram(); av_renderProfile = av.isShowSequenceLogo(); av_normaliseProfile = av.isNormaliseSequenceLogo(); - av_renderInformationHistogram = av.isShowInformationHistogram(); - av_renderHMMProfile = av.isShowHMMSequenceLogo(); - av_normaliseHMMProfile = av.isNormaliseHMMSequenceLogo(); profcolour = av.getResidueShading(); if (profcolour == null || profcolour.getColourScheme() == null) { @@ -351,7 +351,7 @@ public class AnnotationRenderer } columnSelection = av.getColumnSelection(); hiddenColumns = av.getAlignment().getHiddenColumns(); - hconsensus = av.getSequenceConsensusHash(); + hconsensus = av.getConsensusProfiles(); complementConsensus = av.getComplementConsensusHash(); hStrucConsensus = av.getRnaStructureConsensusHash(); av_ignoreGapsConsensus = av.isIgnoreGapsConsensus(); @@ -388,13 +388,13 @@ public class AnnotationRenderer .startsWith("cDNA Consensus"))) { boolean forComplement = aa.label.startsWith("cDNA Consensus"); - if (aa.groupRef != null && aa.groupRef.consensusData != null + if (aa.groupRef != null && aa.groupRef.getConsensusData() != null && aa.groupRef.isShowSequenceLogo()) { // TODO? group consensus for cDNA complement return AAFrequency.extractProfile( - aa.groupRef.consensusData.get(column), - aa.groupRef.getIgnoreGapsConsensus()); + aa.groupRef.getConsensusData().get(column), + aa.groupRef.isIgnoreGapsConsensus()); } // TODO extend annotation row to enable dynamic and static profile data to // be stored @@ -529,9 +529,18 @@ public class AnnotationRenderer } else if (InformationThread.HMM_CALC_ID.equals(row.getCalcId())) { - renderHistogram = av_renderInformationHistogram; - renderProfile = av_renderHMMProfile; - normaliseProfile = av_normaliseHMMProfile; + if (row.groupRef != null) + { + renderHistogram = row.groupRef.isShowInformationHistogram(); + renderProfile = row.groupRef.isShowHMMSequenceLogo(); + normaliseProfile = row.groupRef.isNormaliseHMMSequenceLogo(); + } + else + { + renderHistogram = av.isShowInformationHistogram(); + renderProfile = av.isShowHMMSequenceLogo(); + normaliseProfile = av.isNormaliseHMMSequenceLogo(); + } } else { diff --git a/src/jalview/schemes/HMMERAlignmentColourScheme.java b/src/jalview/schemes/HMMERAlignmentColourScheme.java index d5bbe0c..79fc871 100644 --- a/src/jalview/schemes/HMMERAlignmentColourScheme.java +++ b/src/jalview/schemes/HMMERAlignmentColourScheme.java @@ -10,7 +10,6 @@ import jalview.util.Comparison; import java.awt.Color; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -132,15 +131,19 @@ public class HMMERAlignmentColourScheme extends ResidueColourScheme public ColourSchemeI getInstance(AnnotatedCollectionI sg, Map hiddenRepSequences) { - List hmms = sg.getHMMConsensusSequences(); - HiddenMarkovModel model = hmms.isEmpty() ? null : hmms.get(0).getHMM(); + SequenceI hmmSeq = sg.getHmmConsensus(); + HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM(); return new HMMERAlignmentColourScheme(sg, model); } + /** + * Answers true if the sequence collection has an HMM consensus sequence, else + * false + */ @Override public boolean isApplicableTo(AnnotatedCollectionI ac) { - return !ac.getHMMConsensusSequences().isEmpty(); + return ac.getHmmConsensus() != null; } @Override diff --git a/src/jalview/schemes/HMMERColourScheme.java b/src/jalview/schemes/HMMERColourScheme.java index 2ba0898..ee6c873 100644 --- a/src/jalview/schemes/HMMERColourScheme.java +++ b/src/jalview/schemes/HMMERColourScheme.java @@ -8,7 +8,6 @@ import jalview.util.ColorUtils; import jalview.util.Comparison; import java.awt.Color; -import java.util.List; import java.util.Map; /** @@ -139,12 +138,9 @@ public class HMMERColourScheme extends ResidueColourScheme public ColourSchemeI getInstance(AnnotatedCollectionI sg, Map hiddenRepSequences) { - HiddenMarkovModel model = null; - List seqs = sg.getHMMConsensusSequences(); - if (!seqs.isEmpty()) - { - model = seqs.get(0).getHMM(); - } + SequenceI hmmSeq = sg.getHmmConsensus(); + HiddenMarkovModel model = hmmSeq == null ? null : hmmSeq.getHMM(); + HMMERColourScheme colour = new HMMERColourScheme(model); return colour; } @@ -161,10 +157,14 @@ public class HMMERColourScheme extends ResidueColourScheme return false; } + /** + * Answers true if the sequence collection has an HMM consensus sequence, else + * false + */ @Override public boolean isApplicableTo(AnnotatedCollectionI ac) { - return !ac.getHMMConsensusSequences().isEmpty(); + return ac.getHmmConsensus() != null; } } diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index d320ee2..60fd25c 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -2544,7 +2544,8 @@ public class ResidueProperties amino.put('P', 0.0472f); amino.put('V', 0.0686f); backgroundFrequencies.put("amino", amino); - + // todo: these don't match https://www.ebi.ac.uk/uniprot/TrEMBLstats - what + // are they? } // TODO get correct frequencies diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index ecca699..58dba9d 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -37,8 +37,6 @@ import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; -import jalview.datamodel.ProfileI; -import jalview.datamodel.Profiles; import jalview.datamodel.ProfilesI; import jalview.datamodel.SearchResultsI; import jalview.datamodel.Sequence; @@ -113,8 +111,6 @@ public abstract class AlignmentViewport public boolean autoCalculateConsensus = true; - public boolean autoCalculateInformation = true; - protected boolean autoCalculateStrucConsensus = true; protected boolean ignoreGapsInConsensusCalculation = false; @@ -137,8 +133,6 @@ public abstract class AlignmentViewport protected AlignmentAnnotation quality; - protected List information = new ArrayList<>(); - /** * alignment displayed in the viewport */ @@ -147,25 +141,25 @@ public abstract class AlignmentViewport /** * results of alignment consensus analysis for visible portion of view */ - protected ProfilesI hconsensus = null; + protected ProfilesI consensusProfiles; /** - * results of information annotation analysis for the visible portion of view + * HMM profile for the alignment */ - protected List hinformation = new ArrayList<>(); + protected ProfilesI hmmProfiles; /** * results of cDNA complement consensus visible portion of view */ - protected Hashtable[] hcomplementConsensus = null; + protected Hashtable[] hcomplementConsensus; /** * results of secondary structure base pair consensus for visible portion of * view */ - protected Hashtable[] hStrucConsensus = null; + protected Hashtable[] hStrucConsensus; - protected Conservation hconservation = null; + protected Conservation hconservation; public AlignmentViewport(AlignmentI al) { @@ -747,9 +741,9 @@ public abstract class AlignmentViewport } @Override - public void setSequenceConsensusHash(ProfilesI hconsensus) + public void setConsensusProfiles(ProfilesI hconsensus) { - this.hconsensus = hconsensus; + this.consensusProfiles = hconsensus; } @Override @@ -759,37 +753,21 @@ public abstract class AlignmentViewport } @Override - public ProfilesI getSequenceConsensusHash() + public ProfilesI getConsensusProfiles() { - return hconsensus; + return consensusProfiles; } @Override - public void setSequenceInformationHashes(List info) + public void setHmmProfiles(ProfilesI info) { - hinformation = info; - } - - @Override - public void setSequenceInformationHash(ProfilesI info, int index) - { - if (hinformation.size() < index + 1) - { - return; - } - hinformation.set(index, info); + hmmProfiles = info; } @Override - public List getSequenceInformationHashes() + public ProfilesI getHmmProfiles() { - return hinformation; - } - - @Override - public ProfilesI getSequenceInformationHash(int index) - { - return hinformation.get(index); + return hmmProfiles; } @Override @@ -830,13 +808,7 @@ public abstract class AlignmentViewport } @Override - public List getInformationAnnotations() - { - return information; - } - - @Override - public AlignmentAnnotation getAlignmentGapAnnotation() + public AlignmentAnnotation getOccupancyAnnotation() { return occupancy; } @@ -1004,7 +976,7 @@ public abstract class AlignmentViewport strucConsensus = null; conservation = null; quality = null; - hconsensus = null; + consensusProfiles = null; hconservation = null; hcomplementConsensus = null; occupancy = null; @@ -1347,27 +1319,26 @@ public abstract class AlignmentViewport ignoreGapsInConsensusCalculation); } } - } public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap) { + boolean was = ignoreBelowBackGroundFrequencyCalculation; ignoreBelowBackGroundFrequencyCalculation = b; - if (ap != null) + if (ap != null && was != b) { updateInformation(ap); } - } public void setInfoLetterHeight(boolean b, AlignmentViewPanel ap) { + boolean was = infoLetterHeight; infoLetterHeight = b; - if (ap != null) + if (ap != null && was != b) { updateInformation(ap); } - } private long sgrouphash = -1, colselhash = -1; @@ -1995,7 +1966,7 @@ public abstract class AlignmentViewport { updateConsensus(ap); } - if (hconsensus != null && autoCalculateConsensus) + if (consensusProfiles != null && autoCalculateConsensus) { updateConservation(ap); } @@ -2003,17 +1974,9 @@ public abstract class AlignmentViewport { updateStrucConsensus(ap); } - initInformation(); + // initInformation(); updateInformation(ap); - List hmmSequences; - hmmSequences = alignment.getHMMConsensusSequences(); - - for (SequenceI seq : hmmSequences) - { - seq.updateHMMMapping(); - } - // Reset endRes of groups if beyond alignment width int alWidth = alignment.getWidth(); List groups = alignment.getGroups(); @@ -2048,7 +2011,7 @@ public abstract class AlignmentViewport { rs.alignmentChanged(alignment, hiddenRepSequences); - rs.setConsensus(hconsensus); + rs.setConsensus(consensusProfiles); if (rs.conservationApplied()) { rs.setConservation(Conservation.calculateConservation("All", @@ -2073,7 +2036,7 @@ public abstract class AlignmentViewport // depending on if the user wants to see the annotation or not in a // specific alignment - if (hconsensus == null && !isDataset) + if (consensusProfiles == null && !isDataset) { if (!alignment.isNucleotide()) { @@ -2146,30 +2109,6 @@ public abstract class AlignmentViewport } } - @Override - public void initInformation() - { - for (SequenceI seq : alignment.getHMMConsensusSequences()) - { - if (!seq.hasHMMAnnotation()) - { - AlignmentAnnotation info = new AlignmentAnnotation(seq.getName(), - MessageManager.getString("label.information_description"), - new Annotation[1], 0f, 6.52f, - AlignmentAnnotation.BAR_GRAPH); - info.hasText = true; - info.autoCalculated = false; - info.sequenceRef = seq; - info.setCalcId(InformationThread.HMM_CALC_ID); - this.information.add(info); - hinformation.add(new Profiles(new ProfileI[1])); - alignment.addAnnotation(info); - seq.updateHMMMapping(); - seq.addAlignmentAnnotation(info); - } - } - } - // these should be extracted from the view model - style and settings for // derived annotation private void initOccupancy() diff --git a/src/jalview/workers/ConsensusThread.java b/src/jalview/workers/ConsensusThread.java index 335529c..d6a4488 100644 --- a/src/jalview/workers/ConsensusThread.java +++ b/src/jalview/workers/ConsensusThread.java @@ -50,7 +50,7 @@ public class ConsensusThread extends AlignCalcWorker try { AlignmentAnnotation consensus = getConsensusAnnotation(); - AlignmentAnnotation gap = getGapAnnotation(); + AlignmentAnnotation gap = getOccupancyAnnotation(); if ((consensus == null && gap == null) || calcMan.isPending(this)) { calcMan.workerComplete(this); @@ -119,7 +119,7 @@ public class ConsensusThread extends AlignCalcWorker { AlignmentAnnotation consensus = getConsensusAnnotation(); consensus.annotations = new Annotation[aWidth]; - AlignmentAnnotation gap = getGapAnnotation(); + AlignmentAnnotation gap = getOccupancyAnnotation(); if (gap != null) { gap.annotations = new Annotation[aWidth]; @@ -137,7 +137,7 @@ public class ConsensusThread extends AlignCalcWorker ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width, true); - alignViewport.setSequenceConsensusHash(hconsensus); + alignViewport.setConsensusProfiles(hconsensus); setColourSchemeConsensus(hconsensus); } @@ -176,9 +176,9 @@ public class ConsensusThread extends AlignCalcWorker * * @return */ - protected AlignmentAnnotation getGapAnnotation() + protected AlignmentAnnotation getOccupancyAnnotation() { - return alignViewport.getAlignmentGapAnnotation(); + return alignViewport.getOccupancyAnnotation(); } /** @@ -199,10 +199,10 @@ public class ConsensusThread extends AlignCalcWorker && hconsensus != null) { deriveConsensus(consensus, hconsensus); - AlignmentAnnotation gap = getGapAnnotation(); - if (gap != null) + AlignmentAnnotation occupancy = getOccupancyAnnotation(); + if (occupancy != null) { - deriveGap(gap, hconsensus); + deriveOccupancy(occupancy, hconsensus); } } } @@ -219,7 +219,6 @@ public class ConsensusThread extends AlignCalcWorker protected void deriveConsensus(AlignmentAnnotation consensusAnnotation, ProfilesI hconsensus) { - long nseq = getSequences().length; AAFrequency.completeConsensus(consensusAnnotation, hconsensus, hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, @@ -235,11 +234,11 @@ public class ConsensusThread extends AlignCalcWorker * @param hconsensus * the computed consensus data */ - protected void deriveGap(AlignmentAnnotation gapAnnotation, + protected void deriveOccupancy(AlignmentAnnotation gapAnnotation, ProfilesI hconsensus) { long nseq = getSequences().length; - AAFrequency.completeGapAnnot(gapAnnotation, hconsensus, + AAFrequency.completeOccupancyAnnot(gapAnnotation, hconsensus, hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, nseq); } @@ -252,6 +251,6 @@ public class ConsensusThread extends AlignCalcWorker protected Object getViewportConsensus() { // TODO convert ComplementConsensusThread to use Profile - return alignViewport.getSequenceConsensusHash(); + return alignViewport.getConsensusProfiles(); } } diff --git a/src/jalview/workers/InformationThread.java b/src/jalview/workers/InformationThread.java index 09b428b..6a86a61 100644 --- a/src/jalview/workers/InformationThread.java +++ b/src/jalview/workers/InformationThread.java @@ -8,11 +8,19 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.ProfilesI; +import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; +import jalview.util.MessageManager; import java.util.List; +/** + * This class calculates HMM Information Content annotations, based on any HMM + * consensus sequences and their HMM models. HMM consensus sequences may be + * present for the whole alignment, or subgroups of it. + * + */ public class InformationThread extends AlignCalcWorker { public static final String HMM_CALC_ID = "HMM"; @@ -20,7 +28,7 @@ public class InformationThread extends AlignCalcWorker private float max = 0f; /** - * Constructor for information thread. + * Constructor * * @param alignViewport * @param alignPanel @@ -31,6 +39,10 @@ public class InformationThread extends AlignCalcWorker super(alignViewport, alignPanel); } + /** + * Recomputes Information annotations for any HMM consensus sequences (for + * alignment and/or groups) + */ @Override public void run() { @@ -41,18 +53,17 @@ public class InformationThread extends AlignCalcWorker calcMan.notifyStart(this); // long started = System.currentTimeMillis(); - List information = getInformationAnnotations(); try { - if ((information == null) || calcMan.isPending(this)) + if (calcMan.isPending(this)) { + // another instance of this is waiting to run calcMan.workerComplete(this); return; } while (!calcMan.notifyWorking(this)) { - // System.err.println("Thread - // (Information"+Thread.currentThread().getName()+") Waiting around."); + // another thread in progress, wait my turn try { if (ap != null) @@ -72,20 +83,21 @@ public class InformationThread extends AlignCalcWorker } AlignmentI alignment = alignViewport.getAlignment(); - int aWidth = -1; + int aWidth = alignment == null ? -1 : alignment.getWidth(); - if (alignment == null || (aWidth = alignment.getWidth()) < 0) + if (aWidth < 0) { calcMan.workerComplete(this); return; } - eraseInformation(aWidth); - computeInformation(alignment); + eraseAnnotations(alignment); + computeProfiles(alignment); updateResultAnnotation(true); if (ap != null) { + ap.adjustAnnotationHeight(); ap.paintAlignment(true, true); } } catch (OutOfMemoryError error) @@ -99,41 +111,62 @@ public class InformationThread extends AlignCalcWorker } /** - * Clear out any existing information annotations + * Deletes any existing information annotations. These are sequence-related + * annotations which relate to HMM consensus sequences for either the + * alignment or a subgroup. * - * @param aWidth - * the width (number of columns) of the annotated alignment + * @param alignment */ - protected void eraseInformation(int aWidth) + protected void eraseAnnotations(AlignmentI alignment) { - - List information = getInformationAnnotations(); - for (AlignmentAnnotation info : information) + Iterable anns = alignment + .findAnnotation(HMM_CALC_ID); + for (AlignmentAnnotation ann : anns) { - info.annotations = new Annotation[aWidth]; + alignment.deleteAnnotation(ann); } } /** - * Computes the profiles from a HMM for an alignment. + * Computes HMM profiles for any HMM consensus sequences (for alignment or + * subgroups) * * @param alignment */ - protected void computeInformation(AlignmentI alignment) + protected void computeProfiles(AlignmentI alignment) { int width = alignment.getWidth(); - List hmmSeqs = alignment.getHMMConsensusSequences(); - int index = 0; - for (SequenceI seq : hmmSeqs) + /* + * alignment HMM profile + */ + SequenceI seq = alignment.getHmmConsensus(); + if (seq != null) { HiddenMarkovModel hmm = seq.getHMM(); - ProfilesI hinformation = AAFrequency.calculateHMMProfiles(hmm, width, + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, 0, width, true, alignViewport.isIgnoreBelowBackground(), alignViewport.isInfoLetterHeight()); - alignViewport.setSequenceInformationHash(hinformation, index); - // setColourSchemeInformation(hinformation); - index++; + alignViewport.setHmmProfiles(hmmProfiles); + // setColourSchemeInformation(hmmProfiles); + } + + /* + * group HMM profiles + */ + List groups = alignment.getGroups(); + for (SequenceGroup group : groups) + { + seq = group.getHmmConsensus(); + if (seq != null) + { + HiddenMarkovModel hmm = seq.getHMM(); + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, + 0, width, true, group.isIgnoreBelowBackground(), + group.isUseInfoLetterHeight()); + group.setHmmProfiles(hmmProfiles); + // setColourSchemeInformation(hmmProfiles); + } } } @@ -157,28 +190,18 @@ public class InformationThread extends AlignCalcWorker } /** - * Get the Information annotation for the alignment - * - * @return - */ - protected List getInformationAnnotations() - { - return alignViewport.getInformationAnnotations(); - } - - /** * Get the Gap annotation for the alignment * * @return */ protected AlignmentAnnotation getGapAnnotation() { - return alignViewport.getAlignmentGapAnnotation(); + return alignViewport.getOccupancyAnnotation(); } /** - * update the information annotation from the sequence profile data using - * current visualization settings. + * Updates the information annotation from the sequence profile data using + * current visualisation settings */ @Override public void updateAnnotation() @@ -187,27 +210,79 @@ public class InformationThread extends AlignCalcWorker } /** - * Derives the information content for an information annotation. + * Constructs Information Content annotation for any HMM consensus sequences + * (for alignment or groups), and adds the annotation to the sequence and the + * alignment * * @param immediate */ public void updateResultAnnotation(boolean immediate) { - List annots = getInformationAnnotations(); - int index = 0; - for (AlignmentAnnotation information : annots) + AlignmentI alignment = alignViewport.getAlignment(); + + /* + * annotation for alignment HMM consensus if present + */ + SequenceI hmmSeq = alignment.getHmmConsensus(); + ProfilesI profile = alignViewport.getHmmProfiles(); + AlignmentAnnotation ann = makeInformationAnnotation(hmmSeq, profile); + if (ann != null) + { + alignment.addAnnotation(ann); + } + + /* + * annotation for group HMM consensus if present + */ + for (SequenceGroup group : alignment.getGroups()) { - ProfilesI hinformation = getSequenceInformation(index); - if (immediate || !calcMan.isWorking(this) && information != null - && hinformation != null) + hmmSeq = group.getHmmConsensus(); + ProfilesI profiles = group.getHmmProfiles(); + ann = makeInformationAnnotation(hmmSeq, profiles); + if (ann != null) { - deriveInformation(information, hinformation); + ann.groupRef = group; + alignment.addAnnotation(ann); } - index++; } } /** + * Constructs an HMM Profile information content annotation for a sequence + * + * @param seq + * @param profile + * @return + */ + protected AlignmentAnnotation makeInformationAnnotation(SequenceI seq, + ProfilesI profile) + { + if (seq == null || profile == null) + { + return null; + } + + AlignmentI alignment = alignViewport.getAlignment(); + int aWidth = alignment == null ? 0 : alignment.getWidth(); + AlignmentAnnotation ann = new AlignmentAnnotation(seq.getName(), + MessageManager.getString("label.information_description"), + new Annotation[aWidth], 0f, 6.52f, + AlignmentAnnotation.BAR_GRAPH); + ann.hasText = true; + ann.autoCalculated = false; + ann.sequenceRef = seq; + ann.setCalcId(InformationThread.HMM_CALC_ID); + seq.addAlignmentAnnotation(ann); + + long nseq = getSequences().length; + max = AAFrequency.completeInformation(ann, profile, + profile.getStartColumn(), profile.getEndColumn() + 1, nseq, + max); + + return ann; + } + + /** * Convert the computed information data into the desired annotation for * display. * @@ -224,14 +299,4 @@ public class InformationThread extends AlignCalcWorker hinformation, hinformation.getStartColumn(), hinformation.getEndColumn() + 1, nseq, max); } - - /** - * Get the information data stored on the viewport. - * - * @return - */ - protected ProfilesI getSequenceInformation(int index) - { - return alignViewport.getSequenceInformationHash(index); - } } diff --git a/test/jalview/datamodel/SequenceGroupTest.java b/test/jalview/datamodel/SequenceGroupTest.java index b0af5c8..df88268 100644 --- a/test/jalview/datamodel/SequenceGroupTest.java +++ b/test/jalview/datamodel/SequenceGroupTest.java @@ -16,10 +16,10 @@ import jalview.schemes.PIDColourScheme; import java.awt.Color; import java.util.Collections; -import junit.extensions.PA; - import org.testng.annotations.Test; +import junit.extensions.PA; + public class SequenceGroupTest { @Test(groups={"Functional"}) @@ -242,7 +242,7 @@ public class SequenceGroupTest sg.setDisplayBoxes(false); sg.setDisplayText(false); sg.setColourText(true); - sg.isDefined = true; + PA.setValue(sg, "isDefined", true); sg.setShowNonconserved(true); sg.setOutlineColour(Color.red); sg.setIdColour(Color.blue); @@ -275,7 +275,7 @@ public class SequenceGroupTest assertEquals(sg2.thresholdTextColour, sg.thresholdTextColour); assertEquals(sg2.textColour, sg.textColour); assertEquals(sg2.textColour2, sg.textColour2); - assertEquals(sg2.getIgnoreGapsConsensus(), sg.getIgnoreGapsConsensus()); + assertEquals(sg2.isIgnoreGapsConsensus(), sg.isIgnoreGapsConsensus()); assertEquals(sg2.isShowSequenceLogo(), sg.isShowSequenceLogo()); assertEquals(sg2.isNormaliseSequenceLogo(), sg.isNormaliseSequenceLogo()); diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java index 5ed0cac..f0120d6 100644 --- a/test/jalview/gui/AlignViewportTest.java +++ b/test/jalview/gui/AlignViewportTest.java @@ -385,7 +385,7 @@ public class AlignViewportTest AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); AlignViewport av = af.getViewport(); - Assert.assertNull(av.getAlignmentGapAnnotation(), "Preference did not disable occupancy row."); + Assert.assertNull(av.getOccupancyAnnotation(), "Preference did not disable occupancy row."); int c = 0; for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null, null, "Occupancy")) @@ -399,10 +399,10 @@ public class AlignViewportTest af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); av = af.getViewport(); - Assert.assertNotNull(av.getAlignmentGapAnnotation(), "Preference did not enable occupancy row."); + Assert.assertNotNull(av.getOccupancyAnnotation(), "Preference did not enable occupancy row."); c = 0; for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null, - null, av.getAlignmentGapAnnotation().label)) + null, av.getOccupancyAnnotation().label)) { c++; } diff --git a/test/jalview/hmmer/HMMERTest.java b/test/jalview/hmmer/HMMERTest.java index 4720dc2..7c8d637 100644 --- a/test/jalview/hmmer/HMMERTest.java +++ b/test/jalview/hmmer/HMMERTest.java @@ -60,11 +60,12 @@ public class HMMERTest { throws MalformedURLException, IOException { /* - * run hmmbuild - not the side-effect of selecting the HMM + * run hmmbuild - note the side-effect of selecting the HMM * sequence that gets added to the alignment */ testHMMBuild(); HiddenMarkovModel hmm = frame.getSelectedHMM(); + assertNotNull(hmm); /* * now run hmmalign - with respect to the select HMM profile @@ -74,9 +75,9 @@ public class HMMERTest { public void testHMMBuild() { - HMMBuildThread thread = new HMMBuildThread(frame, + HMMBuild builder = new HMMBuild(frame, new ArrayList()); - thread.hmmbuildWaitTillComplete(); + builder.run(); SequenceI seq = frame.getViewport().getAlignment().getSequenceAt(0); HiddenMarkovModel hmm = seq.getHMM(); @@ -84,7 +85,7 @@ public class HMMERTest { assertEquals(hmm.getLength(), 148); assertEquals(hmm.getAlphabetType(), "amino"); - assertEquals(hmm.getName(), "Alignment"); + assertEquals(hmm.getName(), "Alignment_HMM"); assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), "0.648193"); assertEquals(hmm.getConsensusAtAlignColumn(15), 's'); @@ -92,9 +93,9 @@ public class HMMERTest { public void testHMMAlign() { - HMMAlignThread thread = new HMMAlignThread(frame, + HMMAlign thread = new HMMAlign(frame, new ArrayList()); - thread.hmmalignWaitTillComplete(); + thread.run(); AlignFrame[] alignFrames = Desktop.getAlignFrames(); if (alignFrames == null) @@ -110,8 +111,8 @@ public class HMMERTest { assertNotNull(original); AlignmentI realigned = alignFrames[1].getViewport().getAlignment(); assertNotNull(realigned); - assertNotNull(original.getHMMConsensusSequences()); - assertNotNull(realigned.getHMMConsensusSequences()); + assertNotNull(original.getHmmConsensus()); + assertNotNull(realigned.getHmmConsensus()); SequenceI ferCapan = original.findName("FER_CAPAN"); assertTrue(ferCapan.getSequenceAsString().startsWith("MA------SVSAT")); diff --git a/test/jalview/io/JSONFileTest.java b/test/jalview/io/JSONFileTest.java index 158c901..dd21bea 100644 --- a/test/jalview/io/JSONFileTest.java +++ b/test/jalview/io/JSONFileTest.java @@ -492,8 +492,8 @@ public class JSONFileTest + actualGrp.getColourText()); System.out.println(expectedGrp.getDisplayBoxes() + " | " + actualGrp.getDisplayBoxes()); - System.out.println(expectedGrp.getIgnoreGapsConsensus() + " | " - + actualGrp.getIgnoreGapsConsensus()); + System.out.println(expectedGrp.isIgnoreGapsConsensus() + " | " + + actualGrp.isIgnoreGapsConsensus()); System.out.println(expectedGrp.getSequences().size() + " | " + actualGrp.getSequences().size()); System.out.println(expectedGrp.getStartRes() + " | " @@ -510,8 +510,8 @@ public class JSONFileTest if (expectedGrp.getName().equals(actualGrp.getName()) && expectedGrp.getColourText() == actualGrp.getColourText() && expectedGrp.getDisplayBoxes() == actualGrp.getDisplayBoxes() - && expectedGrp.getIgnoreGapsConsensus() == actualGrp - .getIgnoreGapsConsensus() + && expectedGrp.isIgnoreGapsConsensus() == actualGrp + .isIgnoreGapsConsensus() && colourSchemeMatches && expectedGrp.getSequences().size() == actualGrp .getSequences().size()