From f6fc5e76b8b7695512b2357667a6b9c95a3d4edb Mon Sep 17 00:00:00 2001
From: tjc <tjc@ee4ac58c-ac51-4696-9907-e4b3aa274f04>
Date: Wed, 21 Jul 2010 15:47:46 +0000
Subject: [PATCH] initial code for identifying synonymous / non-synonymous
 change

git-svn-id: svn+ssh://svn.internal.sanger.ac.uk/repos/svn/pathsoft/artemis/trunk@14274 ee4ac58c-ac51-4696-9907-e4b3aa274f04
---
 .../artemis/components/variant/VCFview.java   | 216 ++++++++++++++++--
 1 file changed, 193 insertions(+), 23 deletions(-)

diff --git a/uk/ac/sanger/artemis/components/variant/VCFview.java b/uk/ac/sanger/artemis/components/variant/VCFview.java
index afa338e39..e2eea2444 100644
--- a/uk/ac/sanger/artemis/components/variant/VCFview.java
+++ b/uk/ac/sanger/artemis/components/variant/VCFview.java
@@ -49,6 +49,7 @@ import java.util.List;
 import java.util.Vector;
 
 import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JFrame;
@@ -68,6 +69,11 @@ import org.apache.log4j.Level;
 
 import uk.ac.sanger.artemis.Entry;
 import uk.ac.sanger.artemis.EntryGroup;
+import uk.ac.sanger.artemis.Feature;
+import uk.ac.sanger.artemis.FeatureKeyPredicate;
+import uk.ac.sanger.artemis.FeatureSegment;
+import uk.ac.sanger.artemis.FeatureSegmentVector;
+import uk.ac.sanger.artemis.FeatureVector;
 import uk.ac.sanger.artemis.Options;
 import uk.ac.sanger.artemis.Selection;
 import uk.ac.sanger.artemis.SelectionChangeEvent;
@@ -89,6 +95,7 @@ import uk.ac.sanger.artemis.io.Location;
 import uk.ac.sanger.artemis.io.Qualifier;
 import uk.ac.sanger.artemis.io.QualifierVector;
 import uk.ac.sanger.artemis.io.Range;
+import uk.ac.sanger.artemis.sequence.AminoAcidSequence;
 import uk.ac.sanger.artemis.sequence.Bases;
 import uk.ac.sanger.artemis.sequence.MarkerRange;
 import uk.ac.sanger.artemis.sequence.NoSequenceException;
@@ -109,7 +116,7 @@ public class VCFview extends JPanel
   private Selection selection;
   private int nbasesInView;
   private int seqLength;
-  private Bases bases;
+  private EntryGroup entryGroup;
   private String chr;
   private String mouseOverVCFline;
   private int mouseOverIndex = -1;
@@ -117,6 +124,11 @@ public class VCFview extends JPanel
   private int dragStart = -1;
   private JPopupMenu popup;
   private int LINE_HEIGHT = 15;
+  
+  private boolean showSynonymous = true;
+  private boolean showNonSynonymous = true;
+  private boolean showDeletions = true;
+  private boolean showInsertions = true;
 
   public VCFview(final JFrame frame,
                  final JPanel vcfPanel,
@@ -142,11 +154,11 @@ public class VCFview extends JPanel
         (vcfFiles.size()+1)*(LINE_HEIGHT+5)));
     
     if(feature_display != null)
-      this.bases = feature_display.getBases();
+      this.entryGroup = feature_display.getEntryGroup();
     else if(reference != null)
-      this.bases = getReference(reference).getSequenceEntry().getBases();
-    if(bases != null)
-      this.seqLength = bases.getLength();
+      this.entryGroup = getReference(reference);
+    if(entryGroup != null)
+      this.seqLength = entryGroup.getSequenceEntry().getBases().getLength();
     
     try
     {
@@ -312,6 +324,53 @@ public class VCFview extends JPanel
       }
     });
     topPanel.add(combo);
