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;
28 import jalview.api.FeatureRenderer;
29 import jalview.api.structures.JalviewStructureDisplayI;
30 import jalview.bin.Cache;
31 import jalview.bin.Jalview;
32 import jalview.datamodel.DBRefEntry;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.SequenceFeature;
35 import jalview.datamodel.SequenceI;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.Desktop;
38 import jalview.gui.Preferences;
39 import jalview.gui.StructureViewer;
40 import jalview.gui.StructureViewer.ViewerType;
41 import jalview.io.FileLoader;
42 import jalview.io.FormatAdapter;
43 import jalview.structure.StructureMapping;
44 import jalview.structure.StructureSelectionManager;
45 import jalview.ws.sifts.SiftsClient;
46 import jalview.ws.sifts.SiftsException;
47 import jalview.ws.sifts.SiftsSettings;
50 import java.io.IOException;
51 import java.util.List;
52 import java.util.Vector;
54 import org.testng.annotations.AfterClass;
55 import org.testng.annotations.AfterMethod;
56 import org.testng.annotations.BeforeClass;
57 import org.testng.annotations.Test;
59 @Test(singleThreaded = true)
60 public class JalviewChimeraView
63 private JalviewStructureDisplayI chimeraViewer;
66 * @throws java.lang.Exception
68 @BeforeClass(alwaysRun = true)
69 public static void setUpBeforeClass() throws Exception
71 Jalview.main(new String[] { "-noquestionnaire", "-nonews", "-props",
72 "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
73 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
74 ViewerType.CHIMERA.name());
75 Cache.setProperty("SHOW_ANNOTATIONS", "false");
76 Cache.setProperty(Preferences.STRUCT_FROM_PDB, "false");
77 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
78 ViewerType.CHIMERA.name());
79 Cache.setProperty("MAP_WITH_SIFTS", "true");
80 // TODO this should not be necessary!
81 SiftsSettings.setMapWithSifts(true);
85 * @throws java.lang.Exception
87 @AfterClass(alwaysRun = true)
88 public static void tearDownAfterClass() throws Exception
90 Desktop.instance.closeAll_actionPerformed(null);
93 @AfterMethod(alwaysRun = true)
94 public void tearDownAfterTest() throws Exception
96 SiftsClient.setMockSiftsFile(null);
97 if (chimeraViewer != null)
99 chimeraViewer.closeViewer(true);
104 * Load 1GAQ and view the first structure for which a PDB id is found. Note no
105 * network connection is needed - PDB file is read locally, SIFTS fetch fails
106 * so mapping falls back to Needleman-Wunsch - ok for this test.
108 // External as local install of Chimera required
109 @Test(groups = { "External" })
110 public void testSingleSeqViewChimera()
112 String inFile = "examples/1gaq.txt";
113 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
115 assertNotNull(af, "Failed to create AlignFrame");
116 SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
117 assertEquals(sq.getName(), "1GAQ|A");
118 SequenceI dsq = sq.getDatasetSequence();
119 Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
120 assertEquals(pdbIds.size(), 1);
121 PDBEntry pdbEntry = pdbIds.get(0);
122 assertEquals(pdbEntry.getId(), "1GAQ");
123 StructureViewer structureViewer = new StructureViewer(af.getViewport()
124 .getStructureSelectionManager());
125 chimeraViewer = structureViewer.viewStructures(pdbEntry,
126 new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
127 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
131 * Wait for viewer load thread to complete
133 while (!binding.isFinishedInit())
138 } catch (InterruptedException e)
143 assertTrue(binding.isChimeraRunning(), "Failed to start Chimera");
145 assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
146 chimeraViewer.closeViewer(true);
147 chimeraViewer = null;
152 * Test for writing Jalview features as attributes on mapped residues in
153 * Chimera. Note this uses local copies of PDB and SIFTS file, no network
154 * connection required.
156 * @throws IOException
157 * @throws SiftsException
159 // External as this requires a local install of Chimera
160 @Test(groups = { "External" })
161 public void testTransferFeatures() throws IOException, SiftsException
163 String inFile = "examples/uniref50.fa";
164 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
166 assertNotNull(af, "Failed to create AlignFrame");
167 SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
168 assertNotNull(sq, "Didn't find FER2_ARATH");
171 * need a Uniprot dbref for SIFTS mapping to work!!
173 sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
176 * use local test PDB and SIFTS files
178 String pdbFilePath = new File(
179 "test/jalview/ext/rbvi/chimera/4zho.pdb").getPath();
180 PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
181 String siftsFilePath = new File(
182 "test/jalview/ext/rbvi/chimera/4zho.xml.gz")
184 SiftsClient.setMockSiftsFile(new File(siftsFilePath));
186 StructureViewer structureViewer = new StructureViewer(af.getViewport()
187 .getStructureSelectionManager());
188 chimeraViewer = structureViewer.viewStructures(pdbEntry,
189 new SequenceI[] { sq }, af.getCurrentView().getAlignPanel());
191 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
198 } catch (InterruptedException e)
201 } while (!binding.isFinishedInit());
203 assertTrue(binding.isChimeraRunning(), "Failed to launch Chimera");
205 assertEquals(binding.getPdbCount(), 1);
208 * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
209 * (or possibly 52-145 to 1-94 - see JAL-2319)
211 StructureSelectionManager ssm = binding.getSsm();
212 String pdbFile = binding.getPdbFile()[0];
213 StructureMapping[] mappings = ssm.getMapping(pdbFile);
214 assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
215 "Failed to perform SIFTS mapping");
216 assertEquals(mappings.length, 2);
217 assertEquals(mappings[0].getChain(), "A");
218 assertEquals(mappings[0].getPDBResNum(53), 2);
219 assertEquals(mappings[0].getPDBResNum(145), 94);
220 assertEquals(mappings[1].getChain(), "B");
221 assertEquals(mappings[1].getPDBResNum(53), 2);
222 assertEquals(mappings[1].getPDBResNum(145), 94);
225 * now add some features to FER2_ARATH
227 // feature on a sequence region not mapped to structure:
228 sq.addSequenceFeature(new SequenceFeature("transit peptide",
229 "chloroplast", 1, 51, Float.NaN, null));
230 // feature on a region mapped to structure:
231 sq.addSequenceFeature(new SequenceFeature("domain",
232 "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
233 // on sparse positions of the sequence
234 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
235 "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
236 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
237 "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
238 // on a sequence region that is partially mapped to structure:
239 sq.addSequenceFeature(new SequenceFeature("helix", null, 50, 60,
242 sq.addSequenceFeature(new SequenceFeature("chain", null, 50, 70,
244 // add numeric valued features - score is set as attribute value
245 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
247 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
251 * set all features visible except for chain
253 af.setShowSeqFeatures(true);
254 FeatureRenderer fr = af.getFeatureRenderer();
255 fr.setVisible("transit peptide");
256 fr.setVisible("domain");
257 fr.setVisible("metal ion-binding site");
258 fr.setVisible("helix");
262 * 'perform' menu action to copy visible features to
263 * attributes in Chimera
265 // TODO rename and pull up method to binding interface
266 // once functionality is added for Jmol as well
267 binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
270 * give Chimera time to open the commands file and execute it
275 } catch (InterruptedException e)
280 * ask Chimera for its residue attribute names
282 List<String> reply = binding.sendChimeraCommand("list resattr", true);
283 // prefixed and sanitised attribute names for Jalview features:
284 assertTrue(reply.contains("resattr jv_domain"));
285 assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
286 assertTrue(reply.contains("resattr jv_helix"));
287 assertTrue(reply.contains("resattr jv_kd"));
288 // feature is not on a mapped region - no attribute created
289 assertFalse(reply.contains("resattr jv_transit_peptide"));
290 // feature is not visible - no attribute created
291 assertFalse(reply.contains("resattr jv_chain"));
294 * ask Chimera for residues with an attribute
295 * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
297 reply = binding.sendChimeraCommand(
298 "list resi att jv_metal_ion_binding_site", true);
299 assertEquals(reply.size(), 4);
301 .contains("residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
303 .contains("residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
305 .contains("residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
307 .contains("residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
310 * check attributes with score values
311 * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
313 reply = binding.sendChimeraCommand("list resi att jv_kd", true);
314 assertEquals(reply.size(), 4);
315 assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
316 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
317 assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
318 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
321 * list residues with positive kd score
323 reply = binding.sendChimeraCommand(
324 "list resi spec :*/jv_kd>0 attr jv_kd", true);
325 assertEquals(reply.size(), 2);
326 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
327 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
329 SiftsClient.setMockSiftsFile(null);
330 chimeraViewer.closeViewer(true);
331 chimeraViewer = null;