X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FAlignment.java;h=5232f8e4370609161f49d1d83e1b5e849e64a1f4;hb=45d7b8f24253fa1c49977feedfe8a0f2f7cea85e;hp=40e3230ab1a8a4888463310d17cab588cadbd2b4;hpb=cef7be0f9008ff15318e3479a5de35e127071ef3;p=jalview.git diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 40e3230..5232f8e 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -28,10 +28,13 @@ import jalview.util.LinkedIdentityHashSet; import jalview.util.MessageManager; import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -44,11 +47,11 @@ import java.util.Vector; * @author JimP * */ -public class Alignment implements AlignmentI +public class Alignment implements AlignmentI, AutoCloseable { private Alignment dataset; - protected List sequences; + private List sequences; protected List groups; @@ -192,11 +195,13 @@ public class Alignment implements AlignmentI { synchronized (sequences) { + if (i > -1 && i < sequences.size()) { return sequences.get(i); } } + return null; } @@ -324,15 +329,20 @@ public class Alignment implements AlignmentI } @Override - public void finalize() throws Throwable + public void close() { if (getDataset() != null) { - getDataset().removeAlignmentRef(); + try + { + getDataset().removeAlignmentRef(); + } catch (Throwable e) + { + e.printStackTrace(); + } } nullReferences(); - super.finalize(); } /** @@ -607,15 +617,17 @@ public class Alignment implements AlignmentI @Override public SequenceI findName(SequenceI startAfter, String token, boolean b) { - + if (token == null) + return null; int i = 0; SequenceI sq = null; String sqname = null; + int nseq = sequences.size(); if (startAfter != null) { // try to find the sequence in the alignment boolean matched = false; - while (i < sequences.size()) + while (i < nseq) { if (getSequenceAt(i++) == startAfter) { @@ -628,7 +640,7 @@ public class Alignment implements AlignmentI i = 0; } } - while (i < sequences.size()) + while (i < nseq) { sq = getSequenceAt(i); sqname = sq.getName(); @@ -734,15 +746,22 @@ public class Alignment implements AlignmentI for (int i = 0; i < sequences.size(); i++) { - if (getSequenceAt(i).getLength() > maxLength) - { - maxLength = getSequenceAt(i).getLength(); - } + maxLength = Math.max(maxLength, getSequenceAt(i).getLength()); } - return maxLength; } + @Override + public int getVisibleWidth() + { + int w = getWidth(); + if (hiddenCols != null) + { + w -= hiddenCols.getSize(); + } + return w; + } + /** * DOCUMENT ME! * @@ -1203,7 +1222,8 @@ public class Alignment implements AlignmentI int maxLength = -1; SequenceI current; - for (int i = 0; i < sequences.size(); i++) + int nseq = sequences.size(); + for (int i = 0; i < nseq; i++) { current = getSequenceAt(i); for (int j = current.getLength(); j > maxLength; j--) @@ -1220,7 +1240,7 @@ public class Alignment implements AlignmentI maxLength++; int cLength; - for (int i = 0; i < sequences.size(); i++) + for (int i = 0; i < nseq; i++) { current = getSequenceAt(i); cLength = current.getLength(); @@ -1497,8 +1517,8 @@ public class Alignment implements AlignmentI { // TODO JAL-1270 needs test coverage // currently tested for use in jalview.gui.SequenceFetcher - boolean samegap = toappend.getGapCharacter() == getGapCharacter(); char oldc = toappend.getGapCharacter(); + boolean samegap = oldc == getGapCharacter(); boolean hashidden = toappend.getHiddenSequences() != null && toappend.getHiddenSequences().hiddenSequences != null; // get all sequences including any hidden ones @@ -1516,14 +1536,7 @@ public class Alignment implements AlignmentI { if (!samegap) { - char[] oldseq = addedsq.getSequence(); - for (int c = 0; c < oldseq.length; c++) - { - if (oldseq[c] == oldc) - { - oldseq[c] = gapCharacter; - } - } + addedsq.replace(oldc, gapCharacter); } toappendsq.add(addedsq); } @@ -1619,71 +1632,71 @@ public class Alignment implements AlignmentI String calcId, boolean autoCalc, SequenceI seqRef, SequenceGroup groupRef) { - if (annotations != null) + AlignmentAnnotation annot = annotations == null ? null + : AlignmentAnnotation.findFirstAnnotation( + Arrays.asList(getAlignmentAnnotation()), name, calcId, + autoCalc, seqRef, groupRef); + + if (annot == null) { - for (AlignmentAnnotation annot : getAlignmentAnnotation()) + + annot = new AlignmentAnnotation(name, name, new Annotation[1], 0f, 0f, + AlignmentAnnotation.BAR_GRAPH); + annot.hasText = false; + if (calcId != null) { - if (annot.autoCalculated == autoCalc && (name.equals(annot.label)) - && (calcId == null || annot.getCalcId().equals(calcId)) - && annot.sequenceRef == seqRef - && annot.groupRef == groupRef) - { - return annot; - } + annot.setCalcId(calcId); } + annot.autoCalculated = autoCalc; + if (seqRef != null) + { + annot.setSequenceRef(seqRef); + } + annot.groupRef = groupRef; + addAnnotation(annot); + } + return annot; + } + + + @Override + public AlignmentAnnotation updateFromOrCopyAnnotation( + AlignmentAnnotation ala) + { + AlignmentAnnotation annot = AlignmentAnnotation.findFirstAnnotation( + Arrays.asList(getAlignmentAnnotation()), ala.label, ala.calcId, + ala.autoCalculated, ala.sequenceRef, ala.groupRef); + if (annot == null) + { + annot = new AlignmentAnnotation(ala); + addAnnotation(annot); } - AlignmentAnnotation annot = new AlignmentAnnotation(name, name, - new Annotation[1], 0f, 0f, AlignmentAnnotation.BAR_GRAPH); - annot.hasText = false; - annot.setCalcId(new String(calcId)); - annot.autoCalculated = autoCalc; - if (seqRef != null) + else { - annot.setSequenceRef(seqRef); + annot.updateAlignmentAnnotationFrom(ala); } - annot.groupRef = groupRef; - addAnnotation(annot); - + validateAnnotation(annot); return annot; } @Override public Iterable findAnnotation(String calcId) { - List aa = new ArrayList<>(); AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation(); if (alignmentAnnotation != null) { - for (AlignmentAnnotation a : alignmentAnnotation) - { - if (a.getCalcId() == calcId || (a.getCalcId() != null - && calcId != null && a.getCalcId().equals(calcId))) - { - aa.add(a); - } - } + return AlignmentAnnotation.findAnnotation( + Arrays.asList(getAlignmentAnnotation()), calcId); } - return aa; + return Arrays.asList(new AlignmentAnnotation[] {}); } @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); } @Override @@ -1942,51 +1955,138 @@ public class Alignment implements AlignmentI } @Override - public void setHiddenColumns(HiddenColumns cols) + public boolean setHiddenColumns(HiddenColumns cols) { + boolean changed = cols == null ? hiddenCols != null + : !cols.equals(hiddenCols); hiddenCols = cols; + return changed; + } + + @Override + public void setupJPredAlignment() + { + SequenceI repseq = getSequenceAt(0); + setSeqrep(repseq); + HiddenColumns cs = new HiddenColumns(); + cs.hideList(repseq.getInsertions()); + setHiddenColumns(cs); + } + + @Override + public HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentView input) + { + int profsqpos = 0; + + char gc = getGapCharacter(); + Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); + HiddenColumns nview = (HiddenColumns) alandhidden[1]; + SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; + return propagateInsertions(profileseq, origseq, nview); } /** - * Returns all HMM consensus sequences. This will not return real sequences - * with HMMs. If remove is set to true, the consensus sequences will be - * removed from the alignment. + * + * @param profileseq + * sequence in al which corresponds to origseq + * @param al + * alignment which is to have gaps inserted into it + * @param origseq + * sequence corresponding to profileseq which defines gap map for + * modifying al */ - @Override // TODO make this more efficient. - public List getHMMConsensusSequences(boolean remove) + private HiddenColumns propagateInsertions(SequenceI profileseq, + SequenceI origseq, HiddenColumns hc) { - List seqs = new ArrayList<>(); - int position = 0; - int seqsRemoved = 0; - boolean endReached = false; + // take the set of hidden columns, and the set of gaps in origseq, + // and remove all the hidden gaps from hiddenColumns + + // first get the gaps as a Bitset + // then calculate hidden ^ not(gap) + BitSet gaps = origseq.gapBitset(); + hc.andNot(gaps); + + // for each sequence in the alignment, except the profile sequence, + // insert gaps corresponding to each hidden region but where each hidden + // column region is shifted backwards by the number of preceding visible + // gaps update hidden columns at the same time + HiddenColumns newhidden = new HiddenColumns(); - while (!endReached) + int numGapsBefore = 0; + int gapPosition = 0; + Iterator it = hc.iterator(); + while (it.hasNext()) { - SequenceI seq = sequences.get(position); - if (seq.isHMMConsensusSequence()) + int[] region = it.next(); + + // get region coordinates accounting for gaps + // we can rely on gaps not being *in* hidden regions because we already + // removed those + while (gapPosition < region[0]) { - if (remove) + gapPosition++; + if (gaps.get(gapPosition)) { - sequences.remove(position); - seqsRemoved++; - seq.setPreviousPosition(seqsRemoved + position - 1); + numGapsBefore++; } - else - { - position++; - } - seqs.add(seq); } - else + + int left = region[0] - numGapsBefore; + int right = region[1] - numGapsBefore; + + newhidden.hideColumns(left, right); + padGaps(left, right, profileseq); + } + return newhidden; + } + + /** + * Pad gaps in all sequences in alignment except profileseq + * + * @param left + * position of first gap to insert + * @param right + * position of last gap to insert + * @param profileseq + * sequence not to pad + */ + private void padGaps(int left, int right, SequenceI profileseq) + { + char gc = getGapCharacter(); + + // make a string with number of gaps = length of hidden region + StringBuilder sb = new StringBuilder(); + for (int g = 0; g < right - left + 1; g++) + { + sb.append(gc); + } + + // loop over the sequences and pad with gaps where required + for (int s = 0, ns = getHeight(); s < ns; s++) + { + SequenceI sqobj = getSequenceAt(s); + if ((sqobj != profileseq) && (sqobj.getLength() >= left)) { - position++; + String sq = sqobj.getSequenceAsString(); + sqobj.setSequence( + sq.substring(0, left) + sb.toString() + sq.substring(left)); } + } + } - if (position >= sequences.size()) + @Override + public List getHmmSequences() + { + List result = new ArrayList<>(); + for (int i = 0; i < sequences.size(); i++) + { + SequenceI seq = sequences.get(i); + if (seq.hasHMMProfile()) { - endReached = true; + result.add(seq); } } - return seqs; + return result; } }