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 // return a ContactListI for column
197 // column is index into localFrame
198 // 1. map column to corresponding column in matrix
200 final int _lcolumn = localFrame.findPosition(from);
201 final int _rcolumn = (from == to) ? _lcolumn
202 : localFrame.findPosition(to);
206 return new int[] { _lcolumn, _rcolumn };
209 SequenceI lf = localFrame, uf = refSeq;
211 // just look for dataset sequences and check they are the same.
212 // in future we could use DBRefMappings/whatever.
213 while (lf.getDatasetSequence() != null
214 || uf.getDatasetSequence() != null)
216 if (lf.getDatasetSequence() != null)
218 lf = lf.getDatasetSequence();
220 if (uf.getDatasetSequence() != null)
222 uf = uf.getDatasetSequence();
227 // could try harder to find a mapping
228 throw new Error("This Matrix associated with '" + refSeq.getName()
229 + "' is not mappable for the given localFrame sequence. ("
230 + localFrame.getName() + ")");
233 int[] mappedPositions = toSeq.locateInFrom(_lcolumn, _rcolumn);
234 // TODO - trim to localFrame ?
235 // if (mappedPositions!=null) {
237 // for (int p=0;p<mappedPositions.length;p++)
239 // if (s==-1 && mappedPositions[p]>=localFrame.getStart())
241 // s=p; // remember first position within local frame
243 // if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
245 // // update end pointer
247 // // compute local map
248 // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
252 return mappedPositions;
256 public ContactListI getMappableContactList(final SequenceI localFrame,
261 if (localFrame == null)
263 throw new Error("Unimplemented when no local sequence given.");
265 // return a ContactListI for column
266 // column is index into localFrame
267 // 1. map column to corresponding column in matrix
268 final MappableContactMatrix us = this;
269 _lcolumn = localFrame.findPosition(column);
273 SequenceI lf = localFrame, uf = refSeq;
275 // just look for dataset sequences and check they are the same.
276 // in future we could use DBRefMappings/whatever.
277 while (lf.getDatasetSequence() != null
278 || uf.getDatasetSequence() != null)
280 if (lf.getDatasetSequence() != null)
282 lf = lf.getDatasetSequence();
284 if (uf.getDatasetSequence() != null)
286 uf = uf.getDatasetSequence();
291 // could try harder to find a mapping
292 throw new Error("This Matrix associated with '" + refSeq.getName()
293 + "' is not mappable for the given localFrame sequence. ("
294 + localFrame.getName() + ")");
296 // check the mapping to see if localFrame _lcolumn exists
297 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
310 // TODO - remove ? this may be a redundant check
311 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
312 || (toSeq == null && getHeight() <= _column)))
317 // 2. resolve ranges in matrix corresponding to range in localFrame
318 final int[] matrixRange = toSeq == null
320 { localFrame.getStart(), localFrame.getEnd() }
321 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
324 for (int p = 0; p < matrixRange.length; p += 2)
326 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
328 final int rangeHeight = h;
329 // 3. Construct ContactListImpl instance for just those segments.
331 return new ContactListImpl(new ContactListProviderI()
334 public int getColumn()
340 public int getPosition()
346 public int getContactHeight()
352 public double getContactAt(int mcolumn)
354 if (mcolumn < 0 || mcolumn >= rangeHeight)
358 return getElementAt(_column, locateInRange(mcolumn));
360 // this code maps from mcolumn to localFrame - but that isn't what's
362 // int loccolumn = localFrame.findPosition(mcolumn);
363 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
364 // toSeq.locateInTo(loccolumn,loccolumn);
365 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
369 // return getElementAt(_column,lcolumn[0]);
373 public int[] getMappedPositionsFor(int cStart, int cEnd)
375 if (!hasReferenceSeq())
377 return ContactListProviderI.super.getMappedPositionsFor(cStart,
380 // map into segment of matrix being shown
381 int realCstart = locateInRange(cStart);
382 int realCend = locateInRange(cEnd);
384 // TODO account for discontinuities in the mapping
386 int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
387 if (mappedPositions != null)
390 for (int p = 0; p < mappedPositions.length; p++)
392 if (s == -1 && mappedPositions[p] >= localFrame.getStart())
394 s = p; // remember first position within local frame
396 if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
398 // update end pointer
401 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
405 return mappedPositions;
409 * @return the mcolumn'th position in the matrixRange window on the matrix
411 private int locateInRange(int mcolumn)
415 while (h < mcolumn && p + 2 < matrixRange.length)
417 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
420 return matrixRange[p] + mcolumn - h;
424 public Color getColourForGroup()
426 BitSet gp = us.getGroupsFor(_column);
427 Color col = us.getColourForGroup(gp);
434 * get a specific element of the contact matrix in its data-local coordinates
435 * rather than the mapped frame. Implementations are allowed to throw
436 * RunTimeExceptions if _column/i are out of bounds
442 protected abstract double getElementAt(int _column, int i);