Clover icon

Coverage Report

  1. Project Clover database Wed Dec 3 2025 17:03:17 GMT
  2. Package jalview.ext.rbvi.chimera

File JalviewChimeraView.java

 

Code metrics

20
170
8
1
525
337
24
0.14
21.25
8
3

Classes

Class Line # Actions
JalviewChimeraView 64 170 24
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.ext.rbvi.chimera;
22   
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;
27   
28    import java.io.File;
29    import java.io.IOException;
30    import java.util.List;
31    import java.util.Vector;
32   
33    import org.testng.annotations.AfterClass;
34    import org.testng.annotations.AfterMethod;
35    import org.testng.annotations.BeforeClass;
36    import org.testng.annotations.Test;
37   
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;
62   
63    @Test(singleThreaded = true)
 
64    public class JalviewChimeraView
65    {
66   
 
67  0 toggle @BeforeClass(alwaysRun = true)
68    public void setUpJvOptionPane()
69    {
70  0 JvOptionPane.setInteractiveMode(false);
71  0 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
72    }
73   
74    private JalviewStructureDisplayI chimeraViewer;
75   
76    /**
77    * @throws java.lang.Exception
78    */
 
79  0 toggle @BeforeClass(alwaysRun = true)
80    public static void setUpBeforeClass() throws Exception
81    {
82  0 Jalview.main(
83    new String[]
84    { "--noquestionnaire", "--nonews", "--props",
85    "test/jalview/ext/rbvi/chimera/testProps.jvprops" });
86  0 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
87    ViewerType.CHIMERA.name());
88  0 Cache.setProperty("SHOW_ANNOTATIONS", "false");
89  0 Cache.setProperty(Preferences.STRUCT_FROM_PDB, "false");
90  0 Cache.setProperty(Preferences.STRUCTURE_DISPLAY,
91    ViewerType.CHIMERA.name());
92  0 Cache.setProperty("MAP_WITH_SIFTS", "true");
93    // TODO this should not be necessary!
94  0 SiftsSettings.setMapWithSifts(true);
95    }
96   
97    /**
98    * @throws java.lang.Exception
99    */
 
100  0 toggle @AfterClass(alwaysRun = true)
101    public static void tearDownAfterClass() throws Exception
102    {
103  0 if (Desktop.getInstance()!=null) {
104  0 Desktop.getInstance().closeAll_actionPerformed(null);
105    }
106    }
107   
 
108  0 toggle @AfterMethod(alwaysRun = true)
109    public void tearDownAfterTest() throws Exception
110    {
111  0 SiftsClient.setMockSiftsFile(null);
112  0 if (chimeraViewer != null)
113    {
114  0 chimeraViewer.closeViewer(true);
115    }
116    }
117   
118    /**
119    * Load 1GAQ and view the first structure for which a PDB id is found. Note no
120    * network connection is needed - PDB file is read locally, SIFTS fetch fails
121    * so mapping falls back to Needleman-Wunsch - ok for this test.
122    */
123    // External as local install of Chimera required
 
124  0 toggle @Test(groups = { "External" })
125    public void testSingleSeqViewChimera()
126    {
127   
128  0 String inFile = "examples/1gaq.txt";
129  0 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
130    DataSourceType.FILE);
131  0 assertNotNull(af, "Failed to create AlignFrame");
132  0 SequenceI sq = af.getViewport().getAlignment().getSequenceAt(0);
133  0 assertEquals(sq.getName(), "1GAQ|A");
134  0 SequenceI dsq = sq.getDatasetSequence();
135  0 Vector<PDBEntry> pdbIds = dsq.getAllPDBEntries();
136  0 assertEquals(pdbIds.size(), 1);
137  0 PDBEntry pdbEntry = pdbIds.get(0);
138  0 assertEquals(pdbEntry.getId(), "1GAQ");
139  0 StructureViewer structureViewer = new StructureViewer(
140    af.getViewport().getStructureSelectionManager());
141  0 chimeraViewer = structureViewer.viewStructures(pdbEntry,
142    new SequenceI[]
143    { sq }, af.getCurrentView().getAlignPanel());
144  0 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
145    .getBinding();
146   
147    /*
148    * Wait for viewer load thread to complete
149    */
150  0 do
151    {
152  0 try
153    {
154  0 Thread.sleep(500);
155    } catch (InterruptedException e)
156    {
157    }
158  0 } while (!binding.isFinishedInit() || !chimeraViewer.isVisible());
159   
160  0 assertTrue(binding.isViewerRunning(), "Failed to start Chimera");
161   
162  0 assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
163  0 assertTrue(chimeraViewer.hasViewerActionsMenu());
164   
165    // now add another sequence and bind to view
166    //
167  0 AlignmentI al = af.getViewport().getAlignment();
168  0 PDBEntry xpdb = al.getSequenceAt(0).getPDBEntry("1GAQ");
169  0 sq = new Sequence("1GAQ",
170    al.getSequenceAt(0).getSequence(25, 95).toString());
171  0 al.addSequence(sq);
172  0 structureViewer.viewStructures(new PDBEntry[] { xpdb },
173    new SequenceI[]
174    { sq }, af.getCurrentView().getAlignPanel());
175   
176    /*
177    * Wait for viewer load thread to complete
178    */
179  0 do
180    {
181  0 try
182    {
183  0 Thread.sleep(1500);
184    } catch (InterruptedException q)
185    {
186    }
187  0 ;
188  0 } while (!binding.isLoadingFinished());
189   
190    // still just one PDB structure shown
191  0 assertEquals(chimeraViewer.getBinding().getPdbCount(), 1);
192    // and the viewer action menu should still be visible
193  0 assertTrue(chimeraViewer.hasViewerActionsMenu());
194   
195  0 chimeraViewer.closeViewer(true);
196  0 chimeraViewer = null;
197  0 return;
198    }
199   
200    /**
201    * Test for writing Jalview features as attributes on mapped residues in
202    * Chimera. Note this uses local copies of PDB and SIFTS file, no network
203    * connection required.
204    *
205    * @throws IOException
206    * @throws SiftsException
207    */
208    // External as this requires a local install of Chimera
 
209  0 toggle @Test(groups = { "External" })
210    public void testTransferFeatures() throws IOException, SiftsException
211    {
212  0 String inFile = "examples/uniref50.fa";
213  0 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
214    DataSourceType.FILE);
215  0 assertNotNull(af, "Failed to create AlignFrame");
216  0 SequenceI sq = af.getViewport().getAlignment().findName("FER2_ARATH");
217  0 assertNotNull(sq, "Didn't find FER2_ARATH");
218   
219    /*
220    * need a Uniprot dbref for SIFTS mapping to work!!
221    */
222  0 sq.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
223   
224    /*
225    * use local test PDB and SIFTS files
226    */
227  0 String pdbFilePath = new File("test/jalview/ext/rbvi/chimera/4zho.pdb")
228    .getPath();
229  0 PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
230  0 String siftsFilePath = new File(
231    "test/jalview/ext/rbvi/chimera/4zho.xml.gz").getPath();
232  0 SiftsClient.setMockSiftsFile(new File(siftsFilePath));
233   
234  0 StructureViewer structureViewer = new StructureViewer(
235    af.getViewport().getStructureSelectionManager());
236  0 chimeraViewer = structureViewer.viewStructures(pdbEntry,
237    new SequenceI[]
238    { sq }, af.getCurrentView().getAlignPanel());
239   
240  0 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
241    .getBinding();
242  0 do
243    {
244  0 try
245    {
246  0 Thread.sleep(500);
247    } catch (InterruptedException e)
248    {
249    }
250  0 } while (!binding.isFinishedInit());
251   
252  0 assertTrue(binding.isViewerRunning(), "Failed to launch Chimera");
253   
254  0 assertEquals(binding.getPdbCount(), 1);
255   
256    /*
257    * check mapping is (sequence) 53-145 to (structure) 2-94 A/B
258    * (or possibly 52-145 to 1-94 - see JAL-2319)
259    */
260  0 StructureSelectionManager ssm = binding.getSsm();
261  0 String pdbFile = binding.getStructureFiles()[0];
262  0 StructureMapping[] mappings = ssm.getMapping(pdbFile);
263  0 assertTrue(mappings[0].getMappingDetailsOutput().contains("SIFTS"),
264    "Failed to perform SIFTS mapping");
265  0 assertEquals(mappings.length, 2);
266  0 assertEquals(mappings[0].getChain(), "A");
267  0 assertEquals(mappings[0].getPDBResNum(53), 2);
268  0 assertEquals(mappings[0].getPDBResNum(145), 94);
269  0 assertEquals(mappings[1].getChain(), "B");
270  0 assertEquals(mappings[1].getPDBResNum(53), 2);
271  0 assertEquals(mappings[1].getPDBResNum(145), 94);
272   
273    /*
274    * now add some features to FER2_ARATH
275    */
276    // feature on a sequence region not mapped to structure:
277  0 sq.addSequenceFeature(new SequenceFeature("transit peptide",
278    "chloroplast", 1, 51, Float.NaN, null));
279    // feature on a region mapped to structure:
280  0 sq.addSequenceFeature(new SequenceFeature("domain",
281    "2Fe-2S ferredoxin-type", 55, 145, Float.NaN, null));
282    // on sparse positions of the sequence
283  0 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
284    "Iron-Sulfur (2Fe-2S)", 91, 91, Float.NaN, null));
285  0 sq.addSequenceFeature(new SequenceFeature("metal ion-binding site",
286    "Iron-Sulfur (2Fe-2S)", 96, 96, Float.NaN, null));
287    // on a sequence region that is partially mapped to structure:
288  0 sq.addSequenceFeature(
289    new SequenceFeature("helix", null, 50, 60, Float.NaN, null));
290    // and again:
291  0 sq.addSequenceFeature(
292    new SequenceFeature("chain", null, 50, 70, Float.NaN, null));
293    // add numeric valued features - score is set as attribute value
294  0 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 62,
295    62, -2.1f, null));
296  0 sq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 65,
297    65, 3.6f, null));
298  0 sq.addSequenceFeature(new SequenceFeature("RESNUM", "ALA: 2 4zhoA",
299    53, 53, Float.NaN, null));
300   
301    /*
302    * set all features visible except for chain
303    */
304  0 af.setShowSeqFeatures(true);
305  0 FeatureRenderer fr = af.getFeatureRenderer();
306  0 fr.setVisible("transit peptide");
307  0 fr.setVisible("domain");
308  0 fr.setVisible("metal ion-binding site");
309  0 fr.setVisible("helix");
310  0 fr.setVisible("kd");
311  0 fr.setVisible("RESNUM");
312   
313    /*
314    * 'perform' menu action to copy visible features to
315    * attributes in Chimera
316    */
317    // TODO rename and pull up method to binding interface
318    // once functionality is added for Jmol as well
319  0 binding.sendFeaturesToViewer(af.getViewport().getAlignPanel());
320   
321    /*
322    * give Chimera time to open the commands file and execute it
323    */
324  0 try
325    {
326  0 Thread.sleep(1000);
327    } catch (InterruptedException e)
328    {
329    }
330   
331    /*
332    * ask Chimera for its residue attribute names
333    */
334  0 List<String> reply = binding
335    .executeCommand(new StructureCommand("list resattr"), true);
336    // prefixed and sanitised attribute names for Jalview features:
337  0 assertTrue(reply.contains("resattr jv_domain"));
338  0 assertTrue(reply.contains("resattr jv_metal_ion_binding_site"));
339  0 assertTrue(reply.contains("resattr jv_helix"));
340  0 assertTrue(reply.contains("resattr jv_kd"));
341  0 assertTrue(reply.contains("resattr jv_RESNUM"));
342    // feature is not on a mapped region - no attribute created
343  0 assertFalse(reply.contains("resattr jv_transit_peptide"));
344    // feature is not visible - no attribute created
345  0 assertFalse(reply.contains("resattr jv_chain"));
346   
347    /*
348    * ask Chimera for residues with an attribute
349    * 91 and 96 on sequence --> residues 40 and 45 on chains A and B
350    */
351  0 reply = binding.executeCommand(
352    new StructureCommand("list resi att jv_metal_ion_binding_site"),
353    true);
354  0 assertEquals(reply.size(), 4);
355  0 assertTrue(reply.contains(
356    "residue id #0:40.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
357  0 assertTrue(reply.contains(
358    "residue id #0:45.A jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
359  0 assertTrue(reply.contains(
360    "residue id #0:40.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 40"));
361  0 assertTrue(reply.contains(
362    "residue id #0:45.B jv_metal_ion_binding_site \"Iron-Sulfur (2Fe-2S)\" index 45"));
363   
364    /*
365    * check attributes with score values
366    * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B
367    */
368  0 reply = binding.executeCommand(
369    new StructureCommand("list resi att jv_kd"), true);
370  0 assertEquals(reply.size(), 4);
371  0 assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11"));
372  0 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
373  0 assertTrue(reply.contains("residue id #0:11.B jv_kd -2.1 index 11"));
374  0 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
375   
376    /*
377    * list residues with positive kd score
378    */
379  0 reply = binding.executeCommand(
380    new StructureCommand("list resi spec :*/jv_kd>0 attr jv_kd"),
381    true);
382  0 assertEquals(reply.size(), 2);
383  0 assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14"));
384  0 assertTrue(reply.contains("residue id #0:14.B jv_kd 3.6 index 14"));
385   
386  0 SiftsClient.setMockSiftsFile(null);
387  0 chimeraViewer.closeViewer(true);
388  0 chimeraViewer = null;
389    }
390   
391    /**
392    * Test for creating Jalview features from attributes on mapped residues in
393    * Chimera. Note this uses local copies of PDB and SIFTS file, no network
394    * connection required.
395    *
396    * @throws IOException
397    * @throws SiftsException
398    */
399    // External as this requires a local install of Chimera
 
400  0 toggle @Test(groups = { "External" })
401    public void testGetAttributes() throws IOException, SiftsException
402    {
403  0 String inFile = "examples/uniref50.fa";
404  0 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
405    DataSourceType.FILE);
406  0 assertNotNull(af, "Failed to create AlignFrame");
407  0 SequenceI fer2Arath = af.getViewport().getAlignment()
408    .findName("FER2_ARATH");
409  0 assertNotNull(fer2Arath, "Didn't find FER2_ARATH");
410   
411    /*
412    * need a Uniprot dbref for SIFTS mapping to work!!
413    */
414  0 fer2Arath.addDBRef(new DBRefEntry("UNIPROT", "0", "P16972", null));
415   
416    /*
417    * use local test PDB and SIFTS files
418    */
419  0 String pdbFilePath = new File("test/jalview/ext/rbvi/chimera/4zho.pdb")
420    .getPath();
421  0 PDBEntry pdbEntry = new PDBEntry("4ZHO", null, null, pdbFilePath);
422  0 String siftsFilePath = new File(
423    "test/jalview/ext/rbvi/chimera/4zho.xml.gz").getPath();
424  0 SiftsClient.setMockSiftsFile(new File(siftsFilePath));
425   
426  0 StructureViewer structureViewer = new StructureViewer(
427    af.getViewport().getStructureSelectionManager());
428  0 chimeraViewer = structureViewer.viewStructures(pdbEntry,
429    new SequenceI[]
430    { fer2Arath }, af.getCurrentView().getAlignPanel());
431   
432  0 JalviewChimeraBinding binding = (JalviewChimeraBinding) chimeraViewer
433    .getBinding();
434  0 do
435    {
436  0 try
437    {
438  0 Thread.sleep(500);
439    } catch (InterruptedException e)
440    {
441    }
442  0 } while (!binding.isFinishedInit());
443   
444  0 assertTrue(binding.isViewerRunning(), "Failed to launch Chimera");
445   
446  0 assertEquals(binding.getPdbCount(), 1);
447   
448    /*
449    * 'perform' menu action to copy Chimera attributes
450    * to features in Jalview
451    */
452    // TODO rename and pull up method to binding interface
453    // once functionality is added for Jmol as well
454  0 binding.copyStructureAttributesToFeatures("isHelix",
455    af.getViewport().getAlignPanel());
456   
457    /*
458    * verify 22 residues have isHelix feature
459    * (may merge into ranges in future)
460    */
461  0 af.setShowSeqFeatures(true);
462  0 FeatureRenderer fr = af.getFeatureRenderer();
463  0 fr.setVisible("isHelix");
464  0 for (int res = 75; res <= 83; res++)
465    {
466  0 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
467    }
468  0 for (int res = 117; res <= 123; res++)
469    {
470  0 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
471    }
472  0 for (int res = 129; res <= 131; res++)
473    {
474  0 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
475    }
476  0 for (int res = 143; res <= 145; res++)
477    {
478  0 checkFeaturesAtRes(fer2Arath, fr, res, "isHelix");
479    }
480   
481    /*
482    * fetch a numeric valued attribute
483    */
484  0 binding.copyStructureAttributesToFeatures("phi",
485    af.getViewport().getAlignPanel());
486  0 fr.setVisible("phi");
487  0 List<SequenceFeature> fs = fer2Arath.getFeatures().findFeatures(54, 54,
488    "phi");
489  0 assertEquals(fs.size(), 2);
490  0 assertTrue(fs.contains(new SequenceFeature("phi", "A", 54, 54,
491    -131.0713f, "Chimera")));
492  0 assertTrue(fs.contains(new SequenceFeature("phi", "B", 54, 54,
493    -127.39512f, "Chimera")));
494   
495    /*
496    * tear down - also in AfterMethod
497    */
498  0 SiftsClient.setMockSiftsFile(null);
499  0 chimeraViewer.closeViewer(true);
500  0 chimeraViewer = null;
501    }
502   
503    /**
504    * Helper method to verify new feature at a sequence position
505    *
506    * @param seq
507    * @param fr
508    * @param res
509    * @param featureType
510    */
 
511  0 toggle protected void checkFeaturesAtRes(SequenceI seq, FeatureRenderer fr,
512    int res, String featureType)
513    {
514  0 String where = "at position " + res;
515  0 List<SequenceFeature> fs = seq.getFeatures().findFeatures(res, res,
516    featureType);
517   
518  0 assertEquals(fs.size(), 1, where);
519  0 SequenceFeature sf = fs.get(0);
520  0 assertEquals(sf.getType(), featureType, where);
521  0 assertEquals(sf.getFeatureGroup(), "Chimera", where);
522  0 assertEquals(sf.getDescription(), "True", where);
523  0 assertEquals(sf.getScore(), Float.NaN, where);
524    }
525    }