Clover icon

Coverage Report

  1. Project Clover database Wed Nov 6 2024 00:56:24 GMT
  2. Package jalview.ext.pymol

File PymolCommands.java

 

Coverage histogram

../../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

10
77
20
1
373
219
25
0.32
3.85
20
1.25

Classes

Class Line # Actions
PymolCommands 44 77 25
0.859813186%
 

Contributing tests

This file is covered by 17 tests. .

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.pymol;
22   
23    import java.awt.Color;
24    import java.util.ArrayList;
25    import java.util.Arrays;
26    import java.util.List;
27    import java.util.Map;
28   
29    import jalview.structure.AtomSpecModel;
30    import jalview.structure.StructureCommand;
31    import jalview.structure.StructureCommandI;
32    import jalview.structure.StructureCommandsBase;
33   
34    /**
35    * A class that generates commands to send to PyMol over its XML-RPC interface.
36    * <p>
37    * Note that because the xml-rpc interface can only accept one command at a
38    * time, we can't concatenate commands, and must instead form and send them
39    * individually.
40    *
41    * @see https://pymolwiki.org/index.php/Category:Commands
42    * @see https://pymolwiki.org/index.php/RPC
43    */
 
44    public class PymolCommands extends StructureCommandsBase
45    {
46    // https://pymol.org/dokuwiki/doku.php?id=command:zoom
47    // not currently documented on
48    // https://pymolwiki.org/index.php/Category:Commands
49    private static final StructureCommand FOCUS_VIEW = new StructureCommand(
50    "zoom");
51   
52    // https://pymolwiki.org/index.php/Quit
53    private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
54    "quit");
55   
56    // not currently documented on
57    // https://pymolwiki.org/index.php/Category:Commands
58    private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
59    "spectrum", "chain");
60   
61    private static final List<StructureCommandI> COLOR_BY_CHARGE = Arrays
62    .asList(new StructureCommand("color", "white", "*"),
63    new StructureCommand("color", "red", "resn ASP resn GLU"),
64    new StructureCommand("color", "blue",
65    "resn LYS resn ARG"),
66    new StructureCommand("color", "yellow", "resn CYS"));
67   
68    private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
69    .asList(new StructureCommand("hide", "everything"),
70    new StructureCommand("show", "ribbon"));
71   
 
72  1 toggle @Override
73    public StructureCommandI colourByChain()
74    {
75  1 return COLOUR_BY_CHAIN;
76    }
77   
 
78  1 toggle @Override
79    public List<StructureCommandI> colourByCharge()
80    {
81  1 return COLOR_BY_CHARGE;
82    }
83   
 
84  1 toggle @Override
85    public StructureCommandI setBackgroundColour(Color col)
86    {
87    // https://pymolwiki.org/index.php/Bg_Color
88  1 return new StructureCommand("bg_color", getColourString(col));
89    }
90   
91    /**
92    * Returns a colour formatted suitable for use in viewer command syntax. For
93    * example, red is {@code "0xff0000"}.
94    *
95    * @param c
96    * @return
97    */
 
98  5 toggle protected String getColourString(Color c)
99    {
100  5 return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
101    c.getBlue());
102    }
103   
 
104  0 toggle @Override
105    public StructureCommandI focusView()
106    {
107  0 return FOCUS_VIEW;
108    }
109   
 
110  0 toggle @Override
111    public List<StructureCommandI> showChains(List<String> toShow)
112    {
113    // https://pymolwiki.org/index.php/Show
114  0 List<StructureCommandI> commands = new ArrayList<>();
115  0 commands.add(new StructureCommand("hide", "everything"));
116  0 commands.add(new StructureCommand("show", "lines"));
117  0 StringBuilder chains = new StringBuilder();
118  0 for (String chain : toShow)
119    {
120  0 chains.append(" chain ").append(chain);
121    }
122  0 commands.add(
123    new StructureCommand("show", "cartoon", chains.toString()));
124  0 return commands;
125    }
126   
 
