1 package jalview.ws.datamodel.alphafold;
4 import java.util.ArrayList;
5 import java.util.BitSet;
7 import jalview.datamodel.ContactListI;
8 import jalview.datamodel.ContactListImpl;
9 import jalview.datamodel.ContactListProviderI;
10 import jalview.datamodel.ContactMatrixI;
11 import jalview.datamodel.GroupSet;
12 import jalview.datamodel.GroupSetI;
13 import jalview.datamodel.Mapping;
14 import jalview.datamodel.SequenceI;
15 import jalview.util.MapList;
16 import jalview.ws.datamodel.MappableContactMatrixI;
18 public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>>
19 implements MappableContactMatrixI
22 * the matrix that is being mapped to
24 protected ContactMatrixI mappedMatrix = null;
26 public ContactListI getContactList(int column)
28 return mappedMatrix.getContactList(column);
33 return mappedMatrix.getMin();
38 return mappedMatrix.getMax();
43 return mappedMatrix.getWidth();
46 public int getHeight()
48 return mappedMatrix.getHeight();
52 public ContactMatrixI getMappedMatrix()
58 public GroupSetI getGroupSet()
60 return mappedMatrix.getGroupSet();
64 public void setGroupSet(GroupSet makeGroups)
66 mappedMatrix.setGroupSet(makeGroups);
70 * the sequence and how it is mapped to the matrix
73 SequenceI refSeq = null;
78 * the length that refSeq is expected to be (excluding gaps, of course)
83 public boolean hasReferenceSeq()
85 return (refSeq != null);
89 public SequenceI getReferenceSeq()
95 public MapList getMapFor(SequenceI mapSeq)
99 while (mapSeq != refSeq && mapSeq.getDatasetSequence() != null)
101 mapSeq = mapSeq.getDatasetSequence();
103 if (mapSeq != refSeq)
112 // our MapList does not concern this seq
121 * set the reference sequence and construct the mapping between the start-end
122 * positions of given sequence and row/columns of contact matrix
126 public void setRefSeq(SequenceI _refSeq)
129 while (refSeq.getDatasetSequence() != null)
131 refSeq = refSeq.getDatasetSequence();
133 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
134 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
138 { _refSeq.getStart(), _refSeq.getEnd() },
140 { 0, length - 1 }, 1, 1);
144 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
146 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
148 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
149 // Protein reference frames
151 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
153 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
156 * map from matrix to toSeq's coordinate frame
158 int[] refMap = toSeq.locateInFrom(0, length - 1);
159 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
161 for (int i = 0; i < refMap.length; i += 2)
164 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
166 int[] sp2map = mapIsTo
167 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
168 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
174 for (int spm = 0; spm < sp2map.length; spm += 2)
179 if (sp2map[spm] != last + 1)
181 newFromMap.add(sp2map[spm]);
185 newFromMap.remove(newFromMap.size() - 1);
190 newFromMap.add(sp2map[spm]);
192 last = sp2map[spm + 1];
193 newFromMap.add(last);
196 if ((newFromMap.size() % 2) != 0)
198 // should have had an even number of int ranges!
199 throw new Error("PAEMatrix liftover failed.");
201 int fromIntMap[] = new int[newFromMap.size()];
203 for (Integer i : newFromMap)
205 fromIntMap[ipos++] = i;
207 MapList newFromMapList = new MapList(fromIntMap,
209 { 0, length - 1 }, 1, 1);
211 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
215 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
216 MapList newFromMapList);
219 public int[] getMappedPositionsFor(final SequenceI localFrame,
222 return getMappedPositionsFor(localFrame, column, column);
226 public int[] getMappedPositionsFor(final SequenceI localFrame, int from,
229 if (localFrame == null)
231 throw new Error("Unimplemented when no local sequence given.");
233 SequenceI lf = localFrame, uf = refSeq;
235 // check that localFrame is derived from refSeq
236 // just look for dataset sequences and check they are the same.
237 // in future we could use DBRefMappings/whatever.
238 while (lf.getDatasetSequence() != null
239 || uf.getDatasetSequence() != null)
241 if (lf.getDatasetSequence() != null)
243 lf = lf.getDatasetSequence();
245 if (uf.getDatasetSequence() != null)
247 uf = uf.getDatasetSequence();
252 // could try harder to find a mapping
253 throw new Error("This Matrix associated with '" + refSeq.getName()
254 + "' is not mappable for the given localFrame sequence. ("
255 + localFrame.getName() + ")");
258 // now look up from-to matrix columns in toSeq frame
262 // no mapping - so we assume 1:1
263 return new int[] { from, to };
265 // from-to are matrix columns
266 // first locate on reference sequence
268 int[] mappedPositions = toSeq.locateInFrom(from, to);
269 if (mappedPositions == null)
274 // and now map to localFrame
275 // from-to columns on the associated sequence should be
276 // i. restricted to positions in localFrame
279 // int s = -1, e = -1;
280 // for (int p = 0; p < mappedPositions.length; p++)
282 // if (s == -1 && mappedPositions[p] >= localFrame.getStart())
284 // s = p; // remember first position within local frame
286 // if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
288 // // update end pointer
290 // // compute local map
291 // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
294 // int[] _trimmed = new int[e - s + 1];
296 return mappedPositions;
300 public ContactListI getMappableContactList(final SequenceI localFrame,
305 if (localFrame == null)
307 throw new Error("Unimplemented when no local sequence given.");
309 // return a ContactListI for column
310 // column is index into localFrame
311 // 1. map column to corresponding column in matrix
312 final MappableContactMatrix us = this;
313 _lcolumn = localFrame.findPosition(column);
317 SequenceI lf = localFrame, uf = refSeq;
319 // just look for dataset sequences and check they are the same.
320 // in future we could use DBRefMappings/whatever.
321 while (lf.getDatasetSequence() != null
322 || uf.getDatasetSequence() != null)
324 if (lf.getDatasetSequence() != null)
326 lf = lf.getDatasetSequence();
328 if (uf.getDatasetSequence() != null)
330 uf = uf.getDatasetSequence();
335 // could try harder to find a mapping
336 throw new Error("This Matrix associated with '" + refSeq.getName()
337 + "' is not mappable for the given localFrame sequence. ("
338 + localFrame.getName() + ")");
340 // check the mapping to see if localFrame _lcolumn exists
341 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
354 // TODO - remove ? this may be a redundant check
355 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
356 || (toSeq == null && getHeight() <= _column)))
361 // 2. resolve ranges in matrix corresponding to range in localFrame
362 final int[] matrixRange = toSeq == null
364 { localFrame.getStart(), localFrame.getEnd() }
365 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
368 for (int p = 0; p < matrixRange.length; p += 2)
370 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
372 final int rangeHeight = h;
373 // 3. Construct ContactListImpl instance for just those segments.
375 return new ContactListImpl(new ContactListProviderI()
378 public int getColumn()
384 public int getPosition()
390 public int getContactHeight()
396 public double getContactAt(int mcolumn)
398 if (mcolumn < 0 || mcolumn >= rangeHeight)
402 return getElementAt(_column, locateInRange(mcolumn));
404 // this code maps from mcolumn to localFrame - but that isn't what's
406 // int loccolumn = localFrame.findPosition(mcolumn);
407 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
408 // toSeq.locateInTo(loccolumn,loccolumn);
409 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
413 // return getElementAt(_column,lcolumn[0]);
417 public int[] getMappedPositionsFor(int cStart, int cEnd)
419 if (!hasReferenceSeq())
421 return ContactListProviderI.super.getMappedPositionsFor(cStart,
424 // map into segment of matrix being shown
425 int realCstart = locateInRange(cStart);
426 int realCend = locateInRange(cEnd);
428 // TODO account for discontinuities in the mapping
430 int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
431 if (mappedPositions != null)
434 for (int p = 0; p < mappedPositions.length; p++)
436 if (s == -1 && mappedPositions[p] >= localFrame.getStart())
438 s = p; // remember first position within local frame
440 if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
442 // update end pointer
445 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
449 return mappedPositions;
453 * @return the mcolumn'th position in the matrixRange window on the matrix
455 private int locateInRange(int mcolumn)
459 while (h < mcolumn && p + 2 < matrixRange.length)
461 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
464 return matrixRange[p] + mcolumn - h;
468 public Color getColourForGroup()
470 BitSet gp = us.getGroupsFor(_column);
471 Color col = us.getColourForGroup(gp);
478 * get a specific element of the underlying contact matrix in its data-local
479 * coordinates rather than the mapped frame. Implementations are allowed to
480 * throw RunTimeExceptions if _column/i are out of bounds
486 public double getElementAt(int _column, int i)
488 return mappedMatrix.getElementAt(_column, i);
492 public int hashCode()
494 return 7 * (refSeq != null ? refSeq.hashCode() : 0)
495 + 11 * (toSeq != null ? toSeq.hashCode() : 0)
496 + 13 * (mappedMatrix != null ? mappedMatrix.hashCode() : 0)
501 public boolean equals(Object obj)
503 if (obj == null || !(obj.getClass().equals(getClass())))
508 return mappedMatrix == them.mappedMatrix && length == them.length
509 && refSeq == them.refSeq && toSeq.equals(them.toSeq);