Disclaimer: All the contributions displayed on this page were made by subscribers of the PyMOL mailing list at
sourceforge.net and Warren L. DeLano himself. Although i have checked most of the things listed here, i cannot guarantee
that everythings works well. I cannot even guarantee that i have understood everything written on this page. Please be cautious.
1. Running a Python script from PyMOL, usually the command:
run script.pyIs enough. Of course, the file script.py needs to be in the working directory.
pymol example.py # synchronous, in PyMOL module pymol -r example.py # synchronous in __main__ module pymol -l example.py # asychronous in a new moduleYou can also launch python programs from within PyMOL with the commands:
run example.py # synchronous in pymol module run example.py,main # synchronous in __main__ module spawn example.py # asychronous in a new module spawn example.py,global # asychronous in the PyMOL module spawn example.py,main # asychronous in the __main__ module
2. Running PyMOL from a Python script requires two commands:
import pymol pymol.finish_launching()
Are you aware that the PyMOL command line is also a Python command line? You can just use PyMOL interactively in that fashion.
PyMOL>print 1+1 2 PyMOL>from random import random PyMOL>print random() 0.739460642143The only major difference is that the default namespace for PyMOL is "pymol" not "__main__"
PyMOL>print __name__ pymol
Atom selections aren't directly exposed to Python, but you can have PyMOL build a Python list containing whatever information you need:
Using PyMOL commands:
list=[]
iterate (name ca),list.append((resi,resn))
print list
[('ASP', '1'), ('CYS', '2'), ('ALA', '3'), ('TRP', '4'), ('HIS', '5'), ('LEU',
'6'), ('GLY', '7'), ('GLU', '8'), ('LEU', '9'), ('VAL', '10'), ('TRP', '11'),
('CYS', '12'), ('THR', '13')]
or using a Python script (in PyMOL):
from pymol import cmd,stored
stored.list=[]
cmd.iterate("(name ca)","stored.list.append((resi,resn))")
print stored.list
[('1', 'ASP'), ('2', 'CYS'), ('3', 'ALA'), ('4', 'TRP'), ('5', 'HIS'), ('6', '
LEU'), ('7', 'GLY'), ('8', 'GLU'), ('9', 'LEU'), ('10', 'VAL'), ('11', 'TRP'),
('12', 'CYS'), ('13', 'THR')]
The function below will return true if the selection is defined.
from pymol import cmd
from types import *
def sele_exists(sele):
sess = cmd.get_session()
for i in sess["names"]:
if type(i) is ListType:
if sele==i[0]:
return 1
return 0
The actual C-langauge arrays aren't exposed, but there are at least three
different ways you can modify coordinates from within Python:
alter_state 1,pept,(x,y)=(-y,x)
Likewise sub-selections can be transformed as well:
alter_state 1,(pept and name ca),(x,y,z)=(x+5,y,z)
I thought I'd post this example, just in case anyone else cares about this:
delete all
cmd.read_pdbstr("""HEADER CREATED BY CONVERTPROSPECT 27-JAN-02 2tnf \
REMARK 1 \
ATOM 1 N PRO A 9 1.895 67.213 -38.182 1.00 0.00 N \
ATOM 2 CA PRO A 9 1.703 68.680 -38.402 1.00 0.00 C \
....
ATOM 1153 C GLY A 157 6.927 59.108 -38.901 1.00 6.00 C \
ATOM 1154 O GLY A 157 6.700 59.292 -37.676 1.00 6.00 O \
TER 1155 GLY A 157 \
MASTER \
END \
""","2tnfa")
hide all
show cartoon
color grey
....
Use Python (and the run command with .py files).
from pymol import cmd
f=open('dist.txt','w')
dst=cmd.distance('tmp','mol1///25/ha','mol1///26/ha')
f.write("%8.3f\n"%dst)
f.close()
You could measure the whole protein this way by putting a loop around the distance command:
from pymol import cmd
f=open('dist.txt','w')
atom = cmd.get_model("mol1////ha").atom
for i in range(len(atom)-1):
sele1 = 'mol1///%s/HA'%atom[i].resi
sele2 = 'mol1///%s/HA'%atom[i+1].resi
dst=cmd.distance('tmp',sele1,sele2)
f.write("%14s %14s %8.3f\n"%(sele1,sele2,dst))
f.close()
The output "dist.txt" would then look like:
mol1///4/HA mol1///5/HA 4.748 mol1///5/HA mol1///6/HA 4.828 mol1///6/HA mol1///7/HA 4.861 mol1///7/HA mol1///8/HA 4.784 mol1///8/HA mol1///9/HA 4.936 mol1///9/HA mol1///10/HA 4.833 mol1///10/HA mol1///11/HA 4.933 mol1///11/HA mol1///12/HA 4.813
Q: Is there a simple way to colour each object currently loaded, with a
different colour (in the same way that you can colour each chain in a
molecule differently)? This would be really useful in visualising a
set of superposed structures.
A: There is a script color_obj.py that does the job.
The script is also available at
http://www.ebi.ac.uk/~gareth/misc
USAGE
color_obj(rainbow=0)
This function colours each object currently in the PyMOL heirarchy
with a different colour. Colours used are either the 22 named
colours used by PyMOL (in which case the 23rd object, if it exists,
gets the same colour as the first), or are the colours of the rainbow
To retrieve the color for a residue as identified in an expression, you can either iterate over a selection from the PyMOL command line
iterate all, print colorAlternatively, this can be done from a Python script.
import pymol
pymol.color_list = []
cmd.iterate('all', 'pymol.color_list.append(color)')
print pymol.color_list
Secondary structures (both predefined and those calculated with the 'dss' command) can be exported as a long string ('HHHHLLLLSSS') with the following script:
import pymol
pymol.stored_ss = []
cmd.iterate('all', 'pymol.stored_ss.append(string.ljust(ss,1))')
print string.join(pymol.stored_ss)
The following scripts turns the view 30 deg around the y-axis, each time you press the enter key in the python shell (the original shell you started pymol from), just as an example:
#use "spawn spawn_demo.py, local" to invoke this python script from
within pymol
wait=""
i=0
while i < 12 and wait!="x":
cmd.turn("y", 30)
print "Press enter key to continue or x + enter to terminate"
wait=raw_input()
i=i+1
print "Done"
It's not GUI, but you could simply bind a function key such as F1 to a command:
cmd.set_key('F1',lambda :cmd.show('sticks'))
Create a python script (I call it axes.py):
# axes.py from pymol.cgo import * from pymol import cmd from pymol.vfont import plain # create the axes object, draw axes with cylinders coloured red, green, #blue for X, Y and Z obj = [ CYLINDER, 0., 0., 0., 10., 0., 0., 0.2, 1.0, 1.0, 1.0, 1.0, 0.0, 0., CYLINDER, 0., 0., 0., 0., 10., 0., 0.2, 1.0, 1.0, 1.0, 0., 1.0, 0., CYLINDER, 0., 0., 0., 0., 0., 10., 0.2, 1.0, 1.0, 1.0, 0., 0.0, 1.0, ] # add labels to axes object (requires pymol version 0.8 or greater, I # believe cyl_text(obj,plain,[-5.,-5.,-1],'Origin',0.20,axes=[[3,0,0],[0,3,0],[0,0,3]]) cyl_text(obj,plain,[10.,0.,0.],'X',0.20,axes=[[3,0,0],[0,3,0],[0,0,3]]) cyl_text(obj,plain,[0.,10.,0.],'Y',0.20,axes=[[3,0,0],[0,3,0],[0,0,3]]) cyl_text(obj,plain,[0.,0.,10.],'Z',0.20,axes=[[3,0,0],[0,3,0],[0,0,3]]) # then we load it into PyMOL cmd.load_cgo(obj,'axes')
You can modify the "3" in the above description of the text labels to
change the size of the labels. If you are running a version of pymol
older the 0.8, then you cannot add the text (that's why I included
colour coding of the axes). You can also use just lines instead of
cylinders if you wish:
obj = [ BEGIN, LINES, COLOR, 1.0, 0.0, 0.0, VERTEX, 0.0, 0.0, 0.0, VERTEX, 10.0, 0.0, 0.0, COLOR, 0.0, 1.0, 0.0, VERTEX, 0.0, 0.0, 0.0, VERTEX, 0.0, 10.0, 0.0, COLOR, 0.0, 0.0, 1.0, VERTEX, 0.0, 0.0, 0.0, VERTEX, 0.0, 0.0, 10.0, END, ]
You can use the cgo text (line or cylinder versions) as I mentioned in
my reply about drawing the xyz axes, but be warned that the labels
rotate with your molecule, so getting them oriented perpendicular to the
view may be a pain (unless there is something I've missed).
Warren's example from a previous reply of his (cgotext.py):
# draw text using cgo
from pymol import cmd
from pymol.cgo import *
from pymol.vfont import plain
cgo = []
axes = [[2.0,0.0,0.0],[0.0,2.0,0.0],[0.0,0.0,2.0]]
pos = [0.0,0.0,0.0]
wire_text(cgo,plain,pos,'Hello World',axes)
pos = [0.0,-3.0,0.0]
cyl_text(cgo,plain,pos,'Hello Universe',0.10,axes=axes)
cmd.set("cgo_line_radius",0.03)
cmd.load_cgo(cgo,'txt')
cmd.zoom("all",2.0)
You could use the cmd.rotate and cmd.translate to position the labels,
but it is likely to be somewhat painful. If I'm not mistaken, the
rotation will always be about and axis through the origin and so you may
need to translate the label into the correct position.
Thus if you have your label in an object called 'text', you could do,
cmd.rotate(axis='x',angle=20.,object='text')and repeat this with different angles, until you get the orientation correct. Then use:
cmd.translate(vector='[1.,2.,3.]',object='text')(using the appropriate vector, of course!) to position the label.
Here's a script graph.py which can be used to put marks on the positions of every atom in a selection. There are several types of marks included now, e.g. cube, rhombic dodecahedron, tetrahedron, plus and star. Using a matrix operator these can be extended a bit, to 2D counterparts for example, or to elongated or rotated shapes. I should still include some documentation but in brief the usage is as follows:
graph selection = '(all)', shape = 'plus' | 'sphere' | 'star' | 'tetrahedron' | 'dodecahedron', size = 1, r = 0.10, rgb1 = [1,0,0], rgb2 = [0,0,1], mtx = [[1,0,0],[0,1,0],[0,0,1]], name = "graph"Selection should be obvious, as is shape. Size is a relative indicator for the size, though at present I haven't fixed things such that a size 1 tetrahedron matches a size 1 dodecahedron. r is the radius of the lines. rgb1 and rgb2 are the start and end color for each line. mtx is the matrix operator, which works on the original shape centered around the origin (before translation to the point of the atom from the selection).
There is a convenient format: ".pkl", that works like PDB, but is a Pickled copy of the PyMOL Model Class. The main advantage this has over .pdb is that it saves and restores extra properties such as secondary structure code, atom types, van der waals radii, formal and partial charges, etc.
load myprot.pdb dss show cartoon alter 100-110/, ss='H' alter 65-67,ss='L' save myprot.pkl... quit program, complete your PhD, take a vacation, and come back...
load myprot.pkl show cartoonwill work.
".pkl" has the additional advantage of being a simple molecular object useful in straight Python, outside of PyMOL. All you need to do is have a copy of PyMOL's "chempy" module available in your PYTHONPATH
from chempy import io
model = io.pkl.fromFile("myprot.pkl")
for atom in model.atom:
print atom.name
This is a snap. Just "run" the following Python program from
within PyMOL.
from chempy.models import Indexed
from chempy import Bond, Atom
from whrandom import random
from pymol import cmd
model = Indexed()
# create some atoms
for a in range(1,11):
at = Atom()
at.name = "X%02d"%a
at.coord = [random()*5,random()*5,random()*5]
model.atom.append(at)
# now create some bonds
for a in range(1,10):
bd = Bond()
bd.index = [a-1,a] # zero-based indices!
model.bond.append(bd)
# now load and label
cmd.load_model(model,"example")
cmd.label("example","name")
Rubor : http://www.rubor.de
Post an Kristian Rother:
kristian.rother@charite.de
Last modified: Wed Apr 28 07:24:35 CEST 2004