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.GroupSet;
9 import jalview.datamodel.GroupSetI;
10 import jalview.datamodel.Mapping;
11 import jalview.datamodel.SequenceI;
12 import jalview.util.MapList;
13 import jalview.ws.datamodel.MappableContactMatrixI;
15 public abstract class MappableContactMatrix<T extends MappableContactMatrix<T>> implements MappableContactMatrixI
17 SequenceI refSeq = null;
21 * the length that refSeq is expected to be (excluding gaps, of course)
27 public boolean hasReferenceSeq()
29 return (refSeq != null);
33 public SequenceI getReferenceSeq()
38 * container for groups - defined on matrix columns
40 GroupSet grps=new GroupSet();
42 public GroupSetI getGroupSet()
47 public void setGroupSet(GroupSet makeGroups)
53 public MapList getMapFor(SequenceI mapSeq)
57 while (mapSeq!=refSeq && mapSeq.getDatasetSequence()!=null)
59 mapSeq = mapSeq.getDatasetSequence();
67 // our MapList does not concern this seq
76 * set the reference sequence and construct the mapping between the start-end positions of given sequence and row/columns of contact matrix
79 public void setRefSeq(SequenceI _refSeq)
82 while (refSeq.getDatasetSequence() != null)
84 refSeq = refSeq.getDatasetSequence();
86 length = _refSeq.getEnd() - _refSeq.getStart() + 1;
87 // if (length!=refSeq.getLength() || _refSeq.getStart()!=1)
89 toSeq = new MapList(new int[] { _refSeq.getStart(), _refSeq.getEnd()}, new int[] { 0,length-1}, 1,1);
93 public T liftOver(SequenceI newRefSeq, Mapping sp2sq)
95 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
97 // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
98 // Protein reference frames
100 "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
102 boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == refSeq) : false;
105 * map from matrix to toSeq's coordinate frame
107 int[] refMap = toSeq.locateInFrom(0, length - 1);
108 ArrayList<Integer> newFromMap = new ArrayList<Integer>();
110 for (int i = 0; i < refMap.length; i += 2)
113 * for each contiguous range in toSeq, locate corresponding range in sequence mapped to toSeq by sp2sq
115 int[] sp2map = mapIsTo
116 ? sp2sq.getMap().locateInFrom(refMap[i], refMap[i + 1])
117 : sp2sq.getMap().locateInTo(refMap[i], refMap[i + 1]);
123 for (int spm = 0; spm < sp2map.length; spm += 2)
128 if (sp2map[spm] != last + 1)
130 newFromMap.add(sp2map[spm]);
134 newFromMap.remove(newFromMap.size() - 1);
139 newFromMap.add(sp2map[spm]);
141 last = sp2map[spm + 1];
142 newFromMap.add(last);
145 if ((newFromMap.size() % 2) != 0)
147 // should have had an even number of int ranges!
148 throw new Error("PAEMatrix liftover failed.");
150 int fromIntMap[] = new int[newFromMap.size()];
152 for (Integer i : newFromMap)
154 fromIntMap[ipos++] = i;
156 MapList newFromMapList = new MapList(fromIntMap,
158 { 0, length - 1 }, 1, 1);
160 T newCM = newMappableContactMatrix(newRefSeq, newFromMapList);
164 protected abstract T newMappableContactMatrix(SequenceI newRefSeq,
165 MapList newFromMapList);
167 public ContactListI getMappableContactList(final SequenceI localFrame,
172 if (localFrame==null)
174 throw new Error("Unimplemented when no local sequence given.");
176 // return a ContactListI for column
177 // column is index into localFrame
178 // 1. map column to corresponding column in matrix
180 _lcolumn=localFrame.findPosition(column);
184 SequenceI lf = localFrame, uf = refSeq;
186 // just look for dataset sequences and check they are the same.
187 // in future we could use DBRefMappings/whatever.
188 while (lf.getDatasetSequence() != null
189 || uf.getDatasetSequence() != null)
191 if (lf.getDatasetSequence() != null)
193 lf = lf.getDatasetSequence();
195 if (uf.getDatasetSequence() != null)
197 uf = uf.getDatasetSequence();
202 // could try harder to find a mapping
203 throw new Error("This Matrix associated with '" + refSeq.getName()
204 + "' is not mappable for the given localFrame sequence. ("
205 + localFrame.getName() + ")");
207 // check the mapping to see if localFrame _lcolumn exists
208 int[] word = toSeq.locateInTo(_lcolumn, _lcolumn);
221 // TODO - remove ? this may be a redundant check
222 if (_column < 0 || ((toSeq != null && _column > toSeq.getToHighest())
223 || (toSeq == null && getHeight() <= _column)))
228 // 2. resolve ranges in matrix corresponding to range in localFrame
229 final int[] matrixRange = toSeq == null
231 { localFrame.getStart(), localFrame.getEnd() }
232 : toSeq.locateInTo(localFrame.getStart(), localFrame.getEnd());
235 for (int p = 0; p < matrixRange.length; p += 2)
237 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
239 final int rangeHeight = h;
240 // 3. Construct ContactListImpl instance for just those segments.
242 return new ContactListImpl(new ContactListProviderI()
245 public int getColumn()
250 public int getPosition()
256 public int getContactHeight()
262 public double getContactAt(int mcolumn)
264 if (mcolumn<0 || mcolumn>=rangeHeight)
268 return getElementAt(_column, locateInRange(mcolumn));
270 // this code maps from mcolumn to localFrame - but that isn't what's needed
271 // int loccolumn = localFrame.findPosition(mcolumn);
272 // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : toSeq.locateInTo(loccolumn,loccolumn);
273 // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight)
277 // return getElementAt(_column,lcolumn[0]);
280 * @return the mcolumn'th position in the matrixRange window on the matrix
282 private int locateInRange(int mcolumn)
286 while (h < mcolumn && p+2 < matrixRange.length)
288 h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]);
291 return matrixRange[p]+mcolumn-h;
295 public int[] getMappedPositionsFor(int cStart, int cEnd)
297 if (!hasReferenceSeq())
299 return ContactListProviderI.super.getMappedPositionsFor(cStart, cEnd);
301 // map into segment of matrix being shown
302 int realCstart = locateInRange(cStart);
303 int realCend = locateInRange(cEnd);
305 // TODO account for discontinuities in the mapping
307 int[] mappedPositions = toSeq.locateInFrom(realCstart,realCend);
308 if (mappedPositions!=null) {
310 for (int p=0;p<mappedPositions.length;p++)
312 if (s==-1 && mappedPositions[p]>=localFrame.getStart())
314 s=p; // remember first position within local frame
316 if (e==-1 || mappedPositions[p]<=localFrame.getEnd())
318 // update end pointer
321 mappedPositions[p] = localFrame.findIndex(mappedPositions[p]);
325 return mappedPositions;
331 * get a specific element of the contact matrix in its data-local coordinates
332 * rather than the mapped frame. Implementations are allowed to throw RunTimeExceptions if _column/i are out of bounds
338 protected abstract double getElementAt(int _column, int i);