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.pymol;
23 import java.awt.Color;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
29 import jalview.structure.AtomSpecModel;
30 import jalview.structure.StructureCommand;
31 import jalview.structure.StructureCommandI;
32 import jalview.structure.StructureCommandsBase;
35 * A class that generates commands to send to PyMol over its XML-RPC interface.
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
41 * @see https://pymolwiki.org/index.php/Category:Commands
42 * @see https://pymolwiki.org/index.php/RPC
44 public class PymolCommands extends StructureCommandsBase
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(
52 // https://pymolwiki.org/index.php/Quit
53 private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
56 // not currently documented on
57 // https://pymolwiki.org/index.php/Category:Commands
58 private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
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",
66 new StructureCommand("color", "yellow", "resn CYS"));
68 private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
69 .asList(new StructureCommand("hide", "everything"),
70 new StructureCommand("show", "ribbon"));
73 public StructureCommandI colourByChain()
75 return COLOUR_BY_CHAIN;
79 public List<StructureCommandI> colourByCharge()
81 return COLOR_BY_CHARGE;
85 public StructureCommandI setBackgroundColour(Color col)
87 // https://pymolwiki.org/index.php/Bg_Color
88 return new StructureCommand("bg_color", getColourString(col));
92 * Returns a colour formatted suitable for use in viewer command syntax. For
93 * example, red is {@code "0xff0000"}.
98 protected String getColourString(Color c)
100 return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(),
105 public StructureCommandI focusView()
111 public List<StructureCommandI> showChains(List<String> toShow)
113 // https://pymolwiki.org/index.php/Show
114 List<StructureCommandI> commands = new ArrayList<>();
115 commands.add(new StructureCommand("hide", "everything"));
116 commands.add(new StructureCommand("show", "lines"));
117 StringBuilder chains = new StringBuilder();
118 for (String chain : toShow)
120 chains.append(" chain ").append(chain);
123 new StructureCommand("show", "cartoon", chains.toString()));
128 public List<StructureCommandI> superposeStructures(AtomSpecModel refAtoms,
129 AtomSpecModel atomSpec, AtomSpecType specType)
132 // https://pymolwiki.org/index.php/Super
133 List<StructureCommandI> commands = new ArrayList<>();
134 String refAtomsAlphaOnly = "(" + getAtomSpec(refAtoms, specType)
135 + " and (altloc '' or altloc 'a'))";
136 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 commands.add(new StructureCommand("undo_disable"));
141 commands.add(new StructureCommand("pair_fit", atomSpec2AlphaOnly,
143 commands.add(new StructureCommand("undo_enable"));
146 * and show superposed residues as cartoon
148 String refAtomsAll = getAtomSpec(refAtoms, AtomSpecType.RESIDUE_ONLY);
149 String atomSpec2All = getAtomSpec(atomSpec, AtomSpecType.RESIDUE_ONLY);
150 commands.add(new StructureCommand("show", "cartoon",
151 refAtomsAll + " " + atomSpec2All));
157 public StructureCommandI openCommandFile(String path)
159 // https://pymolwiki.org/index.php/Run
160 return new StructureCommand("run", path); // should be .pml
164 public StructureCommandI saveSession(String filepath)
166 // https://pymolwiki.org/index.php/Save#EXAMPLES
167 return new StructureCommand("save", filepath); // should be .pse
171 * Returns a selection string in PyMOL 'selection macro' format:
174 * modelId// chain/residues/
177 * If more than one chain, makes a selection expression for each, and they are
178 * separated by spaces.
180 * @see https://pymolwiki.org/index.php/Selection_Macros
183 public String getAtomSpec(AtomSpecModel model, AtomSpecType specType)
185 StringBuilder sb = new StringBuilder(64);
186 boolean first = true;
187 for (String modelId : model.getModels())
189 for (String chain : model.getChains(modelId))
196 List<int[]> rangeList = model.getRanges(modelId, chain);
197 chain = chain.trim();
198 sb.append(modelId).append("//").append(chain).append("/");
199 boolean firstRange = true;
200 for (int[] range : rangeList)
207 sb.append(String.valueOf(range[0]));
208 if (range[0] != range[1])
210 sb.append("-").append(String.valueOf(range[1]));
214 if (specType == AtomSpecType.ALPHA)
218 if (specType == AtomSpecType.PHOSPHATE)
224 return sb.toString();
228 public List<StructureCommandI> showBackbone()
230 return SHOW_BACKBONE;
234 protected StructureCommandI colourResidues(String atomSpec, Color colour)
236 // https://pymolwiki.org/index.php/Color
237 return new StructureCommand("color", getColourString(colour), atomSpec);
241 protected String getResidueSpec(String residue)
243 // https://pymolwiki.org/index.php/Selection_Algebra
244 return "resn " + residue;
248 public StructureCommandI loadFile(String file)
250 return new StructureCommand("load", file);
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)
262 public List<StructureCommandI> colourBySequence(
263 Map<Object, AtomSpecModel> colourMap)
265 List<StructureCommandI> commands = new ArrayList<>();
266 for (Object key : colourMap.keySet())
268 Color colour = (Color) key;
269 final AtomSpecModel colourData = colourMap.get(colour);
270 commands.add(getColourCommand(colourData, colour));
277 * Returns a viewer command to set the given atom property value on atoms
278 * specified by the AtomSpecModel, for example
281 * iterate 4zho//B/12-34,48-55/CA,jv_chain='primary'
284 * @param attributeName
285 * @param attributeValue
286 * @param atomSpecModel
289 protected StructureCommandI setAttribute(String attributeName,
290 String attributeValue, AtomSpecModel atomSpecModel)
292 StringBuilder sb = new StringBuilder(128);
293 sb.append("p.").append(attributeName).append("='")
294 .append(attributeValue).append("'");
295 String atomSpec = getAtomSpec(atomSpecModel, AtomSpecType.RESIDUE_ONLY);
296 return new StructureCommand("iterate", atomSpec, sb.toString());
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
305 * The format of each command is
308 * <blockquote> iterate atomspec, p.featureName='value'
309 * e.g. iterate 4zho//A/23,28-29/CA, p.jv_Metal='Fe'
317 public List<StructureCommandI> setAttributes(
318 Map<String, Map<Object, AtomSpecModel>> featureMap)
320 List<StructureCommandI> commands = new ArrayList<>();
321 for (String featureType : featureMap.keySet())
323 String attributeName = makeAttributeName(featureType);
326 * todo: clear down existing attributes for this feature?
328 // commands.add(new StructureCommand("iterate", "all",
329 // "p."+attributeName+"='None'"); //?
331 Map<Object, AtomSpecModel> values = featureMap.get(featureType);
332 for (Object value : values.keySet())
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
339 AtomSpecModel atomSpecModel = values.get(value);
340 String featureValue = value.toString();
341 featureValue = featureValue.replaceAll("\\'", "'");
342 StructureCommandI cmd = setAttribute(attributeName, featureValue,
352 public StructureCommandI openSession(String filepath)
354 // https://pymolwiki.org/index.php/Load
355 // this version of the command has no dependency on file extension
356 return new StructureCommand("load", filepath, "", "0", "pse");
360 public StructureCommandI closeViewer()
362 // https://pymolwiki.org/index.php/Quit
367 public List<StructureCommandI> centerViewOn(List<AtomSpecModel> residues)
369 // TODO Auto-generated method stub