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);
189 public int[] getMappedPositionsFor(final SequenceI localFrame, int from,
192 if (localFrame == null)
194 throw new Error("Unimplemented when no local sequence given.");
196 SequenceI lf = localFrame, uf = refSeq;
198 // check that localFrame is derived from refSeq
199 // just look for dataset sequences and check they are the same.
200 // in future we could use DBRefMappings/whatever.
201 while (lf.getDatasetSequence() != null
202 || uf.getDatasetSequence() != null)
204 if (lf.getDatasetSequence() != null)
206 lf = lf.getDatasetSequence();
208 if (uf.getDatasetSequence() != null)
210 uf = uf.getDatasetSequence();
215 // could try harder to find a mapping
216 throw new Error("This Matrix associated with '" + refSeq.getName()
217 + "' is not mappable for the given localFrame sequence. ("
218 + localFrame.getName() + ")");
221 // now look up from-to matrix columns in toSeq frame
225 // no mapping - so we assume 1:1
226 return new int[] { from, to };
228 // from-to are matrix columns
229 // first locate on reference sequence
231 int[] mappedPositions = toSeq.locateInFrom(from, to);
232 if (mappedPositions==null)
237 // and now map to localFrame
238 // from-to columns on the associated sequence should be
239 // i. restricted to positions in localFrame
242 // int s = -1, e = -1;
243 // for (int p = 0; p < mappedPositions.length; p++)
245 // if (s == -1 && mappedPositions[p] >= localFrame.getStart())
247 // s = p; // remember first position within local frame
249 // if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
251 // // update end pointer
253 // // compute local map
254 // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
257 // int[] _trimmed = new int[e - s + 1];
259 return mappedPositions;
263 public ContactListI getMappableContactList(final SequenceI localFrame,
268 if (localFrame == null)
270 throw new Error("Unimplemented when no local sequence given.");
272 // return a ContactListI for column
273 // column is index into localFrame
274 // 1. map column to corresponding column in matrix
275 final MappableContactMatrix us = this;
276 _lcolumn = localFrame.findPosition(column);
280 SequenceI lf = localFrame, uf = refSeq;
282 // just look for dataset sequences and check they are the same.
283 // in future we could use DBRefMappings/whatever.
284 while (lf.getDatasetSequence() != null
285 || uf.getDatasetSequence() != null)
287 if (lf.getDatasetSequence() != null)
289 lf = lf.getDatasetSequence();
291 if (uf.getDatasetSequence() != null)
293 uf = uf.getDatasetSequence();
298 // could try harder to find a mapping
299 throw new Error("This Matrix associated with '" + refSeq.getName()
300 + "' is not mappable for the given localFrame sequence. ("
301 + localFrame.getName() + ")");
303 // check the mapping to see if localFrame _lcolumn exists
304 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
317 // TODO - remove ? this may be a redundant check
318 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
319 || (toSeq == null && getHeight() <= _column)))
324 // 2. resolve ranges in matrix corresponding to range in localFrame
325 final int[] matrixRange = toSeq == null
327 { localFrame.getStart(), localFrame.getEnd() }
328 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
331 for (int p = 0; p < matrixRange.length; p += 2)
333 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
335 final int rangeHeight = h;
336 // 3. Construct ContactListImpl instance for just those segments.
338 return new ContactListImpl(new ContactListProviderI()
341 public int getColumn()
347 public int getPosition()
353 public int getContactHeight()
359 public double getContactAt(int mcolumn)
361 if (mcolumn < 0 || mcolumn >= rangeHeight)
365 return getElementAt(_column, locateInRange(mcolumn));
367 // this code maps from mcolumn to localFrame - but that isn't what's
369 // int loccolumn = localFrame.findPosition(mcolumn);
370 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
371 // toSeq.locateInTo(loccolumn,loccolumn);
372 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
376 // return getElementAt(_column,lcolumn[0]);
380 public int[] getMappedPositionsFor(int cStart, int cEnd)
382 if (!hasReferenceSeq())
384 return ContactListProviderI.super.getMappedPositionsFor(cStart,
387 // map into segment of matrix being shown
388 int realCstart = locateInRange(cStart);
389 int realCend = locateInRange(cEnd);
391 // TODO account for discontinuities in the mapping
393 int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
394 if (mappedPositions != null)
397 for (int p = 0; p < mappedPositions.length; p++)
399 if (s == -1 && mappedPositions[p] >= localFrame.getStart())
401 s = p; // remember first position within local frame
403 if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
405 // update end pointer
408 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
412 return mappedPositions;
416 * @return the mcolumn'th position in the matrixRange window on the matrix
418 private int locateInRange(int mcolumn)
422 while (h < mcolumn && p + 2 < matrixRange.length)
424 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
427 return matrixRange[p] + mcolumn - h;
431 public Color getColourForGroup()
433 BitSet gp = us.getGroupsFor(_column);
434 Color col = us.getColourForGroup(gp);
441 * get a specific element of the contact matrix in its data-local coordinates
442 * rather than the mapped frame. Implementations are allowed to throw
443 * RunTimeExceptions if _column/i are out of bounds
449 protected abstract double getElementAt(int _column, int i);