127  1 toggle @Override
128    public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
129    AtomSpecModel atomSpec, AtomSpecType specType)
130    {
131   
132    // https://pymolwiki.org/index.php/Super
133  1 List<StructureCommandI> commands = new ArrayList<>();
134  1 String refAtomsAlphaOnly = "(" + getAtomSpec(refAtoms, specType)
135    + " and (altloc '' or altloc 'a'))";
136  1 String atomSpec2AlphaOnly = "(" + getAtomSpec(atomSpec, specType)
137    + " and (altloc '' or altloc 'a'))";
138    // pair_fit mobile -> reference
139    // crashes when undo is enabled on 2.5.2 (incentive)
140  1 commands.add(new StructureCommand("undo_disable"));
141  1 commands.add(new StructureCommand("pair_fit", atomSpec2AlphaOnly,
142    refAtomsAlphaOnly));
143  1 commands.add(new StructureCommand("undo_enable"));
144   
145    /*
146    * and show superposed residues as cartoon
147    */
148  1 String refAtomsAll = getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY);
149  1 String atomSpec2All = getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY);
150  1 commands.add(new StructureCommand("show", "cartoon",
151    refAtomsAll + " " + atomSpec2All));
152   
153  1 return commands;
154    }
155   
 
156  1 toggle @Override
157    public StructureCommandI openCommandFile(String path)
158    {
159    // https://pymolwiki.org/index.php/Run
160  1 return new StructureCommand("run", path); // should be .pml
161    }
162   
 
163  1 toggle @Override
164    public StructureCommandI saveSession(String filepath)
165    {
166    // https://pymolwiki.org/index.php/Save#EXAMPLES
167  1 return new StructureCommand("save", filepath); // should be .pse
168    }
169   
170    /**
171    * Returns a selection string in PyMOL 'selection macro' format:
172    *
173    * <pre>
174    * modelId// chain/residues/
175    * </pre>
176    *
177    * If more than one chain, makes a selection expression for each, and they are
178    * separated by spaces.
179    *
180    * @see https://pymolwiki.org/index.php/Selection_Macros
181    */
 
182  36 toggle @Override
183    public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
184    {
185  36 StringBuilder sb = new StringBuilder(64);
186  36 boolean first = true;
187  36 for (String modelId : model.getModels())
188    {
189  52 for (String chain : model.getChains(modelId))
190    {
191  86 if (!first)
192    {
193  52 sb.append(" ");
194    }
195  86 first = false;
196  86 List<int[]> rangeList = model.getRanges(modelId, chain);
197  86 chain = chain.trim();
198  86 sb.append(modelId).append("//").append(chain).append("/");
199  86 boolean firstRange = true;
200  86 for (int[] range : rangeList)
201    {
202  111 if (!firstRange)
203    {
204  25 sb.append("+");
205    }
206  111 firstRange = false;
207  111 sb.append(String.valueOf(range[0]));
208  111 if (range[0] != range[1])
209    {
210  86 sb.append("-").append(String.valueOf(range[1]));
211    }
212    }
213  86 sb.append("/");
214  86 if (specType == AtomSpecType.ALPHA)
215    {
216  34 sb.append("CA");
217    }
218  86 if (specType == AtomSpecType.PHOSPHATE)
219    {
220  0 sb.append("P");
221    }
222    }
223    }
224  36 return sb.toString();
225    }
226   
 
227  1 toggle @Override
228    public List<StructureCommandI> showBackbone()
229    {
230  1 return SHOW_BACKBONE;
231    }
232   
 
233  4 toggle @Override
234    protected StructureCommandI colourResidues(String atomSpec, Color colour)
235    {
236    // https://pymolwiki.org/index.php/Color
237  4 return new StructureCommand("color", getColourString(colour), atomSpec);
238    }
239   
 
240  1 toggle @Override
241    protected String getResidueSpec(String residue)
242    {
243    // https://pymolwiki.org/index.php/Selection_Algebra
244  1 return "resn " + residue;
245    }
246   
 