+    
+    // popup menu
+    popup = new JPopupMenu();
+    final JCheckBoxMenuItem showSyn = new JCheckBoxMenuItem(
+        "Show synonymous", showSynonymous);
+    showSyn.addActionListener(new ActionListener(){
+      public void actionPerformed(ActionEvent e)
+      {
+        showSynonymous = showSyn.isSelected();
+        repaint();
+      }
+    });
+    popup.add(showSyn);
+    
+    final JCheckBoxMenuItem showNonSyn = new JCheckBoxMenuItem(
+        "Show non-synonymous", showNonSynonymous);
+    showNonSyn.addActionListener(new ActionListener(){
+      public void actionPerformed(ActionEvent e)
+      {
+        showNonSynonymous = showNonSyn.isSelected();
+        repaint();
+      }
+    });
+    popup.add(showNonSyn);
+    
+    
+    final JCheckBoxMenuItem showDeletionsMenu = new JCheckBoxMenuItem(
+        "Show deletions", showDeletions);
+    showDeletionsMenu.addActionListener(new ActionListener(){
+      public void actionPerformed(ActionEvent e)
+      {
+        showDeletions = showDeletionsMenu.isSelected();
+        repaint();
+      }
+    });
+    popup.add(showDeletionsMenu);
+    
+    final JCheckBoxMenuItem showInsertionsMenu = new JCheckBoxMenuItem(
+        "Show insertions", showInsertions);
+    showInsertionsMenu.addActionListener(new ActionListener(){
+      public void actionPerformed(ActionEvent e)
+      {
+        showInsertions = showInsertionsMenu.isSelected();
+        repaint();
+      }
+    });
+    popup.add(showInsertionsMenu);
   }
   
   private static EntryGroup getReference(String reference)
@@ -435,6 +494,9 @@ public class VCFview extends JPanel
     String region = chr+":"+start+"-"+end;
        
     drawSelectionRange((Graphics2D)g, pixPerBase, start, end);
+ 
+    FeatureVector features = getCDSFeaturesInRange(start, end);
+    
     // a region is specified; random access
     for (int i = 0; i < tr.length; i++)
     {
@@ -445,7 +507,7 @@ public class VCFview extends JPanel
       {
         while ((s = iter.next()) != null)
         {
-          drawVariantCall(g, s, start, i, pixPerBase);
+          drawVariantCall(g, s, start, i, pixPerBase, features);
         }
       }
       catch (IOException e)
@@ -459,6 +521,31 @@ public class VCFview extends JPanel
       drawScale((Graphics2D)g, start, end, pixPerBase, getHeight());
   }
   
