JAL-3567 unit tests for linked feature tooltips
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 17 Apr 2020 13:00:10 +0000 (14:00 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 17 Apr 2020 13:00:10 +0000 (14:00 +0100)
src/jalview/datamodel/MappedFeatures.java
src/jalview/io/SequenceAnnotationReport.java
test/jalview/datamodel/SequenceFeatureTest.java
test/jalview/io/SequenceAnnotationReportTest.java

index 520ff92..87609c6 100644 (file)
@@ -29,21 +29,16 @@ public class MappedFeatures
   /*
    * the sequence the mapped features are on
    */
-  private final SequenceI linkedSeq;
+  private final SequenceI featureSequence;
 
   /*
    * the mapping between sequences;
-   * NB this could be in either sense
+   * NB this could be in either sense (from or to featureSequence)
    */
   private final Mapping mapping;
 
   /*
-   * if true, mapping is from the linked sequence, else to the linked sequence
-   */
-  private boolean mappingIsFromLinkedSequence;
-
-  /*
-   * features on linkedSeq that overlap the mapped positions
+   * features on featureSequence that overlap the mapped positions
    */
   public final List<SequenceFeature> features;
 
@@ -70,22 +65,23 @@ public class MappedFeatures
    * Constructor
    * 
    * @param theMapping
-   * @param from
-   *                      the sequence mapped from (e.g. CDS)
+   *          sequence mapping (which may be either to, or from, the sequence
+   *          holding the linked features)
+   * @param featureSeq
+   *          the sequence hosting the virtual features
    * @param pos
-   *                      the residue position in the sequence mapped to
+   *          the residue position in the sequence mapped to
    * @param res
-   *                      the residue character at position pos
+   *          the residue character at position pos
    * @param theFeatures
-   *                      list of mapped features found in the 'from' sequence at
-   *                      the mapped position(s)
+   *          list of mapped features found in the 'featureSeq' sequence at the
+   *          mapped position(s)
    */
-  public MappedFeatures(Mapping theMapping, SequenceI from, int pos,
+  public MappedFeatures(Mapping theMapping, SequenceI featureSeq, int pos,
           char res, List<SequenceFeature> theFeatures)
   {
     mapping = theMapping;
-    linkedSeq = from;
-    mappingIsFromLinkedSequence = mapping.to != linkedSeq;
+    featureSequence = featureSeq;
     toPosition = pos;
     toResidue = res;
     features = theFeatures;
@@ -101,13 +97,13 @@ public class MappedFeatures
     {
       codonPos = codonPositions;
       baseCodon = new char[3];
-      int cdsStart = linkedSeq.getStart();
+      int cdsStart = featureSequence.getStart();
       baseCodon[0] = Character
-              .toUpperCase(linkedSeq.getCharAt(codonPos[0] - cdsStart));
+              .toUpperCase(featureSequence.getCharAt(codonPos[0] - cdsStart));
       baseCodon[1] = Character
-              .toUpperCase(linkedSeq.getCharAt(codonPos[1] - cdsStart));
+              .toUpperCase(featureSequence.getCharAt(codonPos[1] - cdsStart));
       baseCodon[2] = Character
-              .toUpperCase(linkedSeq.getCharAt(codonPos[2] - cdsStart));
+              .toUpperCase(featureSequence.getCharAt(codonPos[2] - cdsStart));
     }
     else
     {
@@ -255,7 +251,7 @@ public class MappedFeatures
    */
   public String getLinkedSequenceName()
   {
-    return linkedSeq == null ? null : linkedSeq.getName();
+    return featureSequence == null ? null : featureSequence.getName();
   }
 
   /**
@@ -278,16 +274,22 @@ public class MappedFeatures
   public int[] getMappedPositions(int begin, int end)
   {
     MapList map = mapping.getMap();
-    return mappingIsFromLinkedSequence ? map.locateInTo(begin, end)
-            : map.locateInFrom(begin, end);
+    return mapping.to == featureSequence ? map.locateInFrom(begin, end)
+            : map.locateInTo(begin, end);
   }
 
+  /**
+   * Answers true if the linked features are on coding sequence, false if on
+   * peptide
+   * 
+   * @return
+   */
   public boolean isFromCds()
   {
     if (mapping.getMap().getFromRatio() == 3)
     {
-      return mappingIsFromLinkedSequence;
+      return mapping.to != featureSequence;
     }
-    return !mappingIsFromLinkedSequence;
+    return mapping.to == featureSequence;
   }
 }
index 8328e7a..27c1652 100644 (file)
@@ -216,6 +216,11 @@ public class SequenceAnnotationReport
     {
       beginRange = mf.getMappedPositions(begin, begin);
       endRange = mf.getMappedPositions(end, end);
+      if (beginRange == null || endRange == null)
+      {
+        // something went wrong
+        return false;
+      }
       begin = beginRange[0];
       end = endRange[endRange.length - 1];
     }
index e105659..b4848a5 100644 (file)
@@ -336,7 +336,7 @@ public class SequenceFeatureTest
     SequenceI seq = new Sequence("TestSeq/8-14", "PLRFQMD");
     MapList map = new MapList(new int[] { 101, 118 }, new int[] { 8, 13 },
             3, 1);
-    Mapping mapping = new Mapping(seq.getDatasetSequence(), map);
+    Mapping mapping = new Mapping(seq, map);
     List<SequenceFeature> features = new ArrayList<>();
     // vary ttg (Leu) to ttc (Phe)
     SequenceFeature sf = new SequenceFeature("variant", "G,C", 106, 106,
index 7e00caa..772ed2b 100644 (file)
@@ -33,6 +33,8 @@ import org.testng.annotations.Test;
 
 import jalview.api.FeatureColourI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.MappedFeatures;
+import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
@@ -40,6 +42,7 @@ import jalview.gui.JvOptionPane;
 import jalview.io.gff.GffConstants;
 import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.schemes.FeatureColour;
+import jalview.util.MapList;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 import junit.extensions.PA;
 
@@ -423,4 +426,63 @@ public class SequenceAnnotationReportTest
             .endsWith(
                     "<br/>PDB7 3iu1<br/>PDB8,...<br/>(Output Sequence Details to list all database references)</i>"));
   }
+
+  /**
+   * Test adding a linked feature to the tooltip
+   */
+  @Test(groups = "Functional")
+  public void testAppendFeature_virtualFeature()
+  {
+    /*
+     * map CDS to peptide sequence
+     */
+    SequenceI cds = new Sequence("Cds/101-121", "CCTttgAGAtttCAAatgGAT");
+    SequenceI peptide = new Sequence("Peptide/8-14", "PLRFQMD");
+    MapList map = new MapList(new int[] { 101, 118 }, new int[] { 8, 13 },
+            3, 1);
+    Mapping mapping = new Mapping(peptide, map);
+
+    /*
+     * assume variant feature found at CDS position 106 G>C
+     */
+    List<SequenceFeature> features = new ArrayList<>();
+    // vary ttg (Leu) to ttc (Phe)
+    SequenceFeature sf = new SequenceFeature("variant", "G,C", 106, 106,
+            Float.NaN, null);
+    features.add(sf);
+    MappedFeatures mf = new MappedFeatures(mapping, cds, 9, 'L', features);
+
+    StringBuilder sb = new StringBuilder();
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
+    sar.appendFeature(sb, 1, null, sf, mf, 0);
+
+    /*
+     * linked feature shown in tooltip in protein coordinates
+     */
+    assertEquals("variant 9; G,C", sb.toString());
+
+    /*
+     * adding "alleles" attribute to variant allows peptide consequence
+     * to be calculated and added to the tooltip
+     */
+    sf.setValue("alleles", "G,C");
+    sb = new StringBuilder();
+    sar.appendFeature(sb, 1, null, sf, mf, 0);
+    assertEquals("variant 9; G,C p.Leu9Phe", sb.toString());
+
+    /*
+     * now a virtual peptide feature on CDS
+     * feature at 11-12 on peptide maps to 110-115 on CDS
+     * here we test for tooltip at 113 (t)
+     */
+    SequenceFeature sf2 = new SequenceFeature("metal", "Fe", 11, 12,
+            2.3f, "Uniprot");
+    features.clear();
+    features.add(sf2);
+    mapping = new Mapping(peptide, map);
+    mf = new MappedFeatures(mapping, peptide, 113, 't', features);
+    sb = new StringBuilder();
+    sar.appendFeature(sb, 1, null, sf2, mf, 0);
+    assertEquals("metal 110 115; Fe Score=2.3", sb.toString());
+  }
 }