On Monday 17 November 2003 14:06, Laurence Pearl wrote:
> I should add that I don't actually know
> how to program in python and have no idea how its 'tuples' work, so
> this is a very FORTRAN-like routine - feel free to improve it.
I have attached a "Pythonized" version of the code. It uses docstrings
for the functions, try...except blocks to check some of the parameters,
and things like ("%8.3f" * 17) to save some repetition of format
specifiers. Python is cool!
I have also changed the script to add two commands to PyMol using
cmd.extend: "camtrav first,nframes,selection,zoom,buffer" and
"seqfly object,firstres,lastres". Usage examples:
#---------------------------------
load protein.pdb
run camera_travel.py
mset 1 x150
zoom all
camtrav 1,100,(resi 50),1,4
mplay
# This will zoom in from the complete molecule to residue 50.
#---------------------------------
#---------------------------------
load protein.pdb
run camera_travel.py
mset 1 x150
seqfly protein,1,8
mplay
# This will visit the sequence from residue 1 to 8
#---------------------------------
Finally, I ran into some trouble in a lysozyme structure (PDB 103L). At
residue 139, cosom becomes slightly larger than 1 (1.0008 or so) and
acos(cosom) fails. Also, omega and sinom become zero in this case, so
the divisions by sinom fail. I added some checks to normalize this
situation and stop the code from crashing, but we should look into
what's causing this.
--
Lieven Buts
Department of Ultrastructure
Vrije Universiteit Brussel
# camera_travel - Laurence Pearl, November 2003
# Pythonized by Lieven Buts, November 2003
import cmd
from math import sqrt,acos,sin
def quaternion(view):
"""
Returns a quaternion representation of a view matrix.
"""
nxt = [1,2,0]
q = [0.0,0.0,0.0,1.0]
tr = view[0]+view[4]+view[8]
if tr > 0.0 :
s = sqrt(tr + 1.0)
qw1 = s / 2.0
s = 0.5 / s
return ( (view[5] - view[7]) * s,
(view[6] - view[2]) * s,
(view[1] - view[3]) * s,
qw1 )
else :
i = 0
if (view[4] > view[0]): i = 1
if (view[8] > view[i+3*i]): i = 2
j = nxt[i]
k = nxt[j]
s = sqrt ((view[i+i*3] - (view[j+j*3] + view[k+k*3])) + 1.0)
q[i] = s * 0.5
if (s != 0.0): s = 0.5 / s
q[3] = (view[k+3*j] - view[j+3*k]) * s
q[j] = (view[j+3*i] + view[i+3*j]) * s
q[k] = (view[k+3*i] + view[i+3*k]) * s
return q
def camera_travel(first,nframes=30,sel='(all)',zflag=0,zlevel=2):
"""
Generate progressive view matrices to move the camera smoothly
from the current view to a view defined by a PyMol selection.
first - start frame
nframes - duration
sel - atom selection that defines the orientation at the end of the
sequence
zflag - flag to indicate whether the final view should be 'zoomed'
or not
zlevel - buffer space for zooming final view (as in cmd.zoom)
"""
try:
first=int(first)
except:
print "camera_travel: first frame must be an integer"
return -1
try:
nframes=int(nframes)
except:
print "camera_travel: number of frames"
ff=float(1.0/nframes)
old_view = cmd.get_view(2)
# print ( "view : (" + "%8.3f, "*17 + "%8.3f)" ) % (old_view)
# print "oldtran : %8.3f %8.3f %8.3f" % (old_view[12], old_view[13],
old_view[14])
# do orient operation on selection
cmd.orient(sel,0)
# if zoom to selection is required add this into view matrix
if zflag:
cmd.zoom(sel,zlevel,0,1)
# get new view
new_view = cmd.get_view()
# capture new zoom/clip parameters
ozc1 = new_view[11]
ozc2 = new_view[15]
ozc3 = new_view[16]
# calculate shift in zoom/clip parameters
dzc1 = (ozc1 - old_view[11]) * ff
dzc2 = (ozc2 - old_view[15]) * ff
dzc3 = (ozc3 - old_view[16]) * ff
ozc1 = old_view[11]
ozc2 = old_view[15]
ozc3 = old_view[16]
# capture new translation vector component
ox = new_view[12]
oy = new_view[13]
oz = new_view[14]
# calculate shift vector
dx = ox - old_view[12]
dy = oy - old_view[13]
dz = oz - old_view[14]
dx = dx*ff
dy = dy*ff
dz = dz*ff
ox = old_view[12]
oy = old_view[13]
oz = old_view[14]
# capture old and new rotation matrix components in quaternion form
# m[0][0] = v[0] m[0][1] = v[1] m[0][2] = v[2]
# m[1][0] = v[3] m[1][1] = v[4] m[1][2] = v[5]
# m[2][0] = v[6] m[2][1] = v[7] m[2][2] = v[8]
qx1,qy1,qz1,qw1 = quaternion(old_view)
qx2,qy2,qz2,qw2 = quaternion(new_view)
# calc cosine
cosom = qx1 * qx2 + qy1 * qy2 + qz1 * qz2 + qw1 * qw2
limit = 0.001
if cosom>1.0+limit:
raise ValueError,"Cosine of omega way out of range (positive)"
elif cosom>1.0:
print "Warning: cosom corrected from ",cosom,"to",
cosom = 1.0
print cosom
if cosom<-1.0-limit:
raise ValueError,"Cosine of omega way out of range (negative)"
elif cosom<-1.0:
print "Warning: cosom corrected from ",cosom,"to",
cosom = 1.0
print cosom
# adjust signs
if (cosom < 0.0):
cosom = -cosom
to0 = -qx2
to1 = -qy2
to2 = -qz2
to3 = -qw2
else:
to0 = qx2
to1 = qy2
to2 = qz2
to3 = qw2
# calc coefficients
omega = acos(cosom)
sinom = sin(omega)
if sinom==0.0:
sinom=limit
print "Warning: sinom corrected!"
# restore old view
cmd.set_view( ("%8.3f, " * 17 + "%8.3f") % tuple(old_view) )
# loop interpolating over nframes generating interpolated quaternion
for a in range(nframes+1):
scale0 = sin((1.0 - float(a*ff)) * omega) / sinom
scale1 = sin(float(a*ff) * omega) / sinom
rx = scale0 * qx1 + scale1 * to0;
ry = scale0 * qy1 + scale1 * to1;
rz = scale0 * qz1 + scale1 * to2;
rw = scale0 * qw1 + scale1 * to3;
# convert back to matrix
x2 = rx + rx
y2 = ry + ry
z2 = rz + rz
xx = rx * x2
xy = rx * y2
xz = rx * z2
yy = ry * y2
yz = ry * z2
zz = rz * z2
wx = rw * x2
wy = rw * y2
wz = rw * z2
nv0 = 1.0 - (yy + zz)
nv3 = xy - wz
nv6 = xz + wy
nv1 = xy + wz
nv4 = 1.0 - (xx + zz)
nv7 = yz - wx
nv2 = xz - wy
nv5 = yz + wx
nv8 = 1.0 - (xx + yy)
# update translation vector
ox = ox + dx
oy = oy + dy
oz = oz + dz
# update zoom/clip parameters if required
if zflag:
ozc1 = ozc1 + dzc1
ozc2 = ozc2 + dzc2
ozc3 = ozc3 + dzc3
cmd.mdo("%d" % (first), ("set_view (" + "%8.3f, "*17 +
"%8.3f)") %
(nv0,nv1,nv2,nv3,nv4,nv5,nv6,nv7,nv8,old_view[9],old_view[10],ozc1,
ox,oy,oz,ozc2,ozc3,old_view[17]))
first += 1
cmd.set_view( ("%8.3f, "*17 + "%8.3f") %
(nv0,nv1,nv2,nv3,nv4,nv5,nv6,nv7,nv8,old_view[9],old_view[10],ozc1,
ox,oy,oz,ozc2,ozc3,old_view[17]))
def fly_sequence(object,first,last):
"""
Visit all residues in an object consecutively.
Requires 15 movie frames per residue.
object -
first -
last -
"""
fr=1
for ires in range(int(first),int(last)+1):
res = "(" + object + (" and resi %d" % (ires,)) + ")"
camera_travel(fr,9,res,1,2)
fr = fr + 15
# Install new PyMol commands
cmd.extend("seqfly",fly_sequence)
cmd.extend("camtrav",camera_travel)