+  private FeatureVector getCDSFeaturesInRange(int start, int end)
+  {
+    try
+    {
+      Range range = new Range(start, end);
+      FeatureVector features = entryGroup.getFeaturesInRange(range);
+           
+      FeatureKeyPredicate predicate = new FeatureKeyPredicate(Key.CDS);
+      final FeatureVector cdsFeatures = new FeatureVector();
+
+      for(int i=0; i<features.size(); i++)
+      {
+        final Feature this_feature = features.elementAt(i);
+        if(predicate.testPredicate(this_feature))
+          cdsFeatures.add(this_feature);
+      }
+      return cdsFeatures;
+    }
+    catch (OutOfRangeException e1)
+    {
+      e1.printStackTrace();
+    }
+    return null;
+  }
+  
   /**
    * Highlight a selected range
    * @param g2
@@ -502,10 +589,27 @@ public class VCFview extends JPanel
       return scrollBar.getValue();
   }
   
-  private void drawVariantCall(Graphics g, String line, int start, int index, float pixPerBase)
+  private void drawVariantCall(Graphics g, String line, int start, int index, float pixPerBase, FeatureVector features)
   {
     String parts[] = line.split("\\t");
-    int pos[] = getScreenPosition(line, pixPerBase, start, index);
+    
+    if(!showDeletions && parts[4].indexOf("D")>-1)
+      return;
+    
+    if(!showInsertions && parts[4].indexOf("I")>-1)
+      return;
+    
+    if(!showSynonymous || !showNonSynonymous)
+    {
+      boolean isSyn = isSynonymous(features, 
+          Integer.parseInt(parts[1]),parts[4].toLowerCase().charAt(0));
+      
+      if( (!showSynonymous && isSyn) ||
+          (!showNonSynonymous && !isSyn) )
+        return;
+    }
+    
+    int pos[] = getScreenPosition(parts[1], pixPerBase, start, index);
     
     if(parts[4].equals("C"))
       g.setColor(Color.red);
@@ -516,16 +620,87 @@ public class VCFview extends JPanel
     else if(parts[4].equals("T"))
       g.setColor(Color.black);
     else
-      g.setColor(Color.yellow);
-
+    {
+      if(parts[4].startsWith("D"))
+        g.setColor(Color.gray);
+      else
+        g.setColor(Color.yellow);
+    }
+    
     g.drawLine(pos[0], pos[1], pos[0], pos[1]-LINE_HEIGHT);
   }
   
-  private int[] getScreenPosition(String line, float pixPerBase, int start, int vcfFileIndex)
+  private boolean isSynonymous(FeatureVector features, int basePosition, char variant)
+  {
+    int intronlength = 0;
+    Range lastRange = null;
+    
+    for(int i = 0; i<features.size(); i++)
+    {
+      Feature feature = features.elementAt(i);
+      
+      if(feature.getRawFirstBase() < basePosition && feature.getRawLastBase() > basePosition)
+      {
+        FeatureSegmentVector segments = feature.getSegments();
+        for(int j=0; j< segments.size(); j++)
+        {
+          FeatureSegment segment = segments.elementAt(j);
+          Range range = segment.getRawRange();
+          
+          if(j > 0)
+          {
+            if(feature.isForwardFeature())
+              intronlength+=range.getStart()-lastRange.getEnd()-1;
+            else
+              intronlength+=lastRange.getStart()-range.getEnd()-1;
+            
+            if(intronlength < 0)
+              intronlength = 0;
+          }
+          
+          if(range.getStart() < basePosition && range.getEnd() > basePosition)
+          {
+            int mod;
+            int codonStart;
+            
+            if(feature.isForwardFeature())
+            {
+              mod = (basePosition-feature.getRawFirstBase())%3;
+              codonStart = basePosition-feature.getRawFirstBase()-mod;
+            }
+            else
+            {
+              mod = (feature.getRawLastBase()-basePosition)%3;
+              codonStart = feature.getRawLastBase()-basePosition-mod;
+            }
+
+            codonStart-=intronlength;
+            char codon[] = feature.getBases().substring(codonStart, codonStart+3).toLowerCase().toCharArray();
+
+            //String oldBase = new String(codon);
+            char aaRef = AminoAcidSequence.getCodonTranslation(codon[0], codon[1], codon[2]);
+
+            codon[mod] = variant;
+            char aaNew = AminoAcidSequence.getCodonTranslation(codon[0], codon[1], codon[2]);
+            
+            if(aaNew == aaRef)
+              return true;
+            else 
+              return false;
+          }
+
+          lastRange = range;
+        }
+      }
+    }
+    
+    return true;
+  }
+  
+  private int[] getScreenPosition(String base, float pixPerBase, int start, int vcfFileIndex)
   {
-    String parts[] = line.split("\\t");
     int pos[] = new int[2];
-    pos[0] = Math.round((Integer.parseInt(parts[1]) - start)*pixPerBase);
+    pos[0] = Math.round((Integer.parseInt(base) - start)*pixPerBase);
     pos[1] = getHeight() - 15 - (vcfFileIndex*(LINE_HEIGHT+5)); 
     return pos;
   }
@@ -547,7 +722,7 @@ public class VCFview extends JPanel
       {
         while ((s = iter.next()) != null)
         {
-          int pos[] = getScreenPosition(s, pixPerBase, start, i);
+          int pos[] = getScreenPosition(s.split("\\t")[1], pixPerBase, start, i);
           if(lastMousePoint != null &&
              lastMousePoint.getY() < pos[1] &&
              lastMousePoint.getY() > pos[1]-LINE_HEIGHT &&
@@ -636,9 +811,9 @@ public class VCFview extends JPanel
     try
     {
       if(dragStart < 0)
-        drag_range = new MarkerRange (bases.getForwardStrand(), start, start);
+        drag_range = new MarkerRange (entryGroup.getSequenceEntry().getBases().getForwardStrand(), start, start);
       else
-        drag_range = new MarkerRange (bases.getForwardStrand(), dragStart, start);
+        drag_range = new MarkerRange (entryGroup.getSequenceEntry().getBases().getForwardStrand(), dragStart, start);
       getSelection().setMarkerRange(drag_range);
       repaint();
     }
@@ -799,9 +974,6 @@ public class VCFview extends JPanel
      {
        if(e.isPopupTrigger())
        {
-         if(popup == null)
-           popup = new JPopupMenu();
-         
          if(showDetails != null)
            popup.remove(showDetails);
          
@@ -839,11 +1011,9 @@ public class VCFview extends JPanel
              }  
            });
            popup.add(showDetails);
-           
-           popup.show(e.getComponent(),
-               e.getX(), e.getY());
          }
-
+         popup.show(e.getComponent(),
+             e.getX(), e.getY());
        }
      }
    }
-- 
GitLab