*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+ import jalview.gui.JvOptionPane;
+
import java.awt.Color;
-import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ChimeraCommandsTest
{
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
@Test(groups = { "Functional" })
- public void testAddColourRange()
- {
- Map<Color, Map<Integer, Map<String, List<int[]>>>> map = new LinkedHashMap<Color, Map<Integer, Map<String, List<int[]>>>>();
- ChimeraCommands.addColourRange(map, Color.pink, 1, 2, 4, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 8, 8, "A");
- ChimeraCommands.addColourRange(map, Color.pink, 1, 5, 7, "B");
- ChimeraCommands.addColourRange(map, Color.red, 1, 3, 5, "A");
- ChimeraCommands.addColourRange(map, Color.red, 0, 1, 4, "B");
- ChimeraCommands.addColourRange(map, Color.orange, 0, 5, 9, "C");
-
- // three colours mapped
- assertEquals(3, map.keySet().size());
-
- // Red has two models, Pink and Orange one each
- assertEquals(2, map.get(Color.red).keySet().size());
- assertEquals(1, map.get(Color.orange).keySet().size());
- assertEquals(1, map.get(Color.pink).keySet().size());
-
- // pink model 1 has two chains, red.0 / red.1 / orange.0 one each
- assertEquals(2, map.get(Color.pink).get(1).keySet().size());
- assertEquals(1, map.get(Color.red).get(0).keySet().size());
- assertEquals(1, map.get(Color.red).get(1).keySet().size());
- assertEquals(1, map.get(Color.orange).get(0).keySet().size());
-
- // inspect positions
- List<int[]> posList = map.get(Color.pink).get(1).get("A");
- assertEquals(2, posList.size());
- assertTrue(Arrays.equals(new int[] { 2, 4 }, posList.get(0)));
- assertTrue(Arrays.equals(new int[] { 8, 8 }, posList.get(1)));
-
- posList = map.get(Color.pink).get(1).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 7 }, posList.get(0)));
-
- posList = map.get(Color.red).get(0).get("B");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 1, 4 }, posList.get(0)));
-
- posList = map.get(Color.red).get(1).get("A");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 3, 5 }, posList.get(0)));
-
- posList = map.get(Color.orange).get(0).get("C");
- assertEquals(1, posList.size());
- assertTrue(Arrays.equals(new int[] { 5, 9 }, posList.get(0)));
- }
-
- @Test(groups = { "Functional" })
public void testBuildColourCommands()
{
*/
package jalview.ext.rbvi.chimera;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import jalview.api.FeatureRenderer;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+ import jalview.gui.JvOptionPane;
import jalview.gui.Preferences;
import jalview.gui.StructureViewer;
import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.FileLoader;
- import jalview.io.FormatAdapter;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+import jalview.ws.sifts.SiftsClient;
+import jalview.ws.sifts.SiftsException;
+import jalview.ws.sifts.SiftsSettings;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
+ import jalview.io.DataSourceType;
import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class JalviewChimeraView
{
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ private JalviewStructureDisplayI chimeraViewer;
+
/**
* @throws java.lang.Exception
*/
@AfterClass(alwaysRun = true)
public static void tearDownAfterClass() throws Exception
{
- jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
+ Desktop.instance.closeAll_actionPerformed(null);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDownAfterTest() throws Exception
+ {
+ SiftsClient.setMockSiftsFile(null);
+ if (chimeraViewer != null)
+ {
+ chimeraViewer.closeViewer(true);
+ }
}
- @Test(groups = { "Functional" })
+ /**
+ * Load 1GAQ and view the first structure for which a PDB id is found. Note no
+ * network connection is needed - PDB file is read locally, SIFTS fetch fails
+ * so mapping falls back to Needleman-Wunsch - ok for this test.
+ */
+ // External as local install of Chimera required
+ @Test(groups = { "External" })
public void testSingleSeqViewChimera()
{
- Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
- ViewerType.CHIMERA.name());
String inFile = "examples/1gaq.txt";
- AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
- inFile, DataSourceType.FILE);
- assertTrue("Didn't read input file " + inFile, af != null);
- for (SequenceI sq : af.getViewport().getAlignment().getSequences())
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
- FormatAdapter.FILE);
++ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
+ assertEquals(sq.getName(), "1GAQ|A");
+ SequenceI dsq = sq.getDatasetSequence();
+ Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
+ assertEquals(pdbIds.size(), 1);
+ PDBEntry pdbEntry = pdbIds.get(0);
+ assertEquals(pdbEntry.getId(), "1GAQ");
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+
+ /*
+ * Wait for viewer load thread to complete
+ */
+ while (!binding.isFinishedInit())
{
- System.out.println("** sq=" + sq.getName());
- SequenceI dsq = sq.getDatasetSequence();
- while (dsq.getDatasetSequence() != null)
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- dsq = dsq.getDatasetSequence();
}
- if (dsq.getAllPDBEntries() != null
- && dsq.getAllPDBEntries().size() > 0)
+ }
+
+ assertTrue(binding.isChimeraRunning(), "Failed to start Chimera");
+
+ assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ return;
+ }
+
+ /**
+ * Test for writing Jalview features as attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testTransferFeatures() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
- FormatAdapter.FILE);
++ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
+ assertNotNull(sq, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
+ {
+ }
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
+ * (or possibly 52-145 to 1-94 - see JAL-2319)
+ */
+ StructureSelectionManager ssm = binding.getSsm();
+ String pdbFile = binding.getPdbFile()[0];
+ StructureMapping[] mappings = ssm.getMapping(pdbFile);
+ assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
+ "Failed to perform SIFTS mapping");
+ assertEquals(mappings.length, 2);
+ assertEquals(mappings[0].getChain(), "A");
+ assertEquals(mappings[0].getPDBResNum(53), 2);
+ assertEquals(mappings[0].getPDBResNum(145), 94);
+ assertEquals(mappings[1].getChain(), "B");
+ assertEquals(mappings[1].getPDBResNum(53), 2);
+ assertEquals(mappings[1].getPDBResNum(145), 94);
+
+ /*
+ * now add some features to FER2_ARATH
+ */
+ // feature on a sequence region not mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("transit peptide",
+ "chloroplast", 1, 51, Float.NaN, null));
+ // feature on a region mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("domain",
+ "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
+ // on sparse positions of the sequence
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
+ sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
+ "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
+ // on a sequence region that is partially mapped to structure:
+ sq.addSequenceFeature(new SequenceFeature("helix", null, 50, 60,
+ Float.NaN, null));
+ // and again:
+ sq.addSequenceFeature(new SequenceFeature("chain", null, 50, 70,
+ Float.NaN, null));
+ // add numeric valued features - score is set as attribute value
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
+ 62, -2.1f, null));
+ sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
+ 65, 3.6f, null));
+ sq.addSequenceFeature(new SequenceFeature("RESNUM", "ALA: 2 4zhoA",
+ 53, 53, Float.NaN, null));
+
+ /*
+ * set all features visible except for chain
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("transit peptide");
+ fr.setVisible("domain");
+ fr.setVisible("metal ion-binding site");
+ fr.setVisible("helix");
+ fr.setVisible("kd");
+ fr.setVisible("RESNUM");
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
+
+ /*
+ * give Chimera time to open the commands file and execute it
+ */
+ try
+ {
+ Thread.sleep(1000);
+ } catch (InterruptedException e)
+ {
+ }
+
+ /*
+ * ask Chimera for its residue attribute names
+ */
+ List<String> reply = binding.sendChimeraCommand("list resattr", true);
+ // prefixed and sanitised attribute names for Jalview features:
+ assertTrue(reply.contains("resattr jv_domain"));
+ assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
+ assertTrue(reply.contains("resattr jv_helix"));
+ assertTrue(reply.contains("resattr jv_kd"));
+ assertTrue(reply.contains("resattr jv_RESNUM"));
+ // feature is not on a mapped region - no attribute created
+ assertFalse(reply.contains("resattr jv_transit_peptide"));
+ // feature is not visible - no attribute created
+ assertFalse(reply.contains("resattr jv_chain"));
+
+ /*
+ * ask Chimera for residues with an attribute
+ * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi att jv_metal_ion_binding_site", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply
+ .contains("residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+ assertTrue(reply
+ .contains("residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
+ assertTrue(reply
+ .contains("residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
+
+ /*
+ * check attributes with score values
+ * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
+ */
+ reply = binding.sendChimeraCommand("list resi att jv_kd", true);
+ assertEquals(reply.size(), 4);
+ assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ /*
+ * list residues with positive kd score
+ */
+ reply = binding.sendChimeraCommand(
+ "list resi spec :*/jv_kd>0 attr jv_kd", true);
+ assertEquals(reply.size(), 2);
+ assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
+ assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
+
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Test for creating Jalview features from attributes on mapped residues in
+ * Chimera. Note this uses local copies of PDB and SIFTS file, no network
+ * connection required.
+ *
+ * @throws IOException
+ * @throws SiftsException
+ */
+ // External as this requires a local install of Chimera
+ @Test(groups = { "External" })
+ public void testGetAttributes() throws IOException, SiftsException
+ {
+ String inFile = "examples/uniref50.fa";
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
- FormatAdapter.FILE);
++ DataSourceType.FILE);
+ assertNotNull(af, "Failed to create AlignFrame");
+ SequenceI fer2Arath = af.getViewport().getAlignment()
+ .findName("FER2_ARATH");
+ assertNotNull(fer2Arath, "Didn't find FER2_ARATH");
+
+ /*
+ * need a Uniprot dbref for SIFTS mapping to work!!
+ */
+ fer2Arath.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
+
+ /*
+ * use local test PDB and SIFTS files
+ */
+ String pdbFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
+ PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
+ String siftsFilePath = new File(
+ "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
+ .getPath();
+ SiftsClient.setMockSiftsFile(new File(siftsFilePath));
+
+ StructureViewer structureViewer = new StructureViewer(af.getViewport()
+ .getStructureSelectionManager());
+ chimeraViewer = structureViewer.viewStructures(pdbEntry,
+ new SequenceI[] { fer2Arath }, af.getCurrentView()
+ .getAlignPanel());
+
+ JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
+ .getBinding();
+ do
+ {
+ try
+ {
+ Thread.sleep(500);
+ } catch (InterruptedException e)
{
- for (int q = 0; q < dsq.getAllPDBEntries().size(); q++)
- {
- final StructureViewer structureViewer = new StructureViewer(af
- .getViewport().getStructureSelectionManager());
- structureViewer.setViewerType(ViewerType.CHIMERA);
- JalviewStructureDisplayI chimeraViewer = structureViewer
- .viewStructures(dsq.getAllPDBEntries().elementAt(q),
- new SequenceI[] { sq }, af.getCurrentView()
- .getAlignPanel());
- /*
- * Wait for viewer load thread to complete
- */
- while (!chimeraViewer.getBinding().isFinishedInit())
- {
- try
- {
- Thread.sleep(500);
- } catch (InterruptedException e)
- {
- }
- }
- assertEquals(1, chimeraViewer.getBinding().getPdbCount());
- chimeraViewer.closeViewer(true);
- // todo: break here means only once through this loop?
- break;
- }
- break;
}
+ } while (!binding.isFinishedInit());
+
+ assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
+
+ assertEquals(binding.getPdbCount(), 1);
+
+ /*
+ * 'perform' menu action to copy visible features to
+ * attributes in Chimera
+ */
+ // TODO rename and pull up method to binding interface
+ // once functionality is added for Jmol as well
+ binding.copyStructureAttributesToFeatures("isHelix", af.getViewport()
+ .getAlignPanel());
+
+ /*
+ * verify 22 residues have isHelix feature
+ * (may merge into ranges in future)
+ */
+ af.setShowSeqFeatures(true);
+ FeatureRenderer fr = af.getFeatureRenderer();
+ fr.setVisible("isHelix");
+ for (int res = 75; res <= 83; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
}
+ for (int res = 117; res <= 123; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 129; res <= 131; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+ for (int res = 143; res <= 145; res++)
+ {
+ checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
+ }
+
+ /*
+ * fetch a numeric valued attribute
+ */
+ binding.copyStructureAttributesToFeatures("phi", af.getViewport()
+ .getAlignPanel());
+ fr.setVisible("phi");
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(fer2Arath, 54);
+ assertEquals(fs.size(), 3);
+ assertEquals(fs.get(0).getType(), "RESNUM");
+ assertEquals(fs.get(1).getType(), "phi");
+ assertEquals(fs.get(2).getType(), "phi");
+ assertEquals(fs.get(1).getDescription(), "A"); // chain
+ assertEquals(fs.get(2).getDescription(), "B");
+ assertEquals(fs.get(1).getScore(), -131.0713f, 0.001f);
+ assertEquals(fs.get(2).getScore(), -127.39512, 0.001f);
+
+ /*
+ * tear down - also in AfterMethod
+ */
+ SiftsClient.setMockSiftsFile(null);
+ chimeraViewer.closeViewer(true);
+ chimeraViewer = null;
+ }
+
+ /**
+ * Helper method to verify new feature at a sequence position
+ *
+ * @param seq
+ * @param fr
+ * @param res
+ * @param featureType
+ */
+ protected void checkFeaturesAtRes(SequenceI seq, FeatureRenderer fr,
+ int res, String featureType)
+ {
+ String where = "at position " + res;
+ List<SequenceFeature> fs = fr.findFeaturesAtRes(seq, res);
+ assertEquals(fs.size(), 2, where);
+ assertEquals(fs.get(0).getType(), "RESNUM", where);
+ SequenceFeature sf = fs.get(1);
+ assertEquals(sf.getType(), featureType, where);
+ assertEquals(sf.getFeatureGroup(), "Chimera", where);
+ assertEquals(sf.getDescription(), "True", where);
+ assertEquals(sf.getScore(), Float.NaN, where);
}
}