package jalview.ext.pymol;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
import jalview.structure.AtomSpecModel;
import jalview.structure.StructureCommand;
import jalview.structure.StructureCommandI;
import jalview.structure.StructureCommandsBase;
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.List;
-
/**
- * A class that generates commands to send to PyMol
+ * A class that generates commands to send to PyMol over its XML-RPC interface.
+ * <p>
+ * 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 StructureCommandI COLOUR_BY_CHAIN = new StructureCommand(
- "util.cbc");
+ // https://pymol.org/dokuwiki/doku.php?id=command:zoom
+ // not currently documented on
+ // https://pymolwiki.org/index.php/Category:Commands
+ private static final StructureCommand FOCUS_VIEW = new StructureCommand(
+ "zoom");
- /*
- * 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
- */
- private static final List<StructureCommandI> COLOR_BY_CHARGE = new ArrayList<>();
+ // https://pymolwiki.org/index.php/Quit
+ private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
+ "quit");
- private static final List<StructureCommandI> SHOW_BACKBONE = new ArrayList<>();
+ // not currently documented on
+ // https://pymolwiki.org/index.php/Category:Commands
+ private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
+ "spectrum", "chain");
- 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"));
- SHOW_BACKBONE.add(new StructureCommand("hide", "everything"));
- SHOW_BACKBONE.add(new StructureCommand("show", "ribbon"));
- }
+ private static final List<StructureCommandI> COLOR_BY_CHARGE = Arrays
+ .asList(new StructureCommand("color", "white", "*"),
+ new StructureCommand("color", "red", "resn ASP resn GLU"),
+ new StructureCommand("color", "blue",
+ "resn LYS resn ARG"),
+ new StructureCommand("color", "yellow", "resn CYS"));
+
+ private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
+ .asList(new StructureCommand("hide", "everything"),
+ new StructureCommand("show", "ribbon"));
@Override
public StructureCommandI colourByChain()
{
- // https://pymolwiki.org/index.php/CBC
- // TODO this doesn't execute as an xml-rpc command
return COLOUR_BY_CHAIN;
}
@Override
public StructureCommandI focusView()
{
- // TODO what?
- return null;
+ return FOCUS_VIEW;
}
@Override
{
chains.append(" chain ").append(chain);
}
- commands.add(new StructureCommand("show", "cartoon", chains.toString()));
+ commands.add(
+ new StructureCommand("show", "cartoon", chains.toString()));
return commands;
}
@Override
public StructureCommandI openCommandFile(String path)
{
- // where is this documented by PyMol?
- // todo : xml-rpc answers 'method "@" is not supported'
- return new StructureCommand("@" + path); // should be .pml
+ // https://pymolwiki.org/index.php/Run
+ return new StructureCommand("run", path); // should be .pml
}
@Override
}
@Override
- protected StructureCommandI getColourCommand(String atomSpec, Color colour)
+ protected StructureCommandI colourResidues(String atomSpec, Color colour)
{
// https://pymolwiki.org/index.php/Color
return new StructureCommand("color", getColourString(colour), atomSpec);
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<StructureCommandI> colourBySequence(
+ Map<Object, AtomSpecModel> colourMap)
+ {
+ List<StructureCommandI> 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;
+ }
+
+ /**
+ * Returns a viewer command to set the given atom property value on atoms
+ * specified by the AtomSpecModel, for example
+ *
+ * <pre>
+ * iterate 4zho//B/12-34,48-55/CA,jv_chain='primary'
+ * </pre>
+ *
+ * @param attributeName
+ * @param attributeValue
+ * @param atomSpecModel
+ * @return
+ */
+ protected StructureCommandI setAttribute(String attributeName,
+ String attributeValue, AtomSpecModel atomSpecModel)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("p.").append(attributeName).append("='")
+ .append(attributeValue).append("'");
+ String atomSpec = getAtomSpec(atomSpecModel, false);
+ return new StructureCommand("iterate", atomSpec, sb.toString());
+ }
+
+ /**
+ * Traverse the map of features/values/models/chains/positions to construct a
+ * list of 'set property' commands (one per distinct feature type and value).
+ * The values are stored in the 'p' dictionary of user-defined properties of
+ * each atom.
+ * <p>
+ * The format of each command is
+ *
+ * <pre>
+ * <blockquote> iterate atomspec, p.featureName='value'
+ * e.g. iterate 4zho//A/23,28-29/CA, p.jv_Metal='Fe'
+ * </blockquote>
+ * </pre>
+ *
+ * @param featureMap
+ * @return
+ */
+ @Override
+ public List<StructureCommandI> setAttributes(
+ Map<String, Map<Object, AtomSpecModel>> featureMap)
+ {
+ List<StructureCommandI> commands = new ArrayList<>();
+ for (String featureType : featureMap.keySet())
+ {
+ String attributeName = makeAttributeName(featureType);
+
+ /*
+ * todo: clear down existing attributes for this feature?
+ */
+ // commands.add(new StructureCommand("iterate", "all",
+ // "p."+attributeName+"='None'"); //?
+
+ Map<Object, AtomSpecModel> values = featureMap.get(featureType);
+ for (Object value : values.keySet())
+ {
+ /*
+ * for each distinct value recorded for this feature type,
+ * add a command to set the attribute on the mapped residues
+ * Put values in single quotes, encoding any embedded single quotes
+ */
+ AtomSpecModel atomSpecModel = values.get(value);
+ String featureValue = value.toString();
+ featureValue = featureValue.replaceAll("\\'", "'");
+ StructureCommandI cmd = setAttribute(attributeName, featureValue,
+ atomSpecModel);
+ commands.add(cmd);
+ }
+ }
+
+ return commands;
+ }
+
+ @Override
+ public StructureCommandI openSession(String filepath)
+ {
+ // https://pymolwiki.org/index.php/Load
+ // this version of the command has no dependency on file extension
+ return new StructureCommand("load", filepath, "", "0", "pse");
+ }
+
+ @Override
+ public StructureCommandI closeViewer()
+ {
+ // https://pymolwiki.org/index.php/Quit
+ return CLOSE_PYMOL;
+ }
+
}