Python Scripting Cookbook
Table of Contents
- CHAPTER 1. Introduction
- CHAPTER 2. Quickstart - a practical UnityMol tutorial
- CHAPTER 3. Selection language based on MDAnalysis
- CHAPTER 4. Screen Recording in UnityMolX: Screenshots and Videos
- CHAPTER 5. Keyboard usage
- CHAPTER 6. Python Console in UnityMolX
- CHAPTER 7. Python Scripting Cookbook
- 1. Introduction
- 2. Using recipes from
UnityMolCommons.py - 3. Common patterns
- 4. Remote-controlling UnityMol
1. Introduction
Using scripting with IronPython within UnityMol is a powerful approach to automate and simplify common workflows. Many things are very simple to achieve, when one knows the proper syntax or method to do them. This cookbook aims to collect useful patterns to facilitate such work.
2. Using recipes from UnityMolCommons.py
Since version beta-VR-1.1.3-208-gdb0618c98, UnityMol ships with a
python library that provides a few useful functions. To use it in your
python script, put this in the header:
import sys sys.path.append(Application.streamingAssetsPath) from UnityMolCommons import *
Alternatively, you can start UnityMol with the -c or -commons
option, which will execute these commands for you by calling
loadPythonCommonsModule().
Currently, the following functions are available:
2.1. q() to exit UnityMol
Not much to explain here. q() followed by enter will call
Application.Quit() for you and is just much quicker to type.
2.2. info() for general information about build and execution
With this command you get a printout of quite some useful information. Simply do:
info()
Below, see an example output:
>>> Below information about version and build >>> Version:beta-VR-1.1.3-208-gdb0618c98 >>> Built for architecture:Non-fat file: /Users/Shared/umol-dev-mb.app/Contents/MacOS/UnityMol is architecture: arm64 >>> Executable Info:/Users/Shared/umol-dev-mb.app/Contents/MacOS/UnityMol: Mach-O 64-bit executable arm64 >>> Platform: >>>OSXPlayer >>> productName: UnityMol >>> companyName: CNRS-IBPC >>> unityVersion: 2021.3.45f1 >>> operatingSystem: Mac OS X 15.3.1 >>> deviceModel: Mac16,5 >>> Processor Type: Apple M4 Max >>> OS Architecture: Mac OS X 15.3.1 >>> UnityMol version:beta-VR-1.1.3-208-gdb0618c98
2.3. All() for using a selection with all atoms
You can use All() either without any argument, then it applies to
the last() structure that was loaded, or you can specify a structure
reference obtained from e.g. s=load(..) to then use as in All(s). An example can be to hide all hydrogens:
showHideHydrogensInSelection(All())
Do not mix up
All()as defined here withall(), which is a Python builtin function.
2.4. setTrajFramerate(fr) to set trajectory playback speed
You can use setTrajFramerate(fr) to set the framerate fr for
trajectory playback. Maximum value is 25.0. It can be used either
with fr as a single argument, then it applies to the last()
structure that was loaded - assuming there is trajectory data for it
-, or you can specify a structure reference obtained from
e.g. s=load(..) to then use as in setTrajFramerate(s,fr). A
minimal example below:
s=load("my.pdb") loadTraj(s.name, "my.xtc") setTrajFramerate(25.0)
2.5. nameRes(sel) to retrieve residue names in a selection
Either provide a selection object as an argument, or no argument to
create a temporary selection of all. Use as follows:
fetch("1kx2") print(nameRes()) [Log] Selection of 1249 atoms, named 'tempSel' (all) >>>['ALA', 'ASP', 'LEU', 'GLN', 'GLU', 'ILE', 'TYR', 'ASN', 'LYS', 'CYS', 'THR', 'VAL', 'HIS', 'SER', 'MET', 'GLY', 'PRO', 'TRP', 'ARG', 'PHE', 'HEC']
2.6. Low level functions
2.6.1. run_command(cmd)
This command is used by info() to run a system command via bash
shell. This is useful to access system information, for example about
the machine one is running on:
i=run_command("uname -a") print(i) >>>Darwin neo.lan 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:22 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6041 arm64
3. Common patterns
3.1. Iterating
3.1.1. Over atoms in a selection
In the example below, we select all carbon alpha atoms and then print out their temperature B-factor values. No graphical representation is displayed.
s=fetch("1crn", showDefaultRep=False) ca=select("name CA","ca") for atom1 in ca.atoms: print(atom1.bfactor)
3.1.2. Dynamic double atoms loop
Loop over all carbon alpha atoms within 4.5 angstrom distance using a dynamic selection in a double loop, then annotate these distances. Not very useful per se, but illustrates the feature.
s=fetch("1crn", showDefaultRep=False) showSelection("all_1crn", "trace") ca=select("name CA","ca") for atom1 in ca.atoms: tmp = select("name CA and within 4.5 atomid "+str(atom1.index+1),createSelection=False) for atom2 in tmp.atoms: if atom1 != atom2: annotateDistance(s.name,atom1.index+1,s.name,atom2.index+1)
3.1.3. Over all residues in all chains
In a double loop, we go over all chains in a model, and for each chain we iterate over all residues. We print summary information on number of residues per chain and number of atoms per residue.
s=fetch("1crn", showDefaultRep=False) for chain in s.currentModel.GetChains(): print("Chain with "+str(chain.residues.Count)+" residues encountered.") for residue in chain.residues: print("Residue with "+str(residue.atoms.Count)+" atoms encountered.")
4. Remote-controlling UnityMol
4.1. Using the built-in ZMQ server
4.1.1. General information
UnityMol can be remote controlled through a ZeroMQ (ZMQ) network connection. ZeroMQ is a good choice if you need fast, asynchronous communication between your Python applications and are willing to worry about the details of messaging protocols.
More information:
To manage the internal UnityMol server, you can activate it via
activateExternalCommands()
and shut it down via
disableExternalCommands()
4.1.2. Writing a python script to control UnityMol via ZMQ
Below is a simple and minimalistic skeleton to remote-control the ZMQ server we started in UnityMol from an external python script:
import zmq socket = zmq.Context.instance().socket(zmq.REQ) socket.connect("tcp://localhost:5555") socket.send_string("fetch('1kx2')")
By default the server runs on port 5555 on the local machine
localhost accessible via the tcp network protocol. We open a
socket for communication, then we send the command to fetch the PDB-id
1kx2 from the PDB, which will be displayed with default settings. In
this way we can feed UnityMol any commands it typically reads from a
command python script.
4.1.3. Design a custom menu to drive UnityMol
In this github repository of a recent paper you will find the menu-spike1.py script that shows a more advanced usage of the above features, designing a custom menu to control a UnityMol instance. Below a screenshot illustrating the resulting menu.
4.1.4. Get command results from UnityMol to use in your script
A minimal example below to obtain a list of the currently defined
selections in UnityMol. I the latest UnityMol version the ZMQ exchange
now returns a json payload that contains three fields, success, a
boolean about success or failure of the command execution, result,
the actual result of the command as string, and stdout, the eventual
stdout or log output as another string. Here we only use the result
string:
import zmq import json socket = zmq.Context.instance().socket(zmq.REQ) socket.connect("tcp://localhost:5555") socket.send_string("getSelectionListString()") result = json.loads(socket.recv().decode())["result"] print(*[s.strip() for s in result.strip("[]").split(",") if s.strip()], sep="\n")
First, we establish a connection, then we get the result of the
command getSelectionListString(), parse it to remove [,=]= and ,
characters, separating each selection name, and print these actual
names for each selection.
4.1.5. More advanced usage
A nice example is the implementation of a minimal python console to
drive UnityMol outside the program. This was implemented in python
with the ZMQ protocol. You can obtain the file by cloning the
ScriptCollection git repository, or directly access the
python-console.py script online. You will need the unitymol_zmq.py
helper script to handle zmq connections, it is easily
re-usable. With this script it is very easy to establish a connection
and send commands. Here is boiler-plate code:
import unitymol_zmq if unitymol_zmq.unitymol is None: unitymol_zmq.unitymol = unitymol_zmq.UnityMolZMQ() unitymol_zmq.unitymol.connect() print(unitymol_zmq.unitymol.send_command_clean("ls()"))
