X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FSequenceGroup.java;h=cffe0d9208fe0ce0382069e98850a97f6c7e9033;hb=1903e771d3dae79e9a57fcc1147efd37e8a51421;hp=7d124da748047a4ba209bcec364c40dc002fc098;hpb=6ebc0175847b996abb1fa594492a5c9d23230276;p=jalview.git diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 7d124da..cffe0d9 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -26,9 +26,13 @@ import jalview.renderer.ResidueShader; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; import jalview.util.MessageManager; +import jalview.workers.InformationThread; import java.awt.Color; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -40,107 +44,116 @@ import java.util.Map; */ public class SequenceGroup implements AnnotatedCollectionI { - String groupName; + // TODO ideally this event notification functionality should be separated into + // 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"; - String description; + private String groupName; - Conservation conserve; + private String description; - boolean displayBoxes = true; + private AnnotatedCollectionI context; - boolean displayText = true; + private Conservation conservationData; - boolean colourText = false; + private ProfilesI consensusProfiles; - /** - * True if the group is defined as a group on the alignment, false if it is - * just a selection. + private ProfilesI hmmProfiles; + + private boolean displayBoxes = true; + + private boolean displayText = true; + + private boolean colourText = false; + + /* + * 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; + private int width = -1; - /** - * Colourscheme applied to group if any + /* + * 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; - - /** - * consensus calculation property - */ - private boolean showSequenceLogo = false; + private boolean showSequenceLogo; - /** - * flag indicating if logo should be rendered normalised - */ private boolean normaliseSequenceLogo; - /* - * visibility of rows or represented rows covered by group - */ - private boolean hidereps = false; + private boolean showConsensusHistogram; /* - * visibility of columns intersecting this group + * properties for HMM information annotation */ - private boolean hidecols = false; + private boolean hmmIgnoreBelowBackground = true; - AlignmentAnnotation consensus = null; + private boolean hmmUseInfoLetterHeight; - AlignmentAnnotation conservation = null; + private boolean hmmShowSequenceLogo; - AlignmentAnnotation information = null; + private boolean hmmNormaliseSequenceLogo; - private boolean showConsensusHistogram; + private boolean hmmShowHistogram; - private AnnotatedCollectionI context; + /* + * visibility of rows or represented rows covered by group + */ + private boolean hidereps; + + /* + * visibility of columns intersecting this group + */ + 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() { @@ -185,11 +198,27 @@ public class SequenceGroup implements AnnotatedCollectionI */ public SequenceGroup(SequenceGroup seqsel) { + this(seqsel, true); + } + + /** + * copy constructor + * + * @param seqsel + * @param keepsequences + * if false do not add sequences from seqsel to new instance + */ + public SequenceGroup(SequenceGroup seqsel, boolean keepsequences) + { this(); + if (seqsel != null) { sequences = new ArrayList<>(); - sequences.addAll(seqsel.sequences); + if (keepsequences) + { + sequences.addAll(seqsel.sequences); + } if (seqsel.groupName != null) { groupName = new String(seqsel.groupName); @@ -210,9 +239,9 @@ public class SequenceGroup implements AnnotatedCollectionI showSequenceLogo = seqsel.showSequenceLogo; normaliseSequenceLogo = seqsel.normaliseSequenceLogo; showConsensusHistogram = seqsel.showConsensusHistogram; - showHMMSequenceLogo = seqsel.showHMMSequenceLogo; - normaliseHMMSequenceLogo = seqsel.normaliseHMMSequenceLogo; - showInformationHistogram = seqsel.showInformationHistogram; + hmmShowSequenceLogo = seqsel.hmmShowSequenceLogo; + hmmNormaliseSequenceLogo = seqsel.hmmNormaliseSequenceLogo; + hmmShowHistogram = seqsel.hmmShowHistogram; idColour = seqsel.idColour; outlineColour = seqsel.outlineColour; seqrep = seqsel.seqrep; @@ -221,21 +250,38 @@ public class SequenceGroup implements AnnotatedCollectionI thresholdTextColour = seqsel.thresholdTextColour; width = seqsel.width; ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus; - ignoreBelowBackground = seqsel.ignoreBelowBackground; - if (seqsel.conserve != null) + hmmIgnoreBelowBackground = seqsel.hmmIgnoreBelowBackground; + hmmUseInfoLetterHeight = seqsel.hmmUseInfoLetterHeight; + if (keepsequences && seqsel.conservationData != null) { + // todo avoid doing this if we don't actually want derived calculations + // ! recalcConservation(); // safer than // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ?? } } } + 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; } - public SequenceI[] getSelectionAsNewSequences(AlignmentI align) + public SequenceI[] getSelectionAsNewSequences(AlignmentI align, + boolean copyAnnotation) { int iSize = sequences.size(); SequenceI[] seqs = new SequenceI[iSize]; @@ -249,14 +295,8 @@ public class SequenceGroup implements AnnotatedCollectionI if (seqs[ipos] != null) { seqs[ipos].setDescription(seq.getDescription()); - seqs[ipos].setDBRefs(seq.getDBRefs()); - seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures()); - if (seq.getDatasetSequence() != null) - { - seqs[ipos].setDatasetSequence(seq.getDatasetSequence()); - } - if (seq.getAnnotation() != null) + if (seq.getAnnotation() != null && copyAnnotation) { AlignmentAnnotation[] alann = align.getAlignmentAnnotation(); // Only copy annotation that is either a score or referenced by the @@ -480,7 +520,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public Conservation getConservation() { - return conserve; + return conservationData; } /** @@ -491,7 +531,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public void setConservation(Conservation c) { - conserve = c; + conservationData = c; } /** @@ -511,6 +551,8 @@ public class SequenceGroup implements AnnotatedCollectionI if (s != null && !sequences.contains(s)) { sequences.add(s); + changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, + sequences.size() - 1, sequences.size()); } if (recalc) @@ -550,21 +592,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; } @@ -575,14 +618,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); - _updateInformationRow(info, sequences.size()); + hmmIgnoreBelowBackground, hmmUseInfoLetterHeight); + _updateInformationRow(info); upd = true; } if (consensus != null) @@ -657,10 +700,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) @@ -669,7 +708,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 @@ -687,35 +726,30 @@ public class SequenceGroup implements AnnotatedCollectionI } /** - * Recalculates the information content on the HMM annotation. + * Recalculates the information content on the HMM annotation * * @param cnsns - * @param nseq */ - private void _updateInformationRow(ProfilesI cnsns, long nseq) + private void _updateInformationRow(ProfilesI cnsns) { - 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.calcId = "HMM"; - AAFrequency.completeInformation(information, cnsns, startRes, - endRes + 1, ignoreBelowBackground, showSequenceLogo, nseq); // TODO: - // setting - // container - // for - // ignoreGapsInInformationCalculation); + hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); + AAFrequency.completeInformation(hmmInformation, cnsns, startRes, + endRes + 1); } /** @@ -753,6 +787,8 @@ public class SequenceGroup implements AnnotatedCollectionI synchronized (sequences) { sequences.remove(s); + changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, + sequences.size() + 1, sequences.size()); if (recalc) { @@ -789,7 +825,9 @@ public class SequenceGroup implements AnnotatedCollectionI */ public void setStartRes(int i) { + int before = startRes; startRes = i; + changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes); } /** @@ -799,7 +837,9 @@ public class SequenceGroup implements AnnotatedCollectionI */ public void setEndRes(int i) { + int before = endRes; endRes = i; + changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, endRes); } /** @@ -1166,32 +1206,19 @@ public class SequenceGroup implements AnnotatedCollectionI } /** - * - * @return information content annotation. + * Creates the Hidden Markov Model annotation for this group */ - public AlignmentAnnotation getInformation() + void createInformationAnnotation() { - // TODO get or calculate and get information annotation row for this group - int aWidth = this.getWidth(); - // pointer - // possibility - // here. - if (aWidth < 0) - { - return null; - } - 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() + "_HMM"; - information.description = "Information content, measured in bits"; - information.calcId = "HMM"; - } - 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); } /** @@ -1247,9 +1274,10 @@ public class SequenceGroup implements AnnotatedCollectionI { if (consensus.annotations[i] != null) { - if (consensus.annotations[i].description.charAt(0) == '[') + String desc = consensus.annotations[i].description; + if (desc.length() > 1 && desc.charAt(0) == '[') { - seqs.append(consensus.annotations[i].description.charAt(1)); + seqs.append(desc.charAt(1)); } else { @@ -1275,23 +1303,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 true; + return hmmIgnoreBelowBackground; + } + + public void setInfoLetterHeight(boolean state) + { + hmmUseInfoLetterHeight = state; + } + + public boolean isUseInfoLetterHeight() + { + return hmmUseInfoLetterHeight; } /** @@ -1389,39 +1423,16 @@ public class SequenceGroup implements AnnotatedCollectionI @Override public Iterable findAnnotation(String calcId) { - List aa = new ArrayList<>(); - if (calcId == null) - { - return aa; - } - for (AlignmentAnnotation a : getAlignmentAnnotation()) - { - if (calcId.equals(a.getCalcId())) - { - aa.add(a); - } - } - return aa; + return AlignmentAnnotation.findAnnotation( + Arrays.asList(getAlignmentAnnotation()), calcId); } @Override public Iterable findAnnotations(SequenceI seq, String calcId, String label) { - ArrayList aa = new ArrayList<>(); - for (AlignmentAnnotation ann : getAlignmentAnnotation()) - { - if ((calcId == null || (ann.getCalcId() != null - && ann.getCalcId().equals(calcId))) - && (seq == null || (ann.sequenceRef != null - && ann.sequenceRef == seq)) - && (label == null - || (ann.label != null && ann.label.equals(label)))) - { - aa.add(ann); - } - } - return aa; + return AlignmentAnnotation.findAnnotations( + Arrays.asList(getAlignmentAnnotation()), seq, calcId, label); } /** @@ -1432,17 +1443,8 @@ public class SequenceGroup implements AnnotatedCollectionI */ public boolean hasAnnotation(String calcId) { - if (calcId != null && !"".equals(calcId)) - { - for (AlignmentAnnotation a : getAlignmentAnnotation()) - { - if (a.getCalcId() == calcId) - { - return true; - } - } - } - return false; + return AlignmentAnnotation + .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId); } /** @@ -1452,7 +1454,10 @@ public class SequenceGroup implements AnnotatedCollectionI { synchronized (sequences) { + int before = sequences.size(); sequences.clear(); + changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, + sequences.size()); } } @@ -1569,41 +1574,67 @@ 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; } public boolean isShowHMMSequenceLogo() { - // TODO Auto-generated method stub - return showHMMSequenceLogo; + return hmmShowSequenceLogo; } - public void setshowHMMSequenceLogo(boolean state) + public void setShowHMMSequenceLogo(boolean state) { - showHMMSequenceLogo = state; - + hmmShowSequenceLogo = state; } public boolean isNormaliseHMMSequenceLogo() { - // TODO Auto-generated method stub - return normaliseHMMSequenceLogo; + return hmmNormaliseSequenceLogo; } public void setNormaliseHMMSequenceLogo(boolean state) { - normaliseSequenceLogo = state; + hmmNormaliseSequenceLogo = state; + } + + public ProfilesI getConsensusData() + { + return consensusProfiles; + } + + public ProfilesI getHmmProfiles() + { + return hmmProfiles; + } + + public void setHmmProfiles(ProfilesI hmmProfiles) + { + this.hmmProfiles = hmmProfiles; + } + + @Override + public List getHmmSequences() + { + List result = new ArrayList<>(); + for (int i = 0; i < sequences.size(); i++) + { + SequenceI seq = sequences.get(i); + if (seq.hasHMMProfile()) + { + result.add(seq); + } + } + return result; } }