1 package jalview.ext.pymol;
4 import java.util.ArrayList;
5 import java.util.Arrays;
9 import jalview.structure.AtomSpecModel;
10 import jalview.structure.StructureCommand;
11 import jalview.structure.StructureCommandI;
12 import jalview.structure.StructureCommandsBase;
15 * A class that generates commands to send to PyMol over its XML-RPC interface.
17 * Note that because the xml-rpc interface can only accept one command at a
18 * time, we can't concatenate commands, and must instead form and send them
21 * @see https://pymolwiki.org/index.php/Category:Commands
22 * @see https://pymolwiki.org/index.php/RPC
24 public class PymolCommands extends StructureCommandsBase
26 // https://pymol.org/dokuwiki/doku.php?id=command:zoom
27 // not currently documented on
28 // https://pymolwiki.org/index.php/Category:Commands
29 private static final StructureCommand FOCUS_VIEW = new StructureCommand(
32 // https://pymolwiki.org/index.php/Quit
33 private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
36 // not currently documented on
37 // https://pymolwiki.org/index.php/Category:Commands
38 private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
41 private static final List<StructureCommandI> COLOR_BY_CHARGE = Arrays
42 .asList(new StructureCommand("color", "white", "*"),
43 new StructureCommand("color", "red", "resn ASP resn GLU"),
44 new StructureCommand("color", "blue",
46 new StructureCommand("color", "yellow", "resn CYS"));
48 private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
49 .asList(new StructureCommand("hide", "everything"),
50 new StructureCommand("show", "ribbon"));
53 public StructureCommandI colourByChain()
55 return COLOUR_BY_CHAIN;
59 public List<StructureCommandI> colourByCharge()
61 return COLOR_BY_CHARGE;
65 public StructureCommandI setBackgroundColour(Color col)
67 // https://pymolwiki.org/index.php/Bg_Color
68 return new StructureCommand("bg_color", getColourString(col));
72 * Returns a colour formatted suitable for use in viewer command syntax. For
73 * example, red is {@code "0xff0000"}.
78 protected String getColourString(Color c)
80 return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
85 public StructureCommandI focusView()
91 public List<StructureCommandI> showChains(List<String> toShow)
93 // https://pymolwiki.org/index.php/Show
94 List<StructureCommandI> commands = new ArrayList<>();
95 commands.add(new StructureCommand("hide", "everything"));
96 commands.add(new StructureCommand("show", "lines"));
97 StringBuilder chains = new StringBuilder();
98 for (String chain : toShow)
100 chains.append(" chain ").append(chain);
103 new StructureCommand("show", "cartoon", chains.toString()));
108 public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
109 AtomSpecModel atomSpec, AtomSpecType specType)
112 // https://pymolwiki.org/index.php/Super
113 List<StructureCommandI> commands = new ArrayList<>();
114 String refAtomsAlphaOnly = "("+getAtomSpec(refAtoms, specType)+" and (altloc '' or altloc 'a'))";
115 String atomSpec2AlphaOnly = "("+getAtomSpec(atomSpec, specType)+" and (altloc '' or altloc 'a'))";
116 // pair_fit mobile -> reference
117 // crashes when undo is enabled on 2.5.2 (incentive)
118 commands.add(new StructureCommand("undo_disable"));
119 commands.add(new StructureCommand("pair_fit",
120 atomSpec2AlphaOnly, refAtomsAlphaOnly));
121 commands.add(new StructureCommand("undo_enable"));
124 * and show superposed residues as cartoon
126 String refAtomsAll = getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY);
127 String atomSpec2All = getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY);
128 commands.add(new StructureCommand("show", "cartoon",
129 refAtomsAll + " " + atomSpec2All));
135 public StructureCommandI openCommandFile(String path)
137 // https://pymolwiki.org/index.php/Run
138 return new StructureCommand("run", path); // should be .pml
142 public StructureCommandI saveSession(String filepath)
144 // https://pymolwiki.org/index.php/Save#EXAMPLES
145 return new StructureCommand("save", filepath); // should be .pse
149 * Returns a selection string in PyMOL 'selection macro' format:
152 * modelId// chain/residues/
155 * If more than one chain, makes a selection expression for each, and they are
156 * separated by spaces.
158 * @see https://pymolwiki.org/index.php/Selection_Macros
161 public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
163 StringBuilder sb = new StringBuilder(64);
164 boolean first = true;
165 for (String modelId : model.getModels())
167 for (String chain : model.getChains(modelId))
174 List<int[]> rangeList = model.getRanges(modelId, chain);
175 chain = chain.trim();
176 sb.append(modelId).append("//").append(chain).append("/");
177 boolean firstRange = true;
178 for (int[] range : rangeList)
185 sb.append(String.valueOf(range[0]));
186 if (range[0] != range[1])
188 sb.append("-").append(String.valueOf(range[1]));
192 if (specType == AtomSpecType.ALPHA)
196 if (specType == AtomSpecType.PHOSPHATE)
202 return sb.toString();
206 public List<StructureCommandI> showBackbone()
208 return SHOW_BACKBONE;
212 protected StructureCommandI colourResidues(String atomSpec, Color colour)
214 // https://pymolwiki.org/index.php/Color
215 return new StructureCommand("color", getColourString(colour), atomSpec);
219 protected String getResidueSpec(String residue)
221 // https://pymolwiki.org/index.php/Selection_Algebra
222 return "resn " + residue;
226 public StructureCommandI loadFile(String file)
228 return new StructureCommand("load", file);
232 * Overrides the default implementation (which generates concatenated
233 * commands) to generate one per colour (because the XML-RPC interface to
234 * PyMOL only accepts one command at a time)
240 public List<StructureCommandI> colourBySequence(
241 Map<Object, AtomSpecModel> colourMap)
243 List<StructureCommandI> commands = new ArrayList<>();
244 for (Object key : colourMap.keySet())
246 Color colour = (Color) key;
247 final AtomSpecModel colourData = colourMap.get(colour);
248 commands.add(getColourCommand(colourData, colour));
255 * Returns a viewer command to set the given atom property value on atoms
256 * specified by the AtomSpecModel, for example
259 * iterate 4zho//B/12-34,48-55/CA,jv_chain='primary'
262 * @param attributeName
263 * @param attributeValue
264 * @param atomSpecModel
267 protected StructureCommandI setAttribute(String attributeName,
268 String attributeValue, AtomSpecModel atomSpecModel)
270 StringBuilder sb = new StringBuilder(128);
271 sb.append("p.").append(attributeName).append("='")
272 .append(attributeValue).append("'");
273 String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
274 return new StructureCommand("iterate", atomSpec, sb.toString());
278 * Traverse the map of features/values/models/chains/positions to construct a
279 * list of 'set property' commands (one per distinct feature type and value).
280 * The values are stored in the 'p' dictionary of user-defined properties of
283 * The format of each command is
286 * <blockquote> iterate atomspec, p.featureName='value'
287 * e.g. iterate 4zho//A/23,28-29/CA, p.jv_Metal='Fe'
295 public List<StructureCommandI> setAttributes(
296 Map<String, Map<Object, AtomSpecModel>> featureMap)
298 List<StructureCommandI> commands = new ArrayList<>();
299 for (String featureType : featureMap.keySet())
301 String attributeName = makeAttributeName(featureType);
304 * todo: clear down existing attributes for this feature?
306 // commands.add(new StructureCommand("iterate", "all",
307 // "p."+attributeName+"='None'"); //?
309 Map<Object, AtomSpecModel> values = featureMap.get(featureType);
310 for (Object value : values.keySet())
313 * for each distinct value recorded for this feature type,
314 * add a command to set the attribute on the mapped residues
315 * Put values in single quotes, encoding any embedded single quotes
317 AtomSpecModel atomSpecModel = values.get(value);
318 String featureValue = value.toString();
319 featureValue = featureValue.replaceAll("\\'", "'");
320 StructureCommandI cmd = setAttribute(attributeName, featureValue,
330 public StructureCommandI openSession(String filepath)
332 // https://pymolwiki.org/index.php/Load
333 // this version of the command has no dependency on file extension
334 return new StructureCommand("load", filepath, "", "0", "pse");
338 public StructureCommandI closeViewer()
340 // https://pymolwiki.org/index.php/Quit