From 8e5fa38447bcb8541c71bd7491c16a96f80fabc2 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Wed, 16 Nov 2016 17:01:59 +0000 Subject: [PATCH] JAL-2296 unit test for reading Chimera attributes to Jalview features --- .../ext/rbvi/chimera/JalviewChimeraBinding.java | 48 ++++--- .../ext/rbvi/chimera/JalviewChimeraView.java | 137 ++++++++++++++++++++ 2 files changed, 168 insertions(+), 17 deletions(-) diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 72b33cc..7e70fef 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -1175,19 +1175,32 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String cmd = "list residues attr '" + attName + "'"; List residues = sendChimeraCommand(cmd, true); - /* - * Expect 0, 1 or more reply lines of the format (chi2 is attName): - * residue id #0:5.A chi2 -155.000836316 index 5 - * or - * residue id #0:6.A chi3 None - * - * We assume here that attributes on structure do not naturally convert - * to ranges on sequence, i.e. we just set one feature per mapped position. - * - * To conflate positions, would need to first build a map - * Map>> - * and then traverse it to find feature ranges. - */ + + boolean featureAdded = createFeaturesForAttributes(attName, residues); + if (featureAdded) + { + alignmentPanel.getFeatureRenderer().featuresAdded(); + } + } + + /** + * Create features in Jalview for the given attribute name and structure + * residues. + * + *
+   * The residue list should be 0, 1 or more reply lines of the format: 
+   *     residue id #0:5.A isHelix -155.000836316 index 5 
+   * or 
+   *     residue id #0:6.A isHelix None
+   * 
+ * + * @param attName + * @param residues + * @return + */ + protected boolean createFeaturesForAttributes(String attName, + List residues) + { boolean featureAdded = false; String featureGroup = getViewerFeatureGroup(); @@ -1236,6 +1249,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel spec.setPdbFile(pdbFile); List atoms = Collections.singletonList(spec); + + /* + * locate the mapped position in the alignment (if any) + */ SearchResults sr = getSsm() .findAlignmentPositionsForStructurePositions(atoms); @@ -1255,10 +1272,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel featureAdded |= seq.addSequenceFeature(sf); } } - if (featureAdded) - { - alignmentPanel.getFeatureRenderer().featuresAdded(); - } + return featureAdded; } /** diff --git a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java index a31a065..449b219 100644 --- a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java +++ b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java @@ -334,4 +334,141 @@ public class JalviewChimeraView 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); + 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) + { + } + } 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 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 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); + } } -- 1.7.10.2