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 private static final StructureCommand SHOW_RIBBON = new StructureCommand("show", "ribbon");
28 private static final StructureCommand SHOW_CARTOON = new StructureCommand("show", "cartoon");
30 private static final StructureCommand HIDE_EVERYTHING = new StructureCommand("hide", "everything");
32 // https://pymol.org/dokuwiki/doku.php?id=command:zoom
33 // not currently documented on
34 // https://pymolwiki.org/index.php/Category:Commands
35 private static final StructureCommand FOCUS_VIEW = new StructureCommand(
38 // https://pymolwiki.org/index.php/Quit
39 private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
42 // not currently documented on
43 // https://pymolwiki.org/index.php/Category:Commands
44 private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
46 private static final List<StructureCommandI> COLOR_BY_CHARGE = Arrays
47 .asList(new StructureCommand("color", "white", "*"),
48 new StructureCommand("color", "red", "resn ASP resn GLU"),
49 new StructureCommand("color", "blue",
51 new StructureCommand("color", "yellow", "resn CYS"));
53 private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
54 .asList(new StructureCommand("hide", "everything"),
55 new StructureCommand("show", "ribbon"));
58 public StructureCommandI colourByChain()
60 return COLOUR_BY_CHAIN;
64 public List<StructureCommandI> colourByCharge()
66 return COLOR_BY_CHARGE;
70 public StructureCommandI setBackgroundColour(Color col)
72 // https://pymolwiki.org/index.php/Bg_Color
73 return new StructureCommand("bg_color", getColourString(col));
77 * Returns a colour formatted suitable for use in viewer command syntax. For
78 * example, red is {@code "0xff0000"}.
83 protected String getColourString(Color c)
85 return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
90 public StructureCommandI focusView()
96 public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
97 AtomSpecModel atomSpec)
99 // https://pymolwiki.org/index.php/Super
100 List<StructureCommandI> commands = new ArrayList<>();
101 String refAtomsAlphaOnly = getAtomSpec(refAtoms, true);
102 String atomSpec2AlphaOnly = getAtomSpec(atomSpec, true);
103 commands.add(new StructureCommand("super", refAtomsAlphaOnly,
104 atomSpec2AlphaOnly));
107 * and show superposed residues as cartoon
109 String refAtomsAll = getAtomSpec(refAtoms, false);
110 String atomSpec2All = getAtomSpec(atomSpec, false);
111 commands.add(new StructureCommand("show", "cartoon",
112 refAtomsAll + " " + atomSpec2All));
118 public StructureCommandI openCommandFile(String path)
120 // https://pymolwiki.org/index.php/Run
121 return new StructureCommand("run", path); // should be .pml
125 public StructureCommandI saveSession(String filepath)
127 // https://pymolwiki.org/index.php/Save#EXAMPLES
128 return new StructureCommand("save", filepath); // should be .pse
132 * Returns a selection string in PyMOL 'selection macro' format:
135 * modelId// chain/residues/
138 * If more than one chain, makes a selection expression for each, and they are
139 * separated by spaces.
141 * @see https://pymolwiki.org/index.php/Selection_Macros
144 public String getAtomSpec(AtomSpecModel model, boolean alphaOnly)
146 StringBuilder sb = new StringBuilder(64);
147 boolean first = true;
148 for (String modelId : model.getModels())
150 for (String chain : model.getChains(modelId))
157 List<int[]> rangeList = model.getRanges(modelId, chain);
158 chain = chain.trim();
159 sb.append(modelId).append("//").append(chain).append("/");
160 boolean firstRange = true;
161 for (int[] range : rangeList)
168 sb.append(String.valueOf(range[0]));
169 if (range[0] != range[1])
171 sb.append("-").append(String.valueOf(range[1]));
181 return sb.toString();
185 public List<StructureCommandI> showBackbone()
187 return SHOW_BACKBONE;
191 protected StructureCommandI colourResidues(String atomSpec, Color colour)
193 // https://pymolwiki.org/index.php/Color
194 return new StructureCommand("color", getColourString(colour), atomSpec);
198 protected String getResidueSpec(String residue)
200 // https://pymolwiki.org/index.php/Selection_Algebra
201 return "resn " + residue;
205 public StructureCommandI loadFile(String file)
207 return new StructureCommand("load", file);
211 * Overrides the default implementation (which generates concatenated
212 * commands) to generate one per colour (because the XML-RPC interface to
213 * PyMOL only accepts one command at a time)
219 public List<StructureCommandI> colourBySequence(
220 Map<Object, AtomSpecModel> colourMap)
222 List<StructureCommandI> commands = new ArrayList<>();
223 for (Object key : colourMap.keySet())
225 Color colour = (Color) key;
226 final AtomSpecModel colourData = colourMap.get(colour);
227 commands.add(getColourCommand(colourData, colour));
234 * Returns a viewer command to set the given atom property value on atoms
235 * specified by the AtomSpecModel, for example
238 * iterate 4zho//B/12-34,48-55/CA,jv_chain='primary'
241 * @param attributeName
242 * @param attributeValue
243 * @param atomSpecModel
246 protected StructureCommandI setAttribute(String attributeName,
247 String attributeValue, AtomSpecModel atomSpecModel)
249 StringBuilder sb = new StringBuilder(128);
250 sb.append("p.").append(attributeName).append("='")
251 .append(attributeValue).append("'");
252 String atomSpec = getAtomSpec(atomSpecModel, false);
253 return new StructureCommand("iterate", atomSpec, sb.toString());
257 * Traverse the map of features/values/models/chains/positions to construct a
258 * list of 'set property' commands (one per distinct feature type and value).
259 * The values are stored in the 'p' dictionary of user-defined properties of
262 * The format of each command is
265 * <blockquote> iterate atomspec, p.featureName='value'
266 * e.g. iterate 4zho//A/23,28-29/CA, p.jv_Metal='Fe'
274 public List<StructureCommandI> setAttributes(
275 Map<String, Map<Object, AtomSpecModel>> featureMap)
277 List<StructureCommandI> commands = new ArrayList<>();
278 for (String featureType : featureMap.keySet())
280 String attributeName = makeAttributeName(featureType);
283 * todo: clear down existing attributes for this feature?
285 // commands.add(new StructureCommand("iterate", "all",
286 // "p."+attributeName+"='None'"); //?
288 Map<Object, AtomSpecModel> values = featureMap.get(featureType);
289 for (Object value : values.keySet())
292 * for each distinct value recorded for this feature type,
293 * add a command to set the attribute on the mapped residues
294 * Put values in single quotes, encoding any embedded single quotes
296 AtomSpecModel atomSpecModel = values.get(value);
297 String featureValue = value.toString();
298 featureValue = featureValue.replaceAll("\\'", "'");
299 StructureCommandI cmd = setAttribute(attributeName, featureValue,
309 public StructureCommandI openSession(String filepath)
311 // https://pymolwiki.org/index.php/Load
312 // this version of the command has no dependency on file extension
313 return new StructureCommand("load", filepath, "", "0", "pse");
317 public StructureCommandI showStructures(AtomSpecModel restrictTo)
319 if (restrictTo == null)
325 return new StructureCommand("show", "cartoon",
326 getAtomSpec(restrictTo, false));
331 public StructureCommandI hideChain(String modelId, String chainId)
333 return new StructureCommand("hide", modelId + "//" + chainId + "//");
337 public StructureCommandI hideAll()
339 return HIDE_EVERYTHING;
342 public StructureCommandI closeViewer()