1 package jalview.ws.datamodel.alphafold;
3 import java.util.ArrayList;
5 import jalview.datamodel.ContactListI;
6 import jalview.datamodel.ContactListImpl;
7 import jalview.datamodel.ContactListProviderI;
8 import jalview.datamodel.Mapping;
9 import jalview.datamodel.SequenceI;
10 import jalview.util.MapList;
11 import jalview.ws.datamodel.MappableContactMatrixI;
13 public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>> implements MappableContactMatrixI
15 SequenceI refSeq = null;
19 * the length that refSeq is expected to be (excluding gaps, of course)
25 public boolean hasReferenceSeq()
27 return (refSeq != null);
31 public SequenceI getReferenceSeq()
36 public MapList getMapFor(SequenceI mapSeq)
40 while (mapSeq!=refSeq && mapSeq.getDatasetSequence()!=null)
42 mapSeq = mapSeq.getDatasetSequence();
50 // our MapList does not concern this seq
59 * set the reference sequence and construct the mapping between the start-end positions of given sequence and row/columns of contact matrix
62 public void setRefSeq(SequenceI _refSeq)
65 while (refSeq.getDatasetSequence() != null)
67 refSeq = refSeq.getDatasetSequence();
69 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
70 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
72 toSeq = new MapList(new int[] { _refSeq.getStart(), _refSeq.getEnd()}, new int[] { 0,length-1}, 1,1);
76 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
78 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
80 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
81 // Protein reference frames
83 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
85 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
88 * map from matrix to toSeq's coordinate frame
90 int[] refMap = toSeq.locateInFrom(0, length - 1);
91 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
93 for (int i = 0; i < refMap.length; i += 2)
96 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
98 int[] sp2map = mapIsTo
99 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
100 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
106 for (int spm = 0; spm < sp2map.length; spm += 2)
111 if (sp2map[spm] != last + 1)
113 newFromMap.add(sp2map[spm]);
117 newFromMap.remove(newFromMap.size() - 1);
122 newFromMap.add(sp2map[spm]);
124 last = sp2map[spm + 1];
125 newFromMap.add(last);
128 if ((newFromMap.size() % 2) != 0)
130 // should have had an even number of int ranges!
131 throw new Error("PAEMatrix liftover failed.");
133 int fromIntMap[] = new int[newFromMap.size()];
135 for (Integer i : newFromMap)
137 fromIntMap[ipos++] = i;
139 MapList newFromMapList = new MapList(fromIntMap,
141 { 0, length - 1 }, 1, 1);
143 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
147 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
148 MapList newFromMapList);
150 public ContactListI getMappableContactList(final SequenceI localFrame,
155 if (localFrame==null)
157 throw new Error("Unimplemented when no local sequence given.");
159 // return a ContactListI for column
160 // column is index into localFrame
161 // 1. map column to corresponding column in matrix
163 _lcolumn=localFrame.findPosition(column);
167 SequenceI lf = localFrame, uf = refSeq;
169 // just look for dataset sequences and check they are the same.
170 // in future we could use DBRefMappings/whatever.
171 while (lf.getDatasetSequence() != null
172 || uf.getDatasetSequence() != null)
174 if (lf.getDatasetSequence() != null)
176 lf = lf.getDatasetSequence();
178 if (uf.getDatasetSequence() != null)
180 uf = uf.getDatasetSequence();
185 // could try harder to find a mapping
186 throw new Error("This Matrix associated with '" + refSeq.getName()
187 + "' is not mappable for the given localFrame sequence. ("
188 + localFrame.getName() + ")");
190 // check the mapping to see if localFrame _lcolumn exists
191 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
204 // TODO - remove ? this may be a redundant check
205 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
206 || (toSeq == null && getHeight() <= _column)))
211 // 2. resolve ranges in matrix corresponding to range in localFrame
212 final int[] matrixRange = toSeq == null
214 { localFrame.getStart(), localFrame.getEnd() }
215 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
218 for (int p = 0; p < matrixRange.length; p += 2)
220 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
222 final int rangeHeight = h;
223 // 3. Construct ContactListImpl instance for just those segments.
225 return new ContactListImpl(new ContactListProviderI()
228 public int getColumn()
233 public int getPosition()
239 public int getContactHeight()
245 public double getContactAt(int mcolumn)
247 if (mcolumn<0 || mcolumn>=rangeHeight)
251 return getElementAt(_column, locateInRange(mcolumn));
253 // this code maps from mcolumn to localFrame - but that isn't what's needed
254 // int loccolumn = localFrame.findPosition(mcolumn);
255 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : toSeq.locateInTo(loccolumn,loccolumn);
256 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
260 // return getElementAt(_column,lcolumn[0]);
263 * @return the mcolumn'th position in the matrixRange window on the matrix
265 private int locateInRange(int mcolumn)
269 while (h < mcolumn && p+2 < matrixRange.length)
271 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
274 return matrixRange[p]+mcolumn-h;
278 public int[] getMappedPositionsFor(int cStart, int cEnd)
280 if (!hasReferenceSeq())
282 return ContactListProviderI.super.getMappedPositionsFor(cStart, cEnd);
284 // map into segment of matrix being shown
285 int realCstart = locateInRange(cStart);
286 int realCend = locateInRange(cEnd);
288 // TODO account for discontinuities in the mapping
290 int[] mappedPositions = toSeq.locateInFrom(realCstart,realCend);
291 if (mappedPositions!=null) {
293 for (int p=0;p<mappedPositions.length;p++)
295 if (s==-1 && mappedPositions[p]>=localFrame.getStart())
297 s=p; // remember first position within local frame
299 if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
301 // update end pointer
304 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
308 return mappedPositions;
314 * get a specific element of the contact matrix in its data-local coordinates
315 * rather than the mapped frame. Implementations are allowed to throw RunTimeExceptions if _column/i are out of bounds
321 protected abstract double getElementAt(int _column, int i);