JAL-4134 support recovery of mapped positions for raw matrix column index in Mappable...
authorJames Procter <j.procter@dundee.ac.uk>
Thu, 18 May 2023 18:44:15 +0000 (19:44 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Thu, 18 May 2023 18:44:15 +0000 (19:44 +0100)
src/jalview/datamodel/ContactListImpl.java
src/jalview/datamodel/ContactListProviderI.java
src/jalview/gui/TreeCanvas.java
src/jalview/ws/datamodel/MappableContactMatrixI.java
src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java

index b71c4b7..bde13ff 100644 (file)
@@ -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();
+  }
 }
index 79703d4..51f3126 100644 (file)
@@ -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;
+  }
+
 }
index 8de161f..9463634 100755 (executable)
@@ -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<BinaryNode> l,
index 052bc2f..d1a5ff7 100644 (file)
@@ -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);
 }
index 27665d4..dc8e0d3 100644 (file)
@@ -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<T extends MappableContactMatrix<T>>
   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<mappedPositions.length;p++)
+//      {
+//        if (s==-1 && mappedPositions[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<T extends MappableContactMatrix<T>>
     // 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<T extends MappableContactMatrix<T>>
     
     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<mappedPositions.length;p++)
+        int[] mappedPositions = toSeq.locateInFrom(realCstart, realCend);
+        if (mappedPositions != null)
+        {
+          int s = -1, e = -1;
+          for (int p = 0; p < mappedPositions.length; p++)
           {
-            if (s==-1 && mappedPositions[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<T extends MappableContactMatrix<T>>
         }
         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;
+      }
     });
   }