2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.rbvi.chimera;
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNotNull;
26 import static org.testng.Assert.assertTrue;
29 import java.io.IOException;
30 import java.util.List;
31 import java.util.Vector;
33 import org.testng.annotations.AfterClass;
34 import org.testng.annotations.AfterMethod;
35 import org.testng.annotations.BeforeClass;
36 import org.testng.annotations.Test;
38 import jalview.api.FeatureRenderer;
39 import jalview.api.structures.JalviewStructureDisplayI;
40 import jalview.bin.Cache;
41 import jalview.bin.Jalview;
42 import jalview.datamodel.AlignmentI;
43 import jalview.datamodel.DBRefEntry;
44 import jalview.datamodel.PDBEntry;
45 import jalview.datamodel.Sequence;
46 import jalview.datamodel.SequenceFeature;
47 import jalview.datamodel.SequenceI;
48 import jalview.gui.AlignFrame;
49 import jalview.gui.Desktop;
50 import jalview.gui.JvOptionPane;
51 import jalview.gui.Preferences;
52 import jalview.gui.StructureViewer;
53 import jalview.gui.StructureViewer.ViewerType;
54 import jalview.io.DataSourceType;
55 import jalview.io.FileLoader;
56 import jalview.structure.StructureCommand;
57 import jalview.structure.StructureMapping;
58 import jalview.structure.StructureSelectionManager;
59 import jalview.ws.sifts.SiftsClient;
60 import jalview.ws.sifts.SiftsException;
61 import jalview.ws.sifts.SiftsSettings;
63 @Test(singleThreaded = true)
64 public class JalviewChimeraView
67 @BeforeClass(alwaysRun = true)
68 public void setUpJvOptionPane()
70 JvOptionPane.setInteractiveMode(false);
71 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
74 private JalviewStructureDisplayI chimeraViewer;
77 * @throws java.lang.Exception
79 @BeforeClass(alwaysRun = true)
80 public static void setUpBeforeClass() throws Exception
84 { "-noquestionnaire", "-nonews", "-props",
85 "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
86 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
87 ViewerType.CHIMERA.name());
88 Cache.setProperty("SHOW_ANNOTATIONS", "false");
89 Cache.setProperty(Preferences.STRUCT_FROM_PDB, "false");
90 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
91 ViewerType.CHIMERA.name());
92 Cache.setProperty("MAP_WITH_SIFTS", "true");
93 // TODO this should not be necessary!
94 SiftsSettings.setMapWithSifts(true);
98 * @throws java.lang.Exception
100 @AfterClass(alwaysRun = true)
101 public static void tearDownAfterClass() throws Exception
103 if (Desktop.instance != null)
104 Desktop.instance.closeAll_actionPerformed(null);
107 @AfterMethod(alwaysRun = true)
108 public void tearDownAfterTest() throws Exception
110 SiftsClient.setMockSiftsFile(null);
111 if (chimeraViewer != null)
113 chimeraViewer.closeViewer(true);
118 * Load 1GAQ and view the first structure for which a PDB id is found. Note no
119 * network connection is needed - PDB file is read locally, SIFTS fetch fails
120 * so mapping falls back to Needleman-Wunsch - ok for this test.
122 // External as local install of Chimera required
123 @Test(groups = { "External" })
124 public void testSingleSeqViewChimera()
127 String inFile = "examples/1gaq.txt";
128 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
129 DataSourceType.FILE);
130 assertNotNull(af, "Failed to create AlignFrame");
131 SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
132 assertEquals(sq.getName(), "1GAQ|A");
133 SequenceI dsq = sq.getDatasetSequence();
134 Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
135 assertEquals(pdbIds.size(), 1);
136 PDBEntry pdbEntry = pdbIds.get(0);
137 assertEquals(pdbEntry.getId(), "1GAQ");
138 StructureViewer structureViewer = new StructureViewer(
139 af.getViewport().getStructureSelectionManager());
140 chimeraViewer = structureViewer.viewStructures(pdbEntry,
142 { sq }, af.getCurrentView().getAlignPanel());
143 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
147 * Wait for viewer load thread to complete
154 } catch (InterruptedException e)
157 } while (!binding.isFinishedInit() || !chimeraViewer.isVisible());
159 assertTrue(binding.isViewerRunning(), "Failed to start Chimera");
161 assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
162 assertTrue(chimeraViewer.hasViewerActionsMenu());
164 // now add another sequence and bind to view
166 AlignmentI al = af.getViewport().getAlignment();
167 PDBEntry xpdb = al.getSequenceAt(0).getPDBEntry("1GAQ");
168 sq = new Sequence("1GAQ",
169 al.getSequenceAt(0).getSequence(25, 95).toString());
171 structureViewer.viewStructures(new PDBEntry[] { xpdb },
173 { sq }, af.getCurrentView().getAlignPanel());
176 * Wait for viewer load thread to complete
183 } catch (InterruptedException q)
187 } while (!binding.isLoadingFinished());
189 // still just one PDB structure shown
190 assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
191 // and the viewer action menu should still be visible
192 assertTrue(chimeraViewer.hasViewerActionsMenu());
194 chimeraViewer.closeViewer(true);
195 chimeraViewer = null;
200 * Test for writing Jalview features as attributes on mapped residues in
201 * Chimera. Note this uses local copies of PDB and SIFTS file, no network
202 * connection required.
204 * @throws IOException
205 * @throws SiftsException
207 // External as this requires a local install of Chimera
208 @Test(groups = { "External" })
209 public void testTransferFeatures() throws IOException, SiftsException
211 String inFile = "examples/uniref50.fa";
212 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
213 DataSourceType.FILE);
214 assertNotNull(af, "Failed to create AlignFrame");
215 SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
216 assertNotNull(sq, "Didn't find FER2_ARATH");
219 * need a Uniprot dbref for SIFTS mapping to work!!
221 sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
224 * use local test PDB and SIFTS files
226 String pdbFilePath = new File("test/jalview/ext/rbvi/chimera/4zho.pdb")
228 PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
229 String siftsFilePath = new File(
230 "test/jalview/ext/rbvi/chimera/4zho.xml.gz").getPath();
231 SiftsClient.setMockSiftsFile(new File(siftsFilePath));
233 StructureViewer structureViewer = new StructureViewer(
234 af.getViewport().getStructureSelectionManager());
235 chimeraViewer = structureViewer.viewStructures(pdbEntry,
237 { sq }, af.getCurrentView().getAlignPanel());
239 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
246 } catch (InterruptedException e)
249 } while (!binding.isFinishedInit());
251 assertTrue(binding.isViewerRunning(), "Failed to launch Chimera");
253 assertEquals(binding.getPdbCount(), 1);
256 * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
257 * (or possibly 52-145 to 1-94 - see JAL-2319)
259 StructureSelectionManager ssm = binding.getSsm();
260 String pdbFile = binding.getStructureFiles()[0];
261 StructureMapping[] mappings = ssm.getMapping(pdbFile);
262 assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
263 "Failed to perform SIFTS mapping");
264 assertEquals(mappings.length, 2);
265 assertEquals(mappings[0].getChain(), "A");
266 assertEquals(mappings[0].getPDBResNum(53), 2);
267 assertEquals(mappings[0].getPDBResNum(145), 94);
268 assertEquals(mappings[1].getChain(), "B");
269 assertEquals(mappings[1].getPDBResNum(53), 2);
270 assertEquals(mappings[1].getPDBResNum(145), 94);
273 * now add some features to FER2_ARATH
275 // feature on a sequence region not mapped to structure:
276 sq.addSequenceFeature(new SequenceFeature("transit peptide",
277 "chloroplast", 1, 51, Float.NaN, null));
278 // feature on a region mapped to structure:
279 sq.addSequenceFeature(new SequenceFeature("domain",
280 "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
281 // on sparse positions of the sequence
282 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
283 "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
284 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
285 "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
286 // on a sequence region that is partially mapped to structure:
287 sq.addSequenceFeature(
288 new SequenceFeature("helix", null, 50, 60, Float.NaN, null));
290 sq.addSequenceFeature(
291 new SequenceFeature("chain", null, 50, 70, Float.NaN, null));
292 // add numeric valued features - score is set as attribute value
293 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
295 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
297 sq.addSequenceFeature(new SequenceFeature("RESNUM", "ALA: 2 4zhoA",
298 53, 53, Float.NaN, null));
301 * set all features visible except for chain
303 af.setShowSeqFeatures(true);
304 FeatureRenderer fr = af.getFeatureRenderer();
305 fr.setVisible("transit peptide");
306 fr.setVisible("domain");
307 fr.setVisible("metal ion-binding site");
308 fr.setVisible("helix");
310 fr.setVisible("RESNUM");
313 * 'perform' menu action to copy visible features to
314 * attributes in Chimera
316 // TODO rename and pull up method to binding interface
317 // once functionality is added for Jmol as well
318 binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
321 * give Chimera time to open the commands file and execute it
326 } catch (InterruptedException e)
331 * ask Chimera for its residue attribute names
333 List<String> reply = binding
334 .executeCommand(new StructureCommand("list resattr"), true);
335 // prefixed and sanitised attribute names for Jalview features:
336 assertTrue(reply.contains("resattr jv_domain"));
337 assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
338 assertTrue(reply.contains("resattr jv_helix"));
339 assertTrue(reply.contains("resattr jv_kd"));
340 assertTrue(reply.contains("resattr jv_RESNUM"));
341 // feature is not on a mapped region - no attribute created
342 assertFalse(reply.contains("resattr jv_transit_peptide"));
343 // feature is not visible - no attribute created
344 assertFalse(reply.contains("resattr jv_chain"));
347 * ask Chimera for residues with an attribute
348 * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
350 reply = binding.executeCommand(
351 new StructureCommand("list resi att jv_metal_ion_binding_site"),
353 assertEquals(reply.size(), 4);
354 assertTrue(reply.contains(
355 "residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
356 assertTrue(reply.contains(
357 "residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
358 assertTrue(reply.contains(
359 "residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
360 assertTrue(reply.contains(
361 "residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
364 * check attributes with score values
365 * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
367 reply = binding.executeCommand(
368 new StructureCommand("list resi att jv_kd"), true);
369 assertEquals(reply.size(), 4);
370 assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
371 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
372 assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
373 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
376 * list residues with positive kd score
378 reply = binding.executeCommand(
379 new StructureCommand("list resi spec :*/jv_kd>0 attr jv_kd"),
381 assertEquals(reply.size(), 2);
382 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
383 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
385 SiftsClient.setMockSiftsFile(null);
386 chimeraViewer.closeViewer(true);
387 chimeraViewer = null;
391 * Test for creating Jalview features from attributes on mapped residues in
392 * Chimera. Note this uses local copies of PDB and SIFTS file, no network
393 * connection required.
395 * @throws IOException
396 * @throws SiftsException
398 // External as this requires a local install of Chimera
399 @Test(groups = { "External" })
400 public void testGetAttributes() throws IOException, SiftsException
402 String inFile = "examples/uniref50.fa";
403 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
404 DataSourceType.FILE);
405 assertNotNull(af, "Failed to create AlignFrame");
406 SequenceI fer2Arath = af.getViewport().getAlignment()
407 .findName("FER2_ARATH");
408 assertNotNull(fer2Arath, "Didn't find FER2_ARATH");
411 * need a Uniprot dbref for SIFTS mapping to work!!
413 fer2Arath.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
416 * use local test PDB and SIFTS files
418 String pdbFilePath = new File("test/jalview/ext/rbvi/chimera/4zho.pdb")
420 PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
421 String siftsFilePath = new File(
422 "test/jalview/ext/rbvi/chimera/4zho.xml.gz").getPath();
423 SiftsClient.setMockSiftsFile(new File(siftsFilePath));
425 StructureViewer structureViewer = new StructureViewer(
426 af.getViewport().getStructureSelectionManager());
427 chimeraViewer = structureViewer.viewStructures(pdbEntry,
429 { fer2Arath }, af.getCurrentView().getAlignPanel());
431 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
438 } catch (InterruptedException e)
441 } while (!binding.isFinishedInit());
443 assertTrue(binding.isViewerRunning(), "Failed to launch Chimera");
445 assertEquals(binding.getPdbCount(), 1);
448 * 'perform' menu action to copy Chimera attributes
449 * to features in Jalview
451 // TODO rename and pull up method to binding interface
452 // once functionality is added for Jmol as well
453 binding.copyStructureAttributesToFeatures("isHelix",
454 af.getViewport().getAlignPanel());
457 * verify 22 residues have isHelix feature
458 * (may merge into ranges in future)
460 af.setShowSeqFeatures(true);
461 FeatureRenderer fr = af.getFeatureRenderer();
462 fr.setVisible("isHelix");
463 for (int res = 75; res <= 83; res++)
465 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
467 for (int res = 117; res <= 123; res++)
469 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
471 for (int res = 129; res <= 131; res++)
473 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
475 for (int res = 143; res <= 145; res++)
477 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
481 * fetch a numeric valued attribute
483 binding.copyStructureAttributesToFeatures("phi",
484 af.getViewport().getAlignPanel());
485 fr.setVisible("phi");
486 List<SequenceFeature> fs = fer2Arath.getFeatures().findFeatures(54, 54,
488 assertEquals(fs.size(), 2);
489 assertTrue(fs.contains(new SequenceFeature("phi", "A", 54, 54,
490 -131.0713f, "Chimera")));
491 assertTrue(fs.contains(new SequenceFeature("phi", "B", 54, 54,
492 -127.39512f, "Chimera")));
495 * tear down - also in AfterMethod
497 SiftsClient.setMockSiftsFile(null);
498 chimeraViewer.closeViewer(true);
499 chimeraViewer = null;
503 * Helper method to verify new feature at a sequence position
510 protected void checkFeaturesAtRes(SequenceI seq, FeatureRenderer fr,
511 int res, String featureType)
513 String where = "at position " + res;
514 List<SequenceFeature> fs = seq.getFeatures().findFeatures(res, res,
517 assertEquals(fs.size(), 1, where);
518 SequenceFeature sf = fs.get(0);
519 assertEquals(sf.getType(), featureType, where);
520 assertEquals(sf.getFeatureGroup(), "Chimera", where);
521 assertEquals(sf.getDescription(), "True", where);
522 assertEquals(sf.getScore(), Float.NaN, where);