X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2Fdatamodel%2Falphafold%2FMappableContactMatrix.java;fp=src%2Fjalview%2Fws%2Fdatamodel%2Falphafold%2FMappableContactMatrix.java;h=ae2b37cec8ad42a648e5713e49f39acfae830f7a;hb=f3d6a13271e3f34dfb4e40d6a2a7df1d392f8014;hp=0000000000000000000000000000000000000000;hpb=108f2d4b40f172ad6a34647133dbb18dfab150f7;p=jalview.git diff --git a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java new file mode 100644 index 0000000..ae2b37c --- /dev/null +++ b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java @@ -0,0 +1,318 @@ +package jalview.ws.datamodel.alphafold; + +import java.util.ArrayList; + +import jalview.datamodel.ContactListI; +import jalview.datamodel.ContactListImpl; +import jalview.datamodel.ContactListProviderI; +import jalview.datamodel.Mapping; +import jalview.datamodel.SequenceI; +import jalview.util.MapList; +import jalview.ws.datamodel.MappableContactMatrixI; + +public abstract class MappableContactMatrix> implements MappableContactMatrixI +{ + SequenceI refSeq = null; + MapList toSeq = null; + + /** + * the length that refSeq is expected to be (excluding gaps, of course) + */ + int length; + + + @Override + public boolean hasReferenceSeq() + { + return (refSeq != null); + } + + @Override + public SequenceI getReferenceSeq() + { + return refSeq; + } + @Override + public MapList getMapFor(SequenceI mapSeq) + { + if (refSeq!=null) + { + while (mapSeq!=refSeq && mapSeq.getDatasetSequence()!=null) + { + mapSeq = mapSeq.getDatasetSequence(); + } + if (mapSeq!=refSeq) + { + return null; + } + } else { + if (mapSeq!=null) { + // our MapList does not concern this seq + return null; + } + } + + return toSeq; + } + + protected void setRefSeq(SequenceI _refSeq) + { + refSeq = _refSeq; + while (refSeq.getDatasetSequence() != null) + { + refSeq = refSeq.getDatasetSequence(); + } + length = _refSeq.getEnd() - _refSeq.getStart() + 1; +// if (length!=refSeq.getLength() || _refSeq.getStart()!=1) + { + toSeq = new MapList(new int[] { _refSeq.getStart(), _refSeq.getEnd()}, new int[] { 0,length-1}, 1,1); + } + } + + public T liftOver(SequenceI newRefSeq, Mapping sp2sq) + { + if (sp2sq.getMappedWidth() != sp2sq.getWidth()) + { + // TODO: employ getWord/MappedWord to transfer annotation between cDNA and + // Protein reference frames + throw new Error( + "liftOver currently not implemented for transfer of annotation between different types of seqeunce"); + } + boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false; + + /** + * map from matrix to toSeq's coordinate frame + */ + int[] refMap = toSeq.locateInFrom(0, length - 1); + ArrayList newFromMap = new ArrayList(); + int last = -1; + for (int i = 0; i < refMap.length; i += 2) + { + /* + * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq + */ + int[] sp2map = mapIsTo + ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1]) + : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]); + if (sp2map == null) + { + continue; + } + + for (int spm = 0; spm < sp2map.length; spm += 2) + { + + if (last > -1) + { + if (sp2map[spm] != last + 1) + { + newFromMap.add(sp2map[spm]); + } + else + { + newFromMap.remove(newFromMap.size() - 1); + } + } + else + { + newFromMap.add(sp2map[spm]); + } + last = sp2map[spm + 1]; + newFromMap.add(last); + } + } + if ((newFromMap.size() % 2) != 0) + { + // should have had an even number of int ranges! + throw new Error("PAEMatrix liftover failed."); + } + int fromIntMap[] = new int[newFromMap.size()]; + int ipos = 0; + for (Integer i : newFromMap) + { + fromIntMap[ipos++] = i; + } + MapList newFromMapList = new MapList(fromIntMap, + new int[] + { 0, length - 1 }, 1, 1); + + T newCM = newMappableContactMatrix(newRefSeq, newFromMapList); + return newCM; + } + + protected abstract T newMappableContactMatrix(SequenceI newRefSeq, + MapList newFromMapList); + @Override + public ContactListI getMappableContactList(final SequenceI localFrame, + final int column) + { + final int _column; + final int _lcolumn; + if (localFrame==null) + { + throw new Error("Unimplemented when no local sequence given."); + } + // return a ContactListI for column + // column is index into localFrame + // 1. map column to corresponding column in matrix + + _lcolumn=localFrame.findPosition(column); + + if (toSeq != null) + { + SequenceI lf = localFrame, uf = refSeq; + + // just look for dataset sequences and check they are the same. + // in future we could use DBRefMappings/whatever. + while (lf.getDatasetSequence() != null + || uf.getDatasetSequence() != null) + { + if (lf.getDatasetSequence() != null) + { + lf = lf.getDatasetSequence(); + } + if (uf.getDatasetSequence() != null) + { + uf = uf.getDatasetSequence(); + } + } + if (lf != uf) + { + // could try harder to find a mapping + throw new Error("This Matrix associated with '" + refSeq.getName() + + "' is not mappable for the given localFrame sequence. (" + + localFrame.getName() + ")"); + } + // check the mapping to see if localFrame _lcolumn exists + int[] word = toSeq.locateInTo(_lcolumn, _lcolumn); + if (word == null) + { + return null; + } + _column = word[0]; + } + else + { + // no mapping + _column = _lcolumn; + } + + // TODO - remove ? this may be a redundant check + if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest()) + || (toSeq == null && getHeight() <= _column))) + { + return null; + } + + // 2. resolve ranges in matrix corresponding to range in localFrame + final int[] matrixRange = toSeq == null + ? new int[] + { localFrame.getStart(), localFrame.getEnd() } + : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd()); + + int h = 0; + for (int p = 0; p < matrixRange.length; p += 2) + { + h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]); + } + final int rangeHeight = h; + // 3. Construct ContactListImpl instance for just those segments. + + return new ContactListImpl(new ContactListProviderI() + { + + public int getColumn() + { + return column; + } + @Override + public int getPosition() + { + return _column; + } + + @Override + public int getContactHeight() + { + return rangeHeight; + } + + @Override + public double getContactAt(int mcolumn) + { + if (mcolumn<0 || mcolumn>=rangeHeight) + { + return -1; + } + return getElementAt(_column, locateInRange(mcolumn)); + + // this code maps from mcolumn to localFrame - but that isn't what's needed +// int loccolumn = localFrame.findPosition(mcolumn); +// int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : toSeq.locateInTo(loccolumn,loccolumn); +// if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight) +// { +// return -1; +// } +// return getElementAt(_column,lcolumn[0]); + } + /** + * @return the mcolumn'th position in the matrixRange window on the matrix + */ + private int locateInRange(int mcolumn) + { + + int h=0,p=0; + while (h < mcolumn && p+2 < matrixRange.length) + { + h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]); + p+=2; + } + return matrixRange[p]+mcolumn-h; + } + + @Override + public int[] getMappedPositionsFor(int cStart, int cEnd) + { + if (!hasReferenceSeq()) + { + return ContactListProviderI.super.getMappedPositionsFor(cStart, cEnd); + } + // map into segment of matrix being shown + int realCstart = locateInRange(cStart); + int realCend = locateInRange(cEnd); + + // TODO account for discontinuities in the mapping + + int[] mappedPositions = toSeq.locateInFrom(realCstart,realCend); + if (mappedPositions!=null) { + int s=-1,e=-1; + for (int p=0;p=localFrame.getStart()) + { + s=p; // remember first position within local frame + } + if (e==-1 || mappedPositions[p]<=localFrame.getEnd()) + { + // update end pointer + e=p; + // compute local map + mappedPositions[p] = localFrame.findIndex(mappedPositions[p]); + } + } + } + return mappedPositions; + } + }); + } + + /** + * get a specific element of the contact matrix in its data-local coordinates + * rather than the mapped frame. Implementations are allowed to throw RunTimeExceptions if _column/i are out of bounds + * + * @param _column + * @param i + * @return + */ + protected abstract double getElementAt(int _column, int i); +}