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.GroupSet;
11 import jalview.datamodel.GroupSetI;
12 import jalview.datamodel.Mapping;
13 import jalview.datamodel.SequenceI;
14 import jalview.util.MapList;
15 import jalview.ws.datamodel.MappableContactMatrixI;
17 public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>>
18 implements MappableContactMatrixI
20 SequenceI refSeq = null;
25 * the length that refSeq is expected to be (excluding gaps, of course)
30 public boolean hasReferenceSeq()
32 return (refSeq != null);
36 public SequenceI getReferenceSeq()
42 * container for groups - defined on matrix columns
44 GroupSet grps = new GroupSet();
47 public GroupSetI getGroupSet()
53 public void setGroupSet(GroupSet makeGroups)
59 public MapList getMapFor(SequenceI mapSeq)
63 while (mapSeq != refSeq && mapSeq.getDatasetSequence() != null)
65 mapSeq = mapSeq.getDatasetSequence();
76 // our MapList does not concern this seq
85 * set the reference sequence and construct the mapping between the start-end
86 * positions of given sequence and row/columns of contact matrix
90 public void setRefSeq(SequenceI _refSeq)
93 while (refSeq.getDatasetSequence() != null)
95 refSeq = refSeq.getDatasetSequence();
97 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
98 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
102 { _refSeq.getStart(), _refSeq.getEnd() },
104 { 0, length - 1 }, 1, 1);
108 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
110 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
112 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
113 // Protein reference frames
115 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
117 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
120 * map from matrix to toSeq's coordinate frame
122 int[] refMap = toSeq.locateInFrom(0, length - 1);
123 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
125 for (int i = 0; i < refMap.length; i += 2)
128 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
130 int[] sp2map = mapIsTo
131 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
132 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
138 for (int spm = 0; spm < sp2map.length; spm += 2)
143 if (sp2map[spm] != last + 1)
145 newFromMap.add(sp2map[spm]);
149 newFromMap.remove(newFromMap.size() - 1);
154 newFromMap.add(sp2map[spm]);
156 last = sp2map[spm + 1];
157 newFromMap.add(last);
160 if ((newFromMap.size() % 2) != 0)
162 // should have had an even number of int ranges!
163 throw new Error("PAEMatrix liftover failed.");
165 int fromIntMap[] = new int[newFromMap.size()];
167 for (Integer i : newFromMap)
169 fromIntMap[ipos++] = i;
171 MapList newFromMapList = new MapList(fromIntMap,
173 { 0, length - 1 }, 1, 1);
175 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
179 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
180 MapList newFromMapList);
183 public int[] getMappedPositionsFor(final SequenceI localFrame,
186 return getMappedPositionsFor(localFrame, column, column);
190 public int[] getMappedPositionsFor(final SequenceI localFrame, int from,
193 if (localFrame == null)
195 throw new Error("Unimplemented when no local sequence given.");
197 SequenceI lf = localFrame, uf = refSeq;
199 // check that localFrame is derived from refSeq
200 // just look for dataset sequences and check they are the same.
201 // in future we could use DBRefMappings/whatever.
202 while (lf.getDatasetSequence() != null
203 || uf.getDatasetSequence() != null)
205 if (lf.getDatasetSequence() != null)
207 lf = lf.getDatasetSequence();
209 if (uf.getDatasetSequence() != null)
211 uf = uf.getDatasetSequence();
216 // could try harder to find a mapping
217 throw new Error("This Matrix associated with '" + refSeq.getName()
218 + "' is not mappable for the given localFrame sequence. ("
219 + localFrame.getName() + ")");
222 // now look up from-to matrix columns in toSeq frame
226 // no mapping - so we assume 1:1
227 return new int[] { from, to };
229 // from-to are matrix columns
230 // first locate on reference sequence
232 int[] mappedPositions = toSeq.locateInFrom(from, to);
233 if (mappedPositions==null)
238 // and now map to localFrame
239 // from-to columns on the associated sequence should be
240 // i. restricted to positions in localFrame
243 // int s = -1, e = -1;
244 // for (int p = 0; p < mappedPositions.length; p++)
246 // if (s == -1 && mappedPositions[p] >= localFrame.getStart())
248 // s = p; // remember first position within local frame
250 // if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
252 // // update end pointer
254 // // compute local map
255 // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
258 // int[] _trimmed = new int[e - s + 1];
260 return mappedPositions;
264 public ContactListI getMappableContactList(final SequenceI localFrame,
269 if (localFrame == null)
271 throw new Error("Unimplemented when no local sequence given.");
273 // return a ContactListI for column
274 // column is index into localFrame
275 // 1. map column to corresponding column in matrix
276 final MappableContactMatrix us = this;
277 _lcolumn = localFrame.findPosition(column);
281 SequenceI lf = localFrame, uf = refSeq;
283 // just look for dataset sequences and check they are the same.
284 // in future we could use DBRefMappings/whatever.
285 while (lf.getDatasetSequence() != null
286 || uf.getDatasetSequence() != null)
288 if (lf.getDatasetSequence() != null)
290 lf = lf.getDatasetSequence();
292 if (uf.getDatasetSequence() != null)
294 uf = uf.getDatasetSequence();
299 // could try harder to find a mapping
300 throw new Error("This Matrix associated with '" + refSeq.getName()
301 + "' is not mappable for the given localFrame sequence. ("
302 + localFrame.getName() + ")");
304 // check the mapping to see if localFrame _lcolumn exists
305 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
318 // TODO - remove ? this may be a redundant check
319 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
320 || (toSeq == null && getHeight() <= _column)))
325 // 2. resolve ranges in matrix corresponding to range in localFrame
326 final int[] matrixRange = toSeq == null
328 { localFrame.getStart(), localFrame.getEnd() }
329 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
332 for (int p = 0; p < matrixRange.length; p += 2)
334 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
336 final int rangeHeight = h;
337 // 3. Construct ContactListImpl instance for just those segments.
339 return new ContactListImpl(new ContactListProviderI()
342 public int getColumn()
348 public int getPosition()
354 public int getContactHeight()
360 public double getContactAt(int mcolumn)
362 if (mcolumn < 0 || mcolumn >= rangeHeight)
366 return getElementAt(_column, locateInRange(mcolumn));
368 // this code maps from mcolumn to localFrame - but that isn't what's
370 // int loccolumn = localFrame.findPosition(mcolumn);
371 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
372 // toSeq.locateInTo(loccolumn,loccolumn);
373 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
377 // return getElementAt(_column,lcolumn[0]);
381 public int[] getMappedPositionsFor(int cStart, int cEnd)
383 if (!hasReferenceSeq())
385 return ContactListProviderI.super.getMappedPositionsFor(cStart,
388 // map into segment of matrix being shown
389 int realCstart = locateInRange(cStart);
390 int realCend = locateInRange(cEnd);
392 // TODO account for discontinuities in the mapping
394 int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
395 if (mappedPositions != null)
398 for (int p = 0; p < mappedPositions.length; p++)
400 if (s == -1 && mappedPositions[p] >= localFrame.getStart())
402 s = p; // remember first position within local frame
404 if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
406 // update end pointer
409 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
413 return mappedPositions;
417 * @return the mcolumn'th position in the matrixRange window on the matrix
419 private int locateInRange(int mcolumn)
423 while (h < mcolumn && p + 2 < matrixRange.length)
425 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
428 return matrixRange[p] + mcolumn - h;
432 public Color getColourForGroup()
434 BitSet gp = us.getGroupsFor(_column);
435 Color col = us.getColourForGroup(gp);
442 * get a specific element of the contact matrix in its data-local coordinates
443 * rather than the mapped frame. Implementations are allowed to throw
444 * RunTimeExceptions if _column/i are out of bounds
450 protected abstract double getElementAt(int _column, int i);