From 8288438dd58cfc2d1fe18a060afda0d647b85c32 Mon Sep 17 00:00:00 2001 From: James Procter Date: Thu, 18 May 2023 19:44:15 +0100 Subject: [PATCH] JAL-4134 support recovery of mapped positions for raw matrix column index in MappableContactMatrixI --- src/jalview/datamodel/ContactListImpl.java | 7 + src/jalview/datamodel/ContactListProviderI.java | 6 + src/jalview/gui/TreeCanvas.java | 78 +++++++--- .../ws/datamodel/MappableContactMatrixI.java | 13 +- .../datamodel/alphafold/MappableContactMatrix.java | 162 +++++++++++++++----- 5 files changed, 208 insertions(+), 58 deletions(-) diff --git a/src/jalview/datamodel/ContactListImpl.java b/src/jalview/datamodel/ContactListImpl.java index b71c4b7..bde13ff 100644 --- a/src/jalview/datamodel/ContactListImpl.java +++ b/src/jalview/datamodel/ContactListImpl.java @@ -1,5 +1,7 @@ package jalview.datamodel; +import java.awt.Color; + import jalview.renderer.ContactGeometry.contactInterval; /** @@ -101,4 +103,9 @@ public class ContactListImpl implements ContactListI { return clist.getMappedPositionsFor(cStart, cEnd); } + @Override + public Color getColourForGroup() + { + return clist.getColourForGroup(); + } } diff --git a/src/jalview/datamodel/ContactListProviderI.java b/src/jalview/datamodel/ContactListProviderI.java index 79703d4..51f3126 100644 --- a/src/jalview/datamodel/ContactListProviderI.java +++ b/src/jalview/datamodel/ContactListProviderI.java @@ -1,5 +1,7 @@ package jalview.datamodel; +import java.awt.Color; + public interface ContactListProviderI { @@ -37,4 +39,8 @@ public interface ContactListProviderI return new int[] { cStart, cEnd}; } + default Color getColourForGroup() { + return null; + } + } diff --git a/src/jalview/gui/TreeCanvas.java b/src/jalview/gui/TreeCanvas.java index 8de161f..9463634 100755 --- a/src/jalview/gui/TreeCanvas.java +++ b/src/jalview/gui/TreeCanvas.java @@ -68,6 +68,7 @@ import jalview.schemes.ColourSchemeI; import jalview.structure.SelectionSource; import jalview.util.Format; import jalview.util.MessageManager; +import jalview.ws.datamodel.MappableContactMatrixI; /** * DOCUMENT ME! @@ -1032,12 +1033,28 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, // stash colors in linked annotation row. // doesn't work yet. TESTS! int sstart=aa.sequenceRef!=null ? aa.sequenceRef.getStart()-1 : 0; + Annotation ae; + Color gpcol = null; + int[] seqpos=null; for (BitSet gp : colors.keySet()) { - Color gpcol = colors.get(gp); - for (int p = gp.nextSetBit(0); p >= 0; p = gp.nextSetBit(p + 1)) + gpcol = colors.get(gp); + for (int p = gp.nextSetBit(0); p >= 0 && p < Integer.MAX_VALUE; p = gp.nextSetBit(p + 1)) { - Annotation ae = aa.getAnnotationForPosition(p+sstart); + if (cm instanceof MappableContactMatrixI) + { + MappableContactMatrixI mcm = (MappableContactMatrixI) cm; + seqpos = mcm.getMappedPositionsFor(aa.sequenceRef,p); + if (seqpos==null) + { + // no mapping for this column. + continue; + } + // TODO: handle ranges... + ae = aa.getAnnotationForPosition(seqpos[0]); + } else { + ae = aa.getAnnotationForPosition(p+sstart); + } if (ae != null) { ae.colour = gpcol.brighter().darker(); @@ -1124,37 +1141,60 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, Color col) { SequenceI rseq = tp.assocAnnotation.sequenceRef; - if (av==null||av.getAlignment()==null) + + if (av == null || av.getAlignment() == null) { // alignment is closed return; } - for (BinaryNode bn:l) + for (BinaryNode bn : l) { - int colm=-1; - try { - colm = Integer.parseInt(bn.getName().substring(bn.getName().indexOf("c")+1)); + int colm = -1; + try + { + colm = Integer.parseInt( + bn.getName().substring(bn.getName().indexOf("c") + 1)); } catch (Exception e) { continue; } + // TODO - sort indices for faster lookup + ColumnSelection cs = av.getColumnSelection(); HiddenColumns hc = av.getAlignment().getHiddenColumns(); + ContactMatrixI cm = av.getContactMatrix(tp.assocAnnotation); + MappableContactMatrixI mcm = null; + int offp; + if (cm instanceof MappableContactMatrixI) { - int offp = (rseq!=null) ? rseq.findIndex(rseq.getStart()+colm) : colm; - - if (!av.hasHiddenColumns() || hc.isVisible(offp-1)) - { - if (cs.contains(offp-1)) - { - cs.removeElement(offp-1); - } else { - cs.addElement(offp-1); - } + mcm = (MappableContactMatrixI) cm; + int[] seqpos = mcm.getMappedPositionsFor(tp.assocAnnotation.sequenceRef,colm); + if (seqpos==null) + { + // no mapping for this column. + continue; + } + // TODO: handle ranges... + offp=seqpos[0]; + } + else + { + offp = (rseq != null) ? rseq.findIndex(rseq.getStart() + colm) + : colm; + } + if (!av.hasHiddenColumns() || hc.isVisible(offp - 1)) + { + if (cs.contains(offp - 1)) + { + cs.removeElement(offp - 1); + } + else + { + cs.addElement(offp - 1); } } - } + } } public void createSeqGroupFor(AlignmentPanel[] aps, Vector l, diff --git a/src/jalview/ws/datamodel/MappableContactMatrixI.java b/src/jalview/ws/datamodel/MappableContactMatrixI.java index 052bc2f..d1a5ff7 100644 --- a/src/jalview/ws/datamodel/MappableContactMatrixI.java +++ b/src/jalview/ws/datamodel/MappableContactMatrixI.java @@ -38,5 +38,16 @@ public interface MappableContactMatrixI extends ContactMatrixI * */ MapList getMapFor(SequenceI sequenceRef); - + + /** + * Locate a position in the mapped sequence for a column in the matrix - use + * this to resolve positions corresponding to column clusters + * + * @param localFrame + * - sequence derivced from reference sequence + * @param column + * - matrix row/column + * @return sequence position(s) corresponding to column in contact matrix + */ + int[] getMappedPositionsFor(SequenceI localFrame, int column); } diff --git a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java index 27665d4..dc8e0d3 100644 --- a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java +++ b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java @@ -1,6 +1,8 @@ package jalview.ws.datamodel.alphafold; +import java.awt.Color; import java.util.ArrayList; +import java.util.BitSet; import jalview.datamodel.ContactListI; import jalview.datamodel.ContactListImpl; @@ -164,6 +166,77 @@ public abstract class MappableContactMatrix> protected abstract T newMappableContactMatrix(SequenceI newRefSeq, MapList newFromMapList); @Override + public int[] getMappedPositionsFor(final SequenceI localFrame, + final int column) + { + return getMappedPositionsFor(localFrame,column,column); + } + public int[] getMappedPositionsFor(final SequenceI localFrame, + int from,int to) + { + if (localFrame==null) + { + throw new Error("Unimplemented when no local sequence given."); + } + // return a ContactListI for column + // column is index into localFrame + // 1. map column to corresponding column in matrix + + final int _lcolumn=localFrame.findPosition(from); + final int _rcolumn=(from==to) ? _lcolumn:localFrame.findPosition(to); + if (toSeq == null) + { + // no mapping + return new int[] { _lcolumn,_rcolumn}; + } + + SequenceI lf = localFrame, uf = refSeq; + + // just look for dataset sequences and check they are the same. + // in future we could use DBRefMappings/whatever. + while (lf.getDatasetSequence() != null + || uf.getDatasetSequence() != null) + { + if (lf.getDatasetSequence() != null) + { + lf = lf.getDatasetSequence(); + } + if (uf.getDatasetSequence() != null) + { + uf = uf.getDatasetSequence(); + } + } + if (lf != uf) + { + // could try harder to find a mapping + throw new Error("This Matrix associated with '" + refSeq.getName() + + "' is not mappable for the given localFrame sequence. (" + + localFrame.getName() + ")"); + } + + int[] mappedPositions = toSeq.locateInFrom(_lcolumn,_rcolumn); + // TODO - trim to localFrame ? +// if (mappedPositions!=null) { +// int s=-1,e=-1; +// for (int p=0;p=localFrame.getStart()) +// { +// s=p; // remember first position within local frame +// } +// if (e==-1 || mappedPositions[p]<=localFrame.getEnd()) +// { +// // update end pointer +// e=p; +// // compute local map +// mappedPositions[p] = localFrame.findIndex(mappedPositions[p]); +// } +// } +// } + return mappedPositions; + } + + @Override public ContactListI getMappableContactList(final SequenceI localFrame, final int column) { @@ -176,7 +249,7 @@ public abstract class MappableContactMatrix> // return a ContactListI for column // column is index into localFrame // 1. map column to corresponding column in matrix - + final MappableContactMatrix us=this; _lcolumn=localFrame.findPosition(column); if (toSeq != null) @@ -241,82 +314,73 @@ public abstract class MappableContactMatrix> return new ContactListImpl(new ContactListProviderI() { - + public int getColumn() { return column; } + @Override public int getPosition() { return _column; } - + @Override public int getContactHeight() { return rangeHeight; } - + @Override public double getContactAt(int mcolumn) { - if (mcolumn<0 || mcolumn>=rangeHeight) + if (mcolumn < 0 || mcolumn >= rangeHeight) { return -1; } return getElementAt(_column, locateInRange(mcolumn)); - - // this code maps from mcolumn to localFrame - but that isn't what's needed -// int loccolumn = localFrame.findPosition(mcolumn); -// int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : toSeq.locateInTo(loccolumn,loccolumn); -// if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight) -// { -// return -1; -// } -// return getElementAt(_column,lcolumn[0]); - } - /** - * @return the mcolumn'th position in the matrixRange window on the matrix - */ - private int locateInRange(int mcolumn) - { - int h=0,p=0; - while (h < mcolumn && p+2 < matrixRange.length) - { - h += 1+Math.abs(matrixRange[p + 1] - matrixRange[p]); - p+=2; - } - return matrixRange[p]+mcolumn-h; + // this code maps from mcolumn to localFrame - but that isn't what's + // needed + // int loccolumn = localFrame.findPosition(mcolumn); + // int[] lcolumn=(toSeq==null) ? new int[] {mcolumn} : + // toSeq.locateInTo(loccolumn,loccolumn); + // if (lcolumn==null || lcolumn[0] < 0 || lcolumn[0] >= rangeHeight) + // { + // return -1; + // } + // return getElementAt(_column,lcolumn[0]); } - + @Override public int[] getMappedPositionsFor(int cStart, int cEnd) { if (!hasReferenceSeq()) { - return ContactListProviderI.super.getMappedPositionsFor(cStart, cEnd); + return ContactListProviderI.super.getMappedPositionsFor(cStart, + cEnd); } // map into segment of matrix being shown int realCstart = locateInRange(cStart); int realCend = locateInRange(cEnd); - + // TODO account for discontinuities in the mapping - int[] mappedPositions = toSeq.locateInFrom(realCstart,realCend); - if (mappedPositions!=null) { - int s=-1,e=-1; - for (int p=0;p=localFrame.getStart()) + if (s == -1 && mappedPositions[p] >= localFrame.getStart()) { - s=p; // remember first position within local frame + s = p; // remember first position within local frame } - if (e==-1 || mappedPositions[p]<=localFrame.getEnd()) + if (e == -1 || mappedPositions[p] <= localFrame.getEnd()) { // update end pointer - e=p; + e = p; // compute local map mappedPositions[p] = localFrame.findIndex(mappedPositions[p]); } @@ -324,6 +388,28 @@ public abstract class MappableContactMatrix> } return mappedPositions; } + + /** + * @return the mcolumn'th position in the matrixRange window on the matrix + */ + private int locateInRange(int mcolumn) + { + + int h = 0, p = 0; + while (h < mcolumn && p + 2 < matrixRange.length) + { + h += 1 + Math.abs(matrixRange[p + 1] - matrixRange[p]); + p += 2; + } + return matrixRange[p] + mcolumn - h; + } + @Override + public Color getColourForGroup() + { + BitSet gp = us.getGroupsFor(_column); + Color col = us.getColourForGroup(gp); + return col; + } }); } -- 1.7.10.2