1 package jalview.ws.datamodel.alphafold;
3 import java.util.ArrayList;
5 import jalview.datamodel.ContactListI;
6 import jalview.datamodel.ContactListImpl;
7 import jalview.datamodel.ContactListProviderI;
8 import jalview.datamodel.Mapping;
9 import jalview.datamodel.SequenceI;
10 import jalview.util.MapList;
11 import jalview.ws.datamodel.MappableContactMatrixI;
13 public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>> implements MappableContactMatrixI
15 SequenceI refSeq = null;
19 * the length that refSeq is expected to be (excluding gaps, of course)
25 public boolean hasReferenceSeq()
27 return (refSeq != null);
31 public SequenceI getReferenceSeq()
36 public MapList getMapFor(SequenceI mapSeq)
40 while (mapSeq!=refSeq && mapSeq.getDatasetSequence()!=null)
42 mapSeq = mapSeq.getDatasetSequence();
50 // our MapList does not concern this seq
58 protected void setRefSeq(SequenceI _refSeq)
61 while (refSeq.getDatasetSequence() != null)
63 refSeq = refSeq.getDatasetSequence();
65 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
66 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
68 toSeq = new MapList(new int[] { _refSeq.getStart(), _refSeq.getEnd()}, new int[] { 0,length-1}, 1,1);
72 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
74 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
76 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
77 // Protein reference frames
79 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
81 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
84 * map from matrix to toSeq's coordinate frame
86 int[] refMap = toSeq.locateInFrom(0, length - 1);
87 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
89 for (int i = 0; i < refMap.length; i += 2)
92 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
94 int[] sp2map = mapIsTo
95 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
96 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
102 for (int spm = 0; spm < sp2map.length; spm += 2)
107 if (sp2map[spm] != last + 1)
109 newFromMap.add(sp2map[spm]);
113 newFromMap.remove(newFromMap.size() - 1);
118 newFromMap.add(sp2map[spm]);
120 last = sp2map[spm + 1];
121 newFromMap.add(last);
124 if ((newFromMap.size() % 2) != 0)
126 // should have had an even number of int ranges!
127 throw new Error("PAEMatrix liftover failed.");
129 int fromIntMap[] = new int[newFromMap.size()];
131 for (Integer i : newFromMap)
133 fromIntMap[ipos++] = i;
135 MapList newFromMapList = new MapList(fromIntMap,
137 { 0, length - 1 }, 1, 1);
139 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
143 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
144 MapList newFromMapList);
146 public ContactListI getMappableContactList(final SequenceI localFrame,
151 if (localFrame==null)
153 throw new Error("Unimplemented when no local sequence given.");
155 // return a ContactListI for column
156 // column is index into localFrame
157 // 1. map column to corresponding column in matrix
159 _lcolumn=localFrame.findPosition(column);
163 SequenceI lf = localFrame, uf = refSeq;
165 // just look for dataset sequences and check they are the same.
166 // in future we could use DBRefMappings/whatever.
167 while (lf.getDatasetSequence() != null
168 || uf.getDatasetSequence() != null)
170 if (lf.getDatasetSequence() != null)
172 lf = lf.getDatasetSequence();
174 if (uf.getDatasetSequence() != null)
176 uf = uf.getDatasetSequence();
181 // could try harder to find a mapping
182 throw new Error("This Matrix associated with '" + refSeq.getName()
183 + "' is not mappable for the given localFrame sequence. ("
184 + localFrame.getName() + ")");
186 // check the mapping to see if localFrame _lcolumn exists
187 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
200 // TODO - remove ? this may be a redundant check
201 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
202 || (toSeq == null && getHeight() <= _column)))
207 // 2. resolve ranges in matrix corresponding to range in localFrame
208 final int[] matrixRange = toSeq == null
210 { localFrame.getStart(), localFrame.getEnd() }
211 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
214 for (int p = 0; p < matrixRange.length; p += 2)
216 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
218 final int rangeHeight = h;
219 // 3. Construct ContactListImpl instance for just those segments.
221 return new ContactListImpl(new ContactListProviderI()
224 public int getColumn()
229 public int getPosition()
235 public int getContactHeight()
241 public double getContactAt(int mcolumn)
243 if (mcolumn<0 || mcolumn>=rangeHeight)
247 return getElementAt(_column, locateInRange(mcolumn));
249 // this code maps from mcolumn to localFrame - but that isn't what's needed
250 // int loccolumn = localFrame.findPosition(mcolumn);
251 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : toSeq.locateInTo(loccolumn,loccolumn);
252 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
256 // return getElementAt(_column,lcolumn[0]);
259 * @return the mcolumn'th position in the matrixRange window on the matrix
261 private int locateInRange(int mcolumn)
265 while (h < mcolumn && p+2 < matrixRange.length)
267 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
270 return matrixRange[p]+mcolumn-h;
274 public int[] getMappedPositionsFor(int cStart, int cEnd)
276 if (!hasReferenceSeq())
278 return ContactListProviderI.super.getMappedPositionsFor(cStart, cEnd);
280 // map into segment of matrix being shown
281 int realCstart = locateInRange(cStart);
282 int realCend = locateInRange(cEnd);
284 // TODO account for discontinuities in the mapping
286 int[] mappedPositions = toSeq.locateInFrom(realCstart,realCend);
287 if (mappedPositions!=null) {
289 for (int p=0;p<mappedPositions.length;p++)
291 if (s==-1 && mappedPositions[p]>=localFrame.getStart())
293 s=p; // remember first position within local frame
295 if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
297 // update end pointer
300 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
304 return mappedPositions;
310 * get a specific element of the contact matrix in its data-local coordinates
311 * rather than the mapped frame. Implementations are allowed to throw RunTimeExceptions if _column/i are out of bounds
317 protected abstract double getElementAt(int _column, int i);