package jalview.ext.pymol; import java.awt.Color; import java.util.ArrayList; import java.util.List; import java.util.Map; import jalview.structure.AtomSpecModel; import jalview.structure.StructureCommand; import jalview.structure.StructureCommandI; import jalview.structure.StructureCommandsBase; /** * A class that generates commands to send to PyMol over its XML-RPC interface. *

* Note that because the xml-rpc interface can only accept one command at a * time, we can't concatenate commands, and must instead form and send them * individually. * * @see https://pymolwiki.org/index.php/Category:Commands * @see https://pymolwiki.org/index.php/RPC */ public class PymolCommands extends StructureCommandsBase { private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand("spectrum", "chain"); private static final List COLOR_BY_CHARGE = new ArrayList<>(); private static final List SHOW_BACKBONE = new ArrayList<>(); static { COLOR_BY_CHARGE.add(new StructureCommand("color", "white", "*")); COLOR_BY_CHARGE .add(new StructureCommand("color", "red", "resn ASP resn GLU")); COLOR_BY_CHARGE.add( new StructureCommand("color", "blue", "resn LYS resn ARG")); COLOR_BY_CHARGE .add(new StructureCommand("color", "yellow", "resn CYS")); SHOW_BACKBONE.add(new StructureCommand("hide", "everything")); SHOW_BACKBONE.add(new StructureCommand("show", "ribbon")); } @Override public StructureCommandI colourByChain() { return COLOUR_BY_CHAIN; } @Override public List colourByCharge() { return COLOR_BY_CHARGE; } @Override public StructureCommandI setBackgroundColour(Color col) { // https://pymolwiki.org/index.php/Bg_Color return new StructureCommand("bg_color", getColourString(col)); } /** * Returns a colour formatted suitable for use in viewer command syntax. For * example, red is {@code "0xff0000"}. * * @param c * @return */ protected String getColourString(Color c) { return String.format("0x%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue()); } @Override public StructureCommandI focusView() { // TODO what? return null; } @Override public List showChains(List toShow) { // https://pymolwiki.org/index.php/Show List commands = new ArrayList<>(); commands.add(new StructureCommand("hide", "everything")); commands.add(new StructureCommand("show", "lines")); StringBuilder chains = new StringBuilder(); for (String chain : toShow) { chains.append(" chain ").append(chain); } commands.add(new StructureCommand("show", "cartoon", chains.toString())); return commands; } @Override public List superposeStructures(AtomSpecModel refAtoms, AtomSpecModel atomSpec) { // https://pymolwiki.org/index.php/Super List commands = new ArrayList<>(); String refAtomsAlphaOnly = getAtomSpec(refAtoms, true); String atomSpec2AlphaOnly = getAtomSpec(atomSpec, true); commands.add(new StructureCommand("super", refAtomsAlphaOnly, atomSpec2AlphaOnly)); /* * and show superposed residues as cartoon */ String refAtomsAll = getAtomSpec(refAtoms, false); String atomSpec2All = getAtomSpec(atomSpec, false); commands.add(new StructureCommand("show", "cartoon", refAtomsAll + " " + atomSpec2All)); return commands; } @Override public StructureCommandI openCommandFile(String path) { // https://pymolwiki.org/index.php/Run return new StructureCommand("run", path); // should be .pml } @Override public StructureCommandI saveSession(String filepath) { // https://pymolwiki.org/index.php/Save#EXAMPLES return new StructureCommand("save", filepath); // should be .pse } /** * Returns a selection string in PyMOL 'selection macro' format: * *

   * modelId// chain/residues/
   * 
* * If more than one chain, makes a selection expression for each, and they are * separated by spaces. * * @see https://pymolwiki.org/index.php/Selection_Macros */ @Override public String getAtomSpec(AtomSpecModel model, boolean alphaOnly) { StringBuilder sb = new StringBuilder(64); boolean first = true; for (String modelId : model.getModels()) { for (String chain : model.getChains(modelId)) { if (!first) { sb.append(" "); } first = false; List rangeList = model.getRanges(modelId, chain); chain = chain.trim(); sb.append(modelId).append("//").append(chain).append("/"); boolean firstRange = true; for (int[] range : rangeList) { if (!firstRange) { sb.append("+"); } firstRange = false; sb.append(String.valueOf(range[0])); if (range[0] != range[1]) { sb.append("-").append(String.valueOf(range[1])); } } sb.append("/"); if (alphaOnly) { sb.append("CA"); } } } return sb.toString(); } @Override public List showBackbone() { return SHOW_BACKBONE; } @Override protected StructureCommandI getColourCommand(String atomSpec, Color colour) { // https://pymolwiki.org/index.php/Color return new StructureCommand("color", getColourString(colour), atomSpec); } @Override protected String getResidueSpec(String residue) { // https://pymolwiki.org/index.php/Selection_Algebra return "resn " + residue; } @Override public StructureCommandI loadFile(String file) { return new StructureCommand("load", file); } /** * Overrides the default implementation (which generates concatenated * commands) to generate one per colour (because the XML-RPC interface to * PyMOL only accepts one command at a time) * * @param colourMap * @return */ @Override public List colourBySequence( Map colourMap) { List commands = new ArrayList<>(); for (Object key : colourMap.keySet()) { Color colour = (Color) key; final AtomSpecModel colourData = colourMap.get(colour); commands.add(getColourCommand(colourData, colour)); } return commands; } }