247  1 toggle @Override
248    public StructureCommandI loadFile(String file)
249    {
250  1 return new StructureCommand("load", file);
251    }
252   
253    /**
254    * Overrides the default implementation (which generates concatenated
255    * commands) to generate one per colour (because the XML-RPC interface to
256    * PyMOL only accepts one command at a time)
257    *
258    * @param colourMap
259    * @return
260    */
 
261  1 toggle @Override
262    public List<StructureCommandI> colourBySequence(
263    Map<Object, AtomSpecModel> colourMap)
264    {
265  1 List<StructureCommandI> commands = new ArrayList<>();
266  1 for (Object key : colourMap.keySet())
267    {
268  3 Color colour = (Color) key;
269  3 final AtomSpecModel colourData = colourMap.get(colour);
270  3 commands.add(getColourCommand(colourData, colour));
271    }
272   
273  1 return commands;
274    }
275   
276    /**
277    * Returns a viewer command to set the given atom property value on atoms
278    * specified by the AtomSpecModel, for example
279    *
280    * <pre>
281    * iterate 4zho//B/12-34,48-55/CA,jv_chain='primary'
282    * </pre>
283    *
284    * @param attributeName
285    * @param attributeValue
286    * @param atomSpecModel
287    * @return
288    */
 
289  7 toggle protected StructureCommandI setAttribute(String attributeName,
290    String attributeValue, AtomSpecModel atomSpecModel)
291    {
292  7 StringBuilder sb = new StringBuilder(128);
293  7 sb.append("p.").append(attributeName).append("='")
294    .append(attributeValue).append("'");
295  7 String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
296  7 return new StructureCommand("iterate", atomSpec, sb.toString());
297    }
298   
299    /**
300    * Traverse the map of features/values/models/chains/positions to construct a
301    * list of 'set property' commands (one per distinct feature type and value).
302    * The values are stored in the 'p' dictionary of user-defined properties of
303    * each atom.
304    * <p>
305    * The format of each command is
306    *
307    * <pre>
308    * <blockquote> iterate atomspec, p.featureName='value'
309    * e.g. iterate 4zho//A/23,28-29/CA, p.jv_Metal='Fe'
310    * </blockquote>
311    * </pre>
312    *
313    * @param featureMap
314    * @return
315    */
 
316  5 toggle @Override
317    public List<StructureCommandI> setAttributes(
318    Map<String, Map<Object, AtomSpecModel>> featureMap)
319    {
320  5 List<StructureCommandI> commands = new ArrayList<>();
321  5 for (String featureType : featureMap.keySet())
322    {
323  5 String attributeName = makeAttributeName(featureType);
324   
325    /*
326    * todo: clear down existing attributes for this feature?
327    */
328    // commands.add(new StructureCommand("iterate", "all",
329    // "p."+attributeName+"='None'"); //?
330   
331  5 Map<Object, AtomSpecModel> values = featureMap.get(featureType);
332  5 for (Object value : values.keySet())
333    {
334    /*
335    * for each distinct value recorded for this feature type,
336    * add a command to set the attribute on the mapped residues
337    * Put values in single quotes, encoding any embedded single quotes
338    */
339  6 AtomSpecModel atomSpecModel = values.get(value);
340  6 String featureValue = value.toString();
341  6 featureValue = featureValue.replaceAll("\\'", "&#39;");
342  6 StructureCommandI cmd = setAttribute(attributeName, featureValue,
343    atomSpecModel);
344  6 commands.add(cmd);
345    }
346    }
347   
348  5 return commands;
349    }
350   
 
351  1 toggle @Override
352    public StructureCommandI openSession(String filepath)
353    {
354    // https://pymolwiki.org/index.php/Load
355    // this version of the command has no dependency on file extension
356  1 return new StructureCommand("load", filepath, "", "0", "pse");
357    }
358   
 
359  1 toggle @Override
360    public StructureCommandI closeViewer()
361    {
362    // https://pymolwiki.org/index.php/Quit
363  1 return CLOSE_PYMOL;
364    }
365   
 
366  0 toggle @Override
367    public List<StructureCommandI> centerViewOn(List<AtomSpecModel> residues)
368    {
369    // TODO Auto-generated method stub
370  0 return null;
371    }
372   
373    }