JAL-1741 nucleotide-aware colour schemes applied to structures
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 20 May 2015 13:41:38 +0000 (14:41 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 20 May 2015 13:41:38 +0000 (14:41 +0100)
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/schemes/ResidueProperties.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/Comparison.java
test/jalview/schemes/ResiduePropertiesTest.java
test/jalview/util/ComparisonTest.java

index 68cc792..45fc378 100644 (file)
  */
 package jalview.ext.jmol;
 
-import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
-import jalview.api.SequenceRenderer;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.io.AppletFormatAdapter;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
-import jalview.structure.StructureSelectionManager;
-import jalview.structures.models.AAStructureBindingModel;
-import jalview.util.MessageManager;
-
 import java.awt.Color;
 import java.awt.Container;
 import java.awt.event.ComponentEvent;
@@ -44,6 +28,7 @@ import java.io.File;
 import java.net.URL;
 import java.security.AccessControlException;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
@@ -55,6 +40,22 @@ import org.jmol.api.JmolViewer;
 import org.jmol.constant.EnumCallback;
 import org.jmol.popup.JmolPopup;
 
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
+import jalview.api.SequenceRenderer;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.MessageManager;
+
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
         implements JmolStatusListener, JmolSelectionListener,
         ComponentListener
@@ -1327,22 +1328,14 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       return;
     }
 
-    int index;
-    Color col;
     jmolHistory(false);
-    // TODO: Switch between nucleotide or aa selection expressions
     StringBuilder command = new StringBuilder(128);
     command.append("select *;color white;");
-    for (String res : ResidueProperties.aa3Hash.keySet())
+    List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
+            false);
+    for (String res : residueSet)
     {
-      index = ResidueProperties.aa3Hash.get(res).intValue();
-      if (index > 20)
-      {
-        continue;
-      }
-
-      col = cs.findColour(ResidueProperties.aa[index].charAt(0));
-
+      Color col = cs.findColour(res.charAt(0));
       command.append("select " + res + ";color[" + col.getRed() + ","
               + col.getGreen() + "," + col.getBlue() + "];");
     }
index 543cad4..b649a64 100644 (file)
@@ -1018,23 +1018,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       return;
     }
 
-    int index;
-    Color col;
     // Chimera expects RBG values in the range 0-1
     final double normalise = 255D;
     viewerCommandHistory(false);
-    // TODO: Switch between nucleotide or aa selection expressions
     StringBuilder command = new StringBuilder(128);
-    command.append("color white;");
-    for (String res : ResidueProperties.aa3Hash.keySet())
-    {
-      index = ResidueProperties.aa3Hash.get(res).intValue();
-      if (index > 20)
-      {
-        continue;
-      }
 
-      col = cs.findColour(ResidueProperties.aa[index].charAt(0));
+    List<String> residueSet = ResidueProperties.getResidues(isNucleotide(),
+            false);
+    for (String res : residueSet)
+    {
+      Color col = cs.findColour(res.charAt(0));
       command.append("color " + col.getRed() / normalise + ","
               + col.getGreen() / normalise + "," + col.getBlue()
               / normalise + " ::" + res + ";");
index 0f34824..662a77e 100755 (executable)
  */
 package jalview.schemes;
 
-import jalview.analysis.scoremodels.FeatureScoreModel;
-import jalview.analysis.scoremodels.PIDScoreModel;
-import jalview.api.analysis.ScoreModelI;
-
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -33,6 +29,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
+import jalview.analysis.scoremodels.FeatureScoreModel;
+import jalview.analysis.scoremodels.PIDScoreModel;
+import jalview.api.analysis.ScoreModelI;
+
 public class ResidueProperties
 {
   public static Hashtable<String, ScoreModelI> scoreMatrices = new Hashtable();
@@ -1787,4 +1787,52 @@ public class ResidueProperties
   }
   // to here
 
+  /**
+   * Returns a list of residue characters for the specified inputs
+   * 
+   * @param nucleotide
+   * @param includeAmbiguous
+   * @return
+   */
+  public static List<String> getResidues(boolean nucleotide,
+          boolean includeAmbiguous)
+  {
+    List<String> result = new ArrayList<String>();
+    if (nucleotide)
+    {
+      for (String nuc : nucleotideName.keySet())
+      {
+        int val = nucleotideIndex[nuc.charAt(0)];
+        if ((!includeAmbiguous && val > 4) || (val >= maxNucleotideIndex))
+        {
+          continue;
+        }
+        nuc = nuc.toUpperCase();
+        if (!result.contains(nuc))
+        {
+          result.add(nuc);
+        }
+      }
+    } else {
+      /*
+       * Peptide
+       */
+      for (String res : aa3Hash.keySet())
+      {
+        int index = aa3Hash.get(res).intValue();
+        if ((!includeAmbiguous && index >= 20) || index >= maxProteinIndex)
+        {
+          continue;
+        }
+        res = res.toUpperCase();
+        if (!result.contains(res))
+        {
+          result.add(res);
+        }
+      }
+    }
+
+    return result;
+  }
+
 }
index 653ec2d..3602056 100644 (file)
@@ -1,16 +1,17 @@
 package jalview.structures.models;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import jalview.api.StructureSelectionManagerProvider;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.structure.AtomSpec;
 import jalview.structure.StructureListener;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * 
  * A base class to hold common function for protein structure model binding.
@@ -46,6 +47,8 @@ public abstract class AAStructureBindingModel extends
 
   protected boolean colourBySequence = true;
 
+  private boolean nucleotide;
+
   /**
    * Constructor
    * 
@@ -74,6 +77,7 @@ public abstract class AAStructureBindingModel extends
   {
     this.ssm = ssm;
     this.sequence = sequenceIs;
+    this.nucleotide = Comparison.isNucleotide(sequenceIs);
     this.chains = chains;
     this.pdbEntry = pdbentry;
     this.protocol = protocol;
@@ -375,8 +379,11 @@ public abstract class AAStructureBindingModel extends
     }
   }
 
-  // TODO Jmol and Chimera seem to expect pdbFile, javascript listener pdbId
   protected abstract void highlightAtom(int atomIndex, int pdbResNum,
           String chain, String pdbFile);
 
+  protected boolean isNucleotide()
+  {
+    return this.nucleotide;
+  }
 }
\ No newline at end of file
index e224b71..835a1b4 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import jalview.datamodel.SequenceI;
 
 /**
@@ -248,7 +251,7 @@ public class Comparison
   /**
    * Answers true if more than 85% of the sequence residues (ignoring gaps) are
    * A, G, C, T or U, else false. This is just a heuristic guess and may give a
-   * wrong answer (as AGCT are also animo acid codes).
+   * wrong answer (as AGCT are also amino acid codes).
    * 
    * @param seqs
    * @return
@@ -263,6 +266,12 @@ public class Comparison
     int aaCount = 0;
     for (SequenceI seq : seqs)
     {
+      if (seq == null)
+      {
+        continue;
+      }
+      // TODO could possibly make an informed guess just from the first sequence
+      // to save a lengthy calculation
       for (char c : seq.getSequence())
       {
         if ('a' <= c && c <= 'z')
@@ -295,4 +304,27 @@ public class Comparison
     }
 
   }
+
+  /**
+   * Convenience overload of isNucleotide
+   * 
+   * @param seqs
+   * @return
+   */
+  public static boolean isNucleotide(SequenceI[][] seqs)
+  {
+    if (seqs == null)
+    {
+      return false;
+    }
+    List<SequenceI> flattened = new ArrayList<SequenceI>();
+    for (SequenceI[] ss : seqs)
+    {
+      for (SequenceI s : ss) {
+      flattened.add(s);
+      }
+    }
+    final SequenceI[] oneDArray = flattened.toArray(new SequenceI[flattened.size()]);
+    return isNucleotide(oneDArray);
+  }
 }
index b976e44..b82d338 100644 (file)
@@ -3,6 +3,9 @@ package jalview.schemes;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
+import java.util.Collections;
+import java.util.List;
+
 import org.junit.Test;
 
 public class ResiduePropertiesTest
@@ -171,4 +174,46 @@ public class ResiduePropertiesTest
     assertNull(ResidueProperties.codonTranslate("VHD"));
     assertNull(ResidueProperties.codonTranslate("WSK"));
   }
+
+  @Test
+  public void testGetResidues_nucleotide()
+  {
+    /*
+     * Non-ambiguous only; we don't care about the order of the list, it is just
+     * sorted here to make assertions reliable
+     */
+    List<String> residues = ResidueProperties.getResidues(true, false);
+    Collections.sort(residues);
+    assertEquals("[A, C, G, T, U]", residues.toString());
+
+    /*
+     * Including ambiguity codes I N R X Y
+     */
+    residues = ResidueProperties.getResidues(true, true);
+    Collections.sort(residues);
+    assertEquals("[A, C, G, I, N, R, T, U, X, Y]", residues.toString());
+  }
+
+  @Test
+  public void testGetResidues_peptide()
+  {
+    /*
+     * Non-ambiguous only; we don't care about the order of the list, it is just
+     * sorted here to make assertions reliable
+     */
+    List<String> residues = ResidueProperties.getResidues(false, false);
+    Collections.sort(residues);
+    assertEquals(
+            "[ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL]",
+            residues.toString());
+
+    /*
+     * Including ambiguity codes ASX, GLX, XAA
+     */
+    residues = ResidueProperties.getResidues(false, true);
+    Collections.sort(residues);
+    assertEquals(
+            "[ALA, ARG, ASN, ASP, ASX, CYS, GLN, GLU, GLX, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, XAA]",
+            residues.toString());
+  }
 }
index bfc2610..57d1ac1 100644 (file)
@@ -3,11 +3,12 @@ package jalview.util;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceI;
 
 import org.junit.Test;
 
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
 public class ComparisonTest
 {
 
@@ -32,6 +33,9 @@ public class ComparisonTest
     SequenceI seq = new Sequence("eightypercent", "agctuAGCPV");
     assertFalse(Comparison.isNucleotide(new SequenceI[]
     { seq }));
+    assertFalse(Comparison.isNucleotide(new SequenceI[][]
+    { new SequenceI[]
+    { seq } }));
 
     seq = new Sequence("eightyfivepercent", "agctuAGCPVagctuAGCUV");
     assertFalse(Comparison.isNucleotide(new SequenceI[]
@@ -57,17 +61,34 @@ public class ComparisonTest
 
     seq = new Sequence("DNA", "ACTugGCCAG");
     SequenceI seq2 = new Sequence("Protein", "FLIMVSPTYW");
+    /*
+     * 90% DNA:
+     */
     assertTrue(Comparison.isNucleotide(new SequenceI[]
-    { seq, seq, seq, seq, seq, seq, seq, seq, seq, seq2 })); // 90% DNA
+    { seq, seq, seq, seq, seq, seq, seq, seq, seq, seq2 }));
+    assertTrue(Comparison.isNucleotide(new SequenceI[][]
+    { new SequenceI[]
+    { seq }, new SequenceI[]
+    { seq, seq, seq }, new SequenceI[]
+    { seq, seq, seq, seq, seq, seq2 } }));
+    /*
+     * 80% DNA:
+     */
     assertFalse(Comparison.isNucleotide(new SequenceI[]
-    { seq, seq, seq, seq, seq, seq, seq, seq, seq2, seq2 })); // 80% DNA
+    { seq, seq, seq, seq, seq, seq, seq, seq, seq2, seq2 }));
+    assertFalse(Comparison.isNucleotide(new SequenceI[][]
+    { new SequenceI[]
+    { seq }, new SequenceI[]
+    { seq, seq, seq }, new SequenceI[]
+    { seq, seq, seq, seq, seq2, seq2, null } }));
 
     seq = new Sequence("ProteinThatLooksLikeDNA", "WYATGCCTGAgtcgt");
     // 12/14 = 85.7%
     assertTrue(Comparison.isNucleotide(new SequenceI[]
     { seq }));
 
-    assertFalse(Comparison.isNucleotide(null));
+    assertFalse(Comparison.isNucleotide((SequenceI[]) null));
+    assertFalse(Comparison.isNucleotide((SequenceI[][]) null));
   }
 
   /**