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>> implements MappableContactMatrixI
19 SequenceI refSeq = null;
23 * the length that refSeq is expected to be (excluding gaps, of course)
29 public boolean hasReferenceSeq()
31 return (refSeq != null);
35 public SequenceI getReferenceSeq()
40 * container for groups - defined on matrix columns
42 GroupSet grps=new GroupSet();
44 public GroupSetI getGroupSet()
49 public void setGroupSet(GroupSet makeGroups)
55 public MapList getMapFor(SequenceI mapSeq)
59 while (mapSeq!=refSeq && mapSeq.getDatasetSequence()!=null)
61 mapSeq = mapSeq.getDatasetSequence();
69 // our MapList does not concern this seq
78 * set the reference sequence and construct the mapping between the start-end positions of given sequence and row/columns of contact matrix
81 public void setRefSeq(SequenceI _refSeq)
84 while (refSeq.getDatasetSequence() != null)
86 refSeq = refSeq.getDatasetSequence();
88 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
89 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
91 toSeq = new MapList(new int[] { _refSeq.getStart(), _refSeq.getEnd()}, new int[] { 0,length-1}, 1,1);
95 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
97 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
99 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
100 // Protein reference frames
102 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
104 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
107 * map from matrix to toSeq's coordinate frame
109 int[] refMap = toSeq.locateInFrom(0, length - 1);
110 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
112 for (int i = 0; i < refMap.length; i += 2)
115 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
117 int[] sp2map = mapIsTo
118 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
119 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
125 for (int spm = 0; spm < sp2map.length; spm += 2)
130 if (sp2map[spm] != last + 1)
132 newFromMap.add(sp2map[spm]);
136 newFromMap.remove(newFromMap.size() - 1);
141 newFromMap.add(sp2map[spm]);
143 last = sp2map[spm + 1];
144 newFromMap.add(last);
147 if ((newFromMap.size() % 2) != 0)
149 // should have had an even number of int ranges!
150 throw new Error("PAEMatrix liftover failed.");
152 int fromIntMap[] = new int[newFromMap.size()];
154 for (Integer i : newFromMap)
156 fromIntMap[ipos++] = i;
158 MapList newFromMapList = new MapList(fromIntMap,
160 { 0, length - 1 }, 1, 1);
162 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
166 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
167 MapList newFromMapList);
169 public int[] getMappedPositionsFor(final SequenceI localFrame,
172 return getMappedPositionsFor(localFrame,column,column);
174 public int[] getMappedPositionsFor(final SequenceI localFrame,
177 if (localFrame==null)
179 throw new Error("Unimplemented when no local sequence given.");
181 // return a ContactListI for column
182 // column is index into localFrame
183 // 1. map column to corresponding column in matrix
185 final int _lcolumn=localFrame.findPosition(from);
186 final int _rcolumn=(from==to) ? _lcolumn:localFrame.findPosition(to);
190 return new int[] { _lcolumn,_rcolumn};
193 SequenceI lf = localFrame, uf = refSeq;
195 // just look for dataset sequences and check they are the same.
196 // in future we could use DBRefMappings/whatever.
197 while (lf.getDatasetSequence() != null
198 || uf.getDatasetSequence() != null)
200 if (lf.getDatasetSequence() != null)
202 lf = lf.getDatasetSequence();
204 if (uf.getDatasetSequence() != null)
206 uf = uf.getDatasetSequence();
211 // could try harder to find a mapping
212 throw new Error("This Matrix associated with '" + refSeq.getName()
213 + "' is not mappable for the given localFrame sequence. ("
214 + localFrame.getName() + ")");
217 int[] mappedPositions = toSeq.locateInFrom(_lcolumn,_rcolumn);
218 // TODO - trim to localFrame ?
219 // if (mappedPositions!=null) {
221 // for (int p=0;p<mappedPositions.length;p++)
223 // if (s==-1 && mappedPositions[p]>=localFrame.getStart())
225 // s=p; // remember first position within local frame
227 // if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
229 // // update end pointer
231 // // compute local map
232 // mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
236 return mappedPositions;
240 public ContactListI getMappableContactList(final SequenceI localFrame,
245 if (localFrame==null)
247 throw new Error("Unimplemented when no local sequence given.");
249 // return a ContactListI for column
250 // column is index into localFrame
251 // 1. map column to corresponding column in matrix
252 final MappableContactMatrix us=this;
253 _lcolumn=localFrame.findPosition(column);
257 SequenceI lf = localFrame, uf = refSeq;
259 // just look for dataset sequences and check they are the same.
260 // in future we could use DBRefMappings/whatever.
261 while (lf.getDatasetSequence() != null
262 || uf.getDatasetSequence() != null)
264 if (lf.getDatasetSequence() != null)
266 lf = lf.getDatasetSequence();
268 if (uf.getDatasetSequence() != null)
270 uf = uf.getDatasetSequence();
275 // could try harder to find a mapping
276 throw new Error("This Matrix associated with '" + refSeq.getName()
277 + "' is not mappable for the given localFrame sequence. ("
278 + localFrame.getName() + ")");
280 // check the mapping to see if localFrame _lcolumn exists
281 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
294 // TODO - remove ? this may be a redundant check
295 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
296 || (toSeq == null && getHeight() <= _column)))
301 // 2. resolve ranges in matrix corresponding to range in localFrame
302 final int[] matrixRange = toSeq == null
304 { localFrame.getStart(), localFrame.getEnd() }
305 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
308 for (int p = 0; p < matrixRange.length; p += 2)
310 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
312 final int rangeHeight = h;
313 // 3. Construct ContactListImpl instance for just those segments.
315 return new ContactListImpl(new ContactListProviderI()
318 public int getColumn()
324 public int getPosition()
330 public int getContactHeight()
336 public double getContactAt(int mcolumn)
338 if (mcolumn < 0 || mcolumn >= rangeHeight)
342 return getElementAt(_column, locateInRange(mcolumn));
344 // this code maps from mcolumn to localFrame - but that isn't what's
346 // int loccolumn = localFrame.findPosition(mcolumn);
347 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} :
348 // toSeq.locateInTo(loccolumn,loccolumn);
349 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
353 // return getElementAt(_column,lcolumn[0]);
357 public int[] getMappedPositionsFor(int cStart, int cEnd)
359 if (!hasReferenceSeq())
361 return ContactListProviderI.super.getMappedPositionsFor(cStart,
364 // map into segment of matrix being shown
365 int realCstart = locateInRange(cStart);
366 int realCend = locateInRange(cEnd);
368 // TODO account for discontinuities in the mapping
370 int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
371 if (mappedPositions != null)
374 for (int p = 0; p < mappedPositions.length; p++)
376 if (s == -1 && mappedPositions[p] >= localFrame.getStart())
378 s = p; // remember first position within local frame
380 if (e == -1 || mappedPositions[p] <= localFrame.getEnd())
382 // update end pointer
385 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
389 return mappedPositions;
393 * @return the mcolumn'th position in the matrixRange window on the matrix
395 private int locateInRange(int mcolumn)
399 while (h < mcolumn && p + 2 < matrixRange.length)
401 h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]);
404 return matrixRange[p] + mcolumn - h;
407 public Color getColourForGroup()
409 BitSet gp = us.getGroupsFor(_column);
410 Color col = us.getColourForGroup(gp);
417 * get a specific element of the contact matrix in its data-local coordinates
418 * rather than the mapped frame. Implementations are allowed to throw RunTimeExceptions if _column/i are out of bounds
424 protected abstract double getElementAt(int _column, int i);