Difference between revisions of "SuperSym"

From PyMOLWiki
Jump to: navigation, search
m (See CCTBX)
 
(21 intermediate revisions by 3 users not shown)
Line 1: Line 1:
SuperSym is a PyMOL plugin providing a large number of tools for visualization of space groups; unit cells; and symmetry axes, operators, and partners. Source code for version 1.0 is available from [https://sourceforge.net/projects/supersym/ https://sourceforge.net/projects/supersym/] and displayed below.
+
[[File:SuperSymExample.png|300px|thumb|right|Symmetry partners for 1hpv showing 6-1 screw axis]]
 +
[[File:SuperSymExample2.png|300px|thumb|right|Full cell of symmetry partners with symmetry axes displayed]]
 +
SuperSym is a PyMOL plugin providing a large number of tools for visualization of space groups; unit cells; and symmetry axes, operators, and partners. Source code for all versions is available from [https://sourceforge.net/projects/supersym/ https://sourceforge.net/projects/supersym/], and the most recent code is available in regular text format from [[SuperSymSource]].
  
==Dependencies and Acknowledgments==
+
== Dependencies ==
  
Pre-v1.0 PyMOL may not display objects created by this plugin properly. Use at your own risk.
+
* [[CCTBX|cctbx]]
 +
* numpy
  
This plugin requires cctbx and numeric python.
+
'''PyMOL, cctbx and numpy must all be compiled with the same Python distribution!'''
 +
See [[CCTBX]].
  
Code for unit cell and symmetry axis building is borrowed from scripts created by Robert Campbell and Ralf W. Grosse-Kunstleve, available at [http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/ http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/]. Some of this code has been modified for use in SuperSym.
+
This plugin was developed in 2010 for PyMOL version 1.2r1 and has not been updated since.
  
[[FindSurfaceResidues]] is utilized for some of SuperSym's graphics generation, with some modifications.
+
== Bugs ==
  
==Using SuperSym==
+
Symmetry axes are not defined for all space groups, and do not display properly for some.
  
To use SuperSym, copy the text of source files to corresponding .py files. Place SuperSymMenu.py in pymol/modules/pmg_tk/startup, and all other files in pymol/modules.
+
== Acknowledgments ==
  
To use functions of SuperSym directly, without creating a drop-down menu in the PyMOL GUI, ignore SuperSymMenu.py and run the other files in PyMOL as you would for any other script.
+
Primary coding and development was done by Stuart Ballard. All comments, questions, and issues should be directed to him at srballard@wisc.edu.
  
==Source Files==
+
Code for unit cell and symmetry axis building is borrowed from scripts created by Robert Campbell and Ralf W. Grosse-Kunstleve, available at [http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/ http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/]. Some of this code has been modified for use in SuperSym.
  
File: SuperSym.py
+
[[FindSurfaceResidues]] is utilized for some of SuperSym's graphics generation, with some modifications.
<source lang="python">
 
from Tkinter import *
 
import tkSimpleDialog
 
import tkMessageBox
 
import tkColorChooser
 
import sys
 
from pymol import stored, cmd, selector
 
import math
 
from cctbx import sgtbx, uctbx
 
import numpy as N
 
from numpy.linalg import *
 
import draw_cell as draw_cell
 
import draw_symops_cctbx as sym_axes
 
 
 
'''
 
symDialog: Dialog generator and command issuer for generating symmetry partners
 
 
 
This function is called by SuperSymMenu when any symmetry partner generating option is
 
selected. It creates dialog windows and receives user input for symmetry generation parameters.
 
 
 
@app -- identifies the GUI interface to build dialog boxes onto.
 
@mode -- determines specific treatment of symmetry building command
 
'''
 
def symDialog(app, mode):
 
    prefix = tkSimpleDialog.askstring('Prefix',
 
    'Enter desired prefix for these partners:', parent=app.root)
 
    object = tkSimpleDialog.askstring('Object',
 
    'Enter object to generate partners from:', parent=app.root)
 
    if (mode == 0): #make default symmetry set in cell [0,0,0]
 
        symset(prefix, object)
 
    if (mode == 1): #make symmetry set in custom cell
 
        cell = tkSimpleDialog.askstring('Cell',
 
        'Enter lattice cell coordinates separated by commas (ex:x,y,z):', parent = app.root)
 
        x,y,z = cell.split(',')
 
        x,y,z = int(x),int(y),int(z)
 
        symset(prefix, object, x, y, z)
 
    if mode == 2: #make 2x2x2 block of symmetry sets
 
        for i in range(2):
 
            for j in range(2):
 
                for k in range(2):
 
                    symset(prefix, object, i, j, k)
 
    if mode == 3: #make 3x3x3 block of symmetry sets
 
        for i in range(-1,2):
 
            for j in range(-1,2):
 
                for k in range(-1,2):
 
                    symset(prefix, object, i, j, k)
 
    if mode == 4: #select individual partners by operation and cell
 
        ops = get_operations(object)
 
        opString = ""
 
        for i in range(len(ops)):
 
            opString = opString + str(i) + " : " + ops[i] + "\n"
 
        opIndeces = tkSimpleDialog.askstring("Symmetry Operations", opString +
 
        "Enter numbers of desired operations separated by commas (ex:0,2,9)", parent = app.root)
 
        opListStrings = opIndeces.split(",")
 
        opList = []
 
        for op in opListStrings:
 
            opList.append(int(op))
 
        cell = tkSimpleDialog.askstring('Cell',
 
        'Enter lattice cell coordinates separated by commas (ex:x,y,z):', parent = app.root)
 
        x,y,z = cell.split(',')
 
        x,y,z = int(x),int(y),int(z)
 
        symset(prefix, object, x,y,z, opList)
 
 
 
'''
 
colorDialog: Dialog generator for coloring commands
 
 
 
This function colors sets of symmetry partners defined by the user in the
 
dialog which it generates.
 
 
 
@app -- identifies root menu calling this function
 
@mode -- determines coloring scheme to execute
 
'''
 
def colorDialog(app, mode):
 
    prefix = tkSimpleDialog.askstring('Prefix',
 
    'Enter the prefix of symmetry partners to color', parent = app.root)
 
    if mode == 0: #standard rainbow by symmetry operation
 
        colors = ["red", "orange", "yellow", "green", "blue", "purple",
 
              "salmon", "grey", "pink", "teal", "brown", "br0", "aquamarine",
 
              "deepolive", "dirtyviolet", "slate", "br4", "darksalmon", "br7",
 
              "chocolate", "firebrick", "brightorange"]
 
        for i in range(10):
 
            try: #required because PyMOL inappropriately throws an exception
 
                #when the cmd.color() function colors no objects
 
                cmd.color(colors[i], prefix + "0" + str(i) + "*")
 
            except:
 
                pass #allows us to move on to next symmetry operator
 
        for i in range(10,20):
 
            try: #required because PyMOL inappropriately throws an exception
 
                #when the cmd.color() function colors no objects
 
                cmd.color(colors[i], prefix + str(i) + "*")
 
            except:
 
                pass #allows us to move on to next symmetry operator
 
    if mode == 1: #specify for each symmetry operation
 
        cmd.iterate_state(1, prefix + "*", "stored.tmpObject = model")
 
        ops = get_operations(stored.tmpObject)
 
        opString = ""
 
        for i in range(len(ops)):
 
            opString = opString + str(i) + " : " + ops[i] + "\n"
 
        opIndeces = tkSimpleDialog.askstring("Symmetry Operations", opString +
 
        "Enter numbers of desired operations separated by commas (ex:0,2,9) or all", parent = app.root)
 
        if opIndeces == "all":
 
            opList = []
 
            for i in range(len(ops)):
 
                opList.append(i)
 
        else:
 
            opList = opIndeces.split(",")
 
        opStringList = opString.split("\n")
 
        for i in opList:
 
            tempColor = tkColorChooser.askcolor(title = "Color for " + opStringList[int(i)], parent = app.root)[0]
 
            rgb = []
 
            for value in tempColor:
 
                value = float(value)
 
                value = value/255
 
                rgb.append(value)
 
            cmd.set_color("tempColor", rgb)
 
            try:
 
                if int(i) < 10:
 
                    cmd.color("tempColor", prefix + "0" + str(i) + "*")
 
                if int(i) > 9:
 
                    cmd.color("tempColor", prefix + str(i) + "*")
 
            except:
 
                pass
 
    if mode == 2: #monochrome for a set of operations
 
        cmd.iterate_state(1, prefix + "*", "stored.tmpObject = model")
 
        ops = get_operations(stored.tmpObject)
 
        opString = ""
 
        for i in range(len(ops)):
 
            opString = opString + str(i) + " : " + ops[i] + "\n"
 
        opIndeces = tkSimpleDialog.askstring("Symmetry Operations", opString +
 
        "Enter numbers of desired operations separated by commas (ex:0,2,9) or all", parent = app.root)
 
        if opIndeces == 'all':
 
            opList = []
 
            for i in range(len(ops)):
 
                opList.append(i)
 
        else:
 
            opList = opIndeces.split(",")
 
        opStringList = opString.split("\n")
 
        tempColor = tkColorChooser.askcolor(parent = app.root)[0]
 
        rgb = []
 
        for value in tempColor:
 
            value = float(value)
 
            value = value/255
 
            rgb.append(value)
 
        cmd.set_color("tempColor", rgb)
 
        for i in opList:
 
            try:
 
                if int(i) < 10:
 
                    cmd.color("tempColor", prefix + "0" + str(i) + "*")
 
                if int(i) > 9:
 
                    cmd.color("tempColor", prefix + str(i) + "*")
 
            except:
 
                pass
 
'''
 
graphicsDialog: Dialog generator for graphics commands
 
 
 
This function sets visual representations for sets of symmetry partners.
 
 
 
@app -- identifies root menu
 
@mode -- determines type of representation to show
 
'''
 
def graphicsDialog(app, mode):
 
    prefix = tkSimpleDialog.askstring('Prefix',
 
    'Enter prefix of symmetry partners to display', parent = app.root)
 
    cmd.hide("everything", prefix + "*")
 
    if mode == 0: # show lines
 
        cmd.show("lines", prefix + "*")
 
    if mode == 1: # show ribbon
 
        cmd.show("ribbon", prefix + "*")
 
    if mode == 2: # sphere surface
 
        objSel = prefix + "*"
 
        findSurfaceResidues(objSel, 3.5, "surface")
 
        cmd.set("sphere_scale", 1.8)
 
        cmd.show("spheres", "surface")
 
    if mode == 3: # regular surface
 
        cmd.show("surface", prefix + "*")
 
 
 
'''
 
cellDialog: dialog proxy for draw_cell
 
 
 
This function generates a unit cell representation
 
FUTURE IMPLEMENTATIONS: select which lattice coordinates to generate unit cell for
 
 
 
@app -- identifies root menu
 
'''
 
def cellDialog(app):
 
    object = tkSimpleDialog.askstring('Object',
 
    'Enter object to generate cell for:', parent = app.root)
 
    if tkMessageBox.askyesno('3D Printing', 'Going to print this model?', parent = app.root):
 
        draw_cell.draw_cell(object, 3.0)
 
    else:
 
        draw_cell.draw_cell(object)
 
 
 
'''
 
axesDialog: dialog proxy for draw_symops_cctbx
 
 
 
This function generates one set of symmetry axes for a given object
 
FUTURE IMPLEMENTATIONS: select individual axes to generate, attach to model for 3D printing,
 
                        generate axes for multiple unit cells
 
 
 
@app -- identifies root menu
 
'''
 
def axesDialog(app):
 
    object = tkSimpleDialog.askstring('Object',
 
    'Enter object to generate symmetry axes for:', parent = app.root)
 
    if tkMessageBox.askyesno('3D Printing', 'Going to print this model?', parent = app.root):
 
        sym_axes.draw_symops(object, 2.0)
 
    else:
 
        sym_axes.draw_symops(object)
 
 
 
'''
 
cellShiftInfo: displays info for using cell_shift hotkeys
 
 
 
@app -- identifies root menu
 
'''
 
def cellShiftInfo(app):
 
    tkMessageBox.showinfo('Cell Shifting',
 
    "To shift a symmetry partner, simply click to select any part of it (select only one partner at a time). \n\n" +
 
    "Next, hold ALT and press the numpad key corresponding to the axis direction you\'d like to move. \n\n" +
 
    "Key assignments:\n" +
 
    "A (x) axis: down--4, up--6 \n" +
 
    "B (y) axis: down--2, up--8 \n" +
 
    "C (z) axis: down--1, up--5", parent = app.root)
 
    tkMessageBox.showwarning('Caution', 'Only attempt to shift symmetry partners created by SuperSym.'+
 
                            'Attempting to shift any other object will result in errors.')
 
 
 
def aboutInfo(app):
 
    tkMessageBox.showinfo('About',
 
                          'SuperSym v1.0\nDeveloped by Stuart Ballard (srballard@wisc.edu)\nDepartment of Biochemistry\n'+
 
                          'University of Wisconsin-Madison', parent = app.root)
 
def helpInfo(app):
 
    tkMessageBox.showinfo('Help',
 
                          'For documentation see http://pymolwiki.org/index.php/SuperSym', parent = app.root)
 
 
 
'''
 
symset: generates up to one full set of symmetry partners for a given object in a given lattice position
 
 
 
1. Obtain all essential symmetry information from CCTBX. This includes the space group, unit cell parameters,
 
and fractional coordinates corresponding to symmetry operations.
 
2. Generate transformation matrices to translate coordinates from orthogonal to fractional, and back.
 
3.
 
'''
 
def symset(prefix = "sym", object = -1, x=0,y=0,z=0, opList = []):
 
    if object == -1:
 
        object = cmd.get_names()[0]
 
    cell = [float(x),float(y),float(z)]
 
    view = cmd.get_view()
 
    cmd.show("lines", object)
 
    sgInfo = cmd.get_symmetry(object)
 
    raw_ops = []
 
    for s in sgtbx.space_group_info(sgInfo[6]).group():
 
        raw_ops.append(str(s))
 
    if (len(opList) == 0):
 
        for i in range(len(raw_ops)):
 
            opList.append(i)
 
    a,b,c,alpha,beta,gamma = sgInfo[0:6]
 
    ca = math.cos(math.radians(alpha))
 
    cb = math.cos(math.radians(beta))
 
    cg = math.cos(math.radians(gamma))
 
    sb = math.sin(math.radians(beta))
 
    sg = math.sin(math.radians(gamma))
 
    stored.fracToOrt = N.array([[a, b * cg, c * cb],
 
                                [0.0, b * sg, c * (ca - cb * cg) / sg],
 
                                [0.0, 0.0, c * sb * math.sqrt(1.0 - ((cb * cg - ca) / (sb * sg))**2)]])
 
    stored.fracToOrt = stored.fracToOrt.transpose()
 
    stored.ortToFrac = inv(stored.fracToOrt)
 
    for i in opList:
 
        try:
 
            stored.tmpOp = raw_ops[i]
 
        except:
 
            print "Bad symmetry partner numbers. Try again."
 
            quit()
 
        if i > 9:
 
            copy = prefix + str(i) + "_" + str(x) + "_" + str(y) + "_" + str(z)
 
        else:
 
            copy = prefix + "0" + str(i) + "_" + str(x) + "_" + str(y) + "_" + str(z)
 
        cmd.copy(copy, object)
 
        #COPIES COORDINATES OF EACH ATOM TO CORRESPONDING ONE IN GIVEN SYMMETRY PARTNER
 
        cmd.alter_state(1, copy, "x,y,z = cmd.sym_partner([x,y,z], stored.tmpOp)")
 
        #MOVES SYMMETRY PARTNER TO PROPER LATTICE COORDINATES AND CORRECTS FOR NATIVE LATTICE POSITION ERROR
 
        stored.xSum,stored.ySum,stored.zSum = 0.0,0.0,0.0
 
        atoms = cmd.count_atoms(copy)
 
        cmd.iterate_state(1, copy, "stored.xSum = stored.xSum + x; stored.ySum = stored.ySum + y; stored.zSum = stored.zSum + z")
 
        xMean = (stored.xSum / atoms)
 
        yMean = (stored.ySum / atoms)
 
        zMean = (stored.zSum / atoms)
 
        xError, yError, zError = N.dot(N.array([xMean,yMean,zMean]), stored.ortToFrac)
 
        dX,dY,dZ = -math.floor(xError) + cell[0], -math.floor(yError) + cell[1], -math.floor(zError) + cell[2]
 
        cell_shift(copy,dX,dY,dZ, 0)
 
    cmd.hide("everything", object)
 
    cmd.set_view(view)
 
 
 
def sym_partner(coords, op):
 
    fracCoords = N.dot(N.array(coords), stored.ortToFrac)
 
    op = op.replace("x", "(" + str(fracCoords[0]) + ")")
 
    op = op.replace("y", "(" + str(fracCoords[1]) + ")")
 
    op = op.replace("z", "(" + str(fracCoords[2]) + ")")
 
    op = op.split(",")
 
    for i in range(3):
 
        index = op[i].find("/")
 
        if index != -1:
 
            if len(op[i]) == index + 2:
 
                op[i] = op[i][0:index - 1] + str(float(op[i][index - 1]) / float(op[i][index + 1]))
 
            else:
 
                op[i] = op[i][0:index - 1] + str(float(op[i][index - 1]) / float(op[i][index + 1])) + op[i][index + 2:]
 
        op[i] = eval(op[i])
 
    return N.dot(N.array(op), stored.fracToOrt)
 
 
 
def cell_shift_proxyX1():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, 1,0,0)
 
def cell_shift_proxyX2():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, -1,0,0)
 
def cell_shift_proxyY1():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, 0,1,0)
 
def cell_shift_proxyY2():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, 0,-1,0)
 
def cell_shift_proxyZ1():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, 0,0,1)
 
def cell_shift_proxyZ2():
 
    cmd.iterate_state(1, "sele", "stored.tmpObject = model")
 
    cell_shift(stored.tmpObject, 0,0,-1)
 
 
 
def cell_shift(object, dX, dY, dZ, rename = 1):
 
    if rename:
 
        oldName = object.split("_")
 
        oldPre = oldName[0]
 
        oldX = int(oldName[1])
 
        oldY = int(oldName[2])
 
        oldZ = int(oldName[3])
 
        newX = "_" + str(int(dX) + oldX)
 
        newY = "_" + str(int(dY) + oldY)
 
        newZ = "_" + str(int(dZ) + oldZ)
 
        newName = oldPre + newX + newY + newZ
 
        #if cmd.get_names().find(newName) != -1:
 
        #    print "Symmetry partner already exists in destination position!"
 
        #    quit()
 
        cmd.set_name(object, newName)
 
object = newName
 
    stored.shift = [float(dX),float(dY),float(dZ)]
 
    stored.sgInfo = cmd.get_symmetry(object)
 
    a,b,c,alpha,beta,gamma = stored.sgInfo[0:6]
 
    ca = math.cos(math.radians(alpha))
 
    cb = math.cos(math.radians(beta))
 
    cg = math.cos(math.radians(gamma))
 
    sb = math.sin(math.radians(beta))
 
    sg = math.sin(math.radians(gamma))
 
    stored.fracToOrt = N.array([[a, b * cg, c * cb],
 
                                [0.0, b * sg, c * (ca - cb * cg) / sg],
 
                                [0.0, 0.0, c * sb * math.sqrt(1.0 - ((cb * cg - ca) / (sb * sg))**2)]])
 
    stored.fracToOrt = stored.fracToOrt.transpose()
 
    stored.ortToFrac = inv(stored.fracToOrt)
 
    cmd.alter_state(1, object, "x,y,z = cmd.cell_shift_helper([x,y,z],stored.shift)")
 
   
 
 
 
def shift_and_copy(object, dX, dY, dZ):
 
    oldName = object.split("_")
 
    oldPre = oldName[0]
 
    oldX = int(oldName[1])
 
    oldY = int(oldName[2])
 
    oldZ = int(oldName[3])
 
    newX = "_" + str(int(dX) + oldX)
 
    newY = "_" + str(int(dY) + oldY)
 
    newZ = "_" + str(int(dZ) + oldZ)
 
    copy = oldPre + newX + newY + newZ
 
    if cmd.count_atoms(copy) != 0:
 
        print "Symmetry partner already exists in destination position!"
 
        quit()
 
    cmd.copy(newName, object)
 
    stored.shift = [float(dX),float(dY),float(dZ)]
 
    stored.sgInfo = cmd.get_symmetry(object)
 
    a,b,c,alpha,beta,gamma = stored.sgInfo[0:6]
 
    ca = math.cos(math.radians(alpha))
 
    cb = math.cos(math.radians(beta))
 
    cg = math.cos(math.radians(gamma))
 
    sb = math.sin(math.radians(beta))
 
    sg = math.sin(math.radians(gamma))
 
    stored.fracToOrt = N.array([[a, b * cg, c * cb],
 
                                [0.0, b * sg, c * (ca - cb * cg) / sg],
 
                                [0.0, 0.0, c * sb * math.sqrt(1.0 - ((cb * cg - ca) / (sb * sg))**2)]])
 
    stored.fracToOrt = stored.fracToOrt.transpose()
 
    stored.ortToFrac = inv(stored.fracToOrt)
 
    cmd.alter_state(1, newName, "x,y,z = cell_shift_helper([x,y,z],stored.shift)")
 
 
 
 
 
def cell_shift_helper(coords, shift):
 
    fracCoords = N.dot(N.array(coords), stored.ortToFrac)
 
    for i in range(3):
 
        fracCoords[i] = fracCoords[i] + shift[i]
 
    coords = N.dot(N.array(fracCoords), stored.fracToOrt)
 
    return coords[0], coords[1], coords[2]
 
 
 
def get_operations(object):
 
    raw_ops = []
 
    sgInfo = cmd.get_symmetry(object)
 
    for s in sgtbx.space_group_info(sgInfo[6]).group():
 
        raw_ops.append(str(s))
 
    return raw_ops 
 
 
 
def get_orthogonalization_matrix(object, quiet = 0):
 
    a,b,c,alpha,beta,gamma = cmd.get_symmetry(object)[0:6]
 
    ca = math.cos(math.radians(alpha))
 
    cb = math.cos(math.radians(beta))
 
    cg = math.cos(math.radians(gamma))
 
    sb = math.sin(math.radians(beta))
 
    sg = math.sin(math.radians(gamma))
 
    fracToOrt = N.array([[a, b * cg, c * cb],
 
                                [0.0, b * sg, c * (ca - cb * cg) / sg],
 
                                [0.0, 0.0, c * sb * math.sqrt(1.0 - ((cb * cg - ca) / (sb * sg))**2)]])
 
    if not quiet:
 
        print fracToOrt
 
        print inv(fracToOrt)
 
    return fracToOrt
 
 
 
# -*- coding: utf-8 -*-
 
# this function is borrowed from findSurfaceResidues script on PyMOL wiki
 
def findSurfaceResidues(objSel="(all)", cutoff=2.5, selName = 0):
 
"""
 
findSurfaceResidues
 
finds those residues on the surface of a protein
 
that have at least 'cutoff' exposed A**2 surface area.
 
 
PARAMS
 
objSel (string)
 
the object or selection in which to find
 
exposed residues
 
DEFAULT: (all)
 
 
cutoff (float)
 
your cutoff of what is exposed or not.
 
DEFAULT: 2.5 Ang**2
 
 
asSel (boolean)
 
make a selection out of the residues found
 
 
RETURNS
 
(list: (chain, resv ) )
 
A Python list of residue numbers corresponding
 
to those residues w/more exposure than the cutoff.
 
 
"""
 
tmpObj="__tmp"
 
cmd.create( tmpObj, objSel + " and polymer");
 
cmd.set("dot_solvent");
 
cmd.get_area(selection=tmpObj, load_b=1)
 
 
# threshold on what one considers an "exposed" atom (in A**2):
 
cmd.remove( tmpObj + " and b < " + str(cutoff) )
 
 
stored.tmp_dict = {}
 
cmd.iterate(tmpObj, "stored.tmp_dict[(chain,resv)]=1")
 
exposed = stored.tmp_dict.keys()
 
exposed.sort()
 
 
cmd.select(selName, objSel + " in " + tmpObj )
 
cmd.delete(tmpObj)
 
 
return exposed
 
</source>
 
File: SuperSymMenu.py
 
<source lang="python">
 
from Tkinter import *
 
import tkFileDialog
 
from pymol import cmd, selector
 
from SuperSym import *
 
 
 
def __init__(self):
 
    #MAIN
 
    self.menuBar.addmenu('SuperSym','SuperSym')
 
    #DEFAULT SET BUILD
 
    self.menuBar.addmenuitem('SuperSym', 'command', 'Default Symmetry Partner Set',
 
                            label = 'Default Symmetry Partner Set',
 
                            command = lambda s = self: symDialog(s, 0))
 
    #UNIT CELL BUILD
 
    self.menuBar.addmenuitem('SuperSym', 'command', 'Draw Unit Cell',
 
                            label = 'Draw Unit Cell',
 
                            command = lambda s = self: cellDialog(s))
 
    #SYM SUBMENU
 
    self.menuBar.addcascademenu('SuperSym', 'Build Symmetry Partners')
 
 
 
    self.menuBar.addmenuitem('Build Symmetry Partners', 'command', 'Cell [0,0,0] (default)',
 
                            label = 'Cell [0,0,0] (default)',
 
                            command = lambda s = self: symDialog(s, 0))
 
 
 
    self.menuBar.addmenuitem('Build Symmetry Partners', 'command', 'Cell [x,y,z] (custom)',
 
                            label = 'Cell [x,y,z] (custom)',
 
                            command = lambda s = self: symDialog(s, 1))
 
 
 
    self.menuBar.addmenuitem('Build Symmetry Partners', 'command', '2x2x2 Block',
 
                            label = '2x2x2 Block',
 
                            command = lambda s = self: symDialog(s, 2))
 
 
 
    self.menuBar.addmenuitem('Build Symmetry Partners', 'command', '3x3x3 Block',
 
                            label = '3x3x3 Block',
 
                            command = lambda s = self: symDialog(s, 3))
 
 
 
    self.menuBar.addmenuitem('Build Symmetry Partners', 'command', 'By Partner',
 
                            label = 'By Partner',
 
                            command = lambda s = self: symDialog(s, 4))
 
    #COLOR SUBMENU
 
    self.menuBar.addcascademenu('SuperSym', 'Coloring')
 
 
 
    self.menuBar.addmenuitem('Coloring', 'command', 'Default Rainbow',
 
                            label = 'Default Rainbow',
 
                            command = lambda s = self: colorDialog(s, 0))
 
 
 
    self.menuBar.addmenuitem('Coloring', 'command', 'Select color for each operation',
 
                            label = 'Select color for each operation',
 
                            command = lambda s = self: colorDialog(s, 1))
 
 
 
    self.menuBar.addmenuitem('Coloring', 'command', 'Select one color for custom set of operations',
 
                            label = 'Select one color for custom set of operations',
 
                            command = lambda s = self: colorDialog(s, 2))
 
    #GRAPHICS SUBMENU
 
    self.menuBar.addcascademenu('SuperSym', 'Graphics')
 
 
 
    self.menuBar.addmenuitem('Graphics', 'command', 'Lines',
 
                            label = 'Lines',
 
                            command = lambda s = self: graphicsDialog(s, 0))
 
 
 
    self.menuBar.addmenuitem('Graphics', 'command', 'Ribbon',
 
                            label = 'Ribbon',
 
                            command = lambda s = self: graphicsDialog(s, 1))
 
 
 
    self.menuBar.addmenuitem('Graphics', 'command', 'Sphere Surface (best for printing)',
 
                            label = 'Sphere Surface (best for printing)',
 
                            command = lambda s = self: graphicsDialog(s, 2))
 
 
 
    self.menuBar.addmenuitem('Graphics', 'command', 'Surface (high load render)',
 
                            label = 'Surface (high load render)',
 
                            command = lambda s = self: graphicsDialog(s, 3))
 
    #SYM AXES SUBMENU
 
    self.menuBar.addcascademenu('SuperSym', 'Symmetry Axes')
 
 
 
    self.menuBar.addmenuitem('Symmetry Axes', 'command', 'Build Axes',
 
                            label = 'Build Axes',
 
                            command = lambda s = self: axesDialog(s))
 
    #ADD OTHER SYMMETRY AXES OPTION HERE
 
    self.menuBar.addmenuitem('SuperSym', 'command', 'Move symmetry partners',
 
                            label = 'Move symmetry partners',
 
                            command = lambda s = self: cellShiftInfo(s))
 
    self.menuBar.addmenuitem('SuperSym', 'command', 'About',
 
                            label = 'About',
 
                            command = lambda s = self: aboutInfo(s))
 
    self.menuBar.addmenuitem('SuperSym', 'command', 'Help',
 
                            label = 'Help',
 
                            command = lambda s = self: helpInfo(s))
 
    cmd.cell_shift = cell_shift
 
    cmd.get_operations = get_operations
 
    cmd.get_matrix = get_orthogonalization_matrix
 
    cmd.symset = symset
 
    cmd.sym_partner = sym_partner
 
    cmd.cell_shift_helper = cell_shift_helper
 
    cmd.set_key("ALT-6", cell_shift_proxyX1)
 
    cmd.set_key("ALT-4", cell_shift_proxyX2)
 
    cmd.set_key("ALT-8", cell_shift_proxyY1)
 
    cmd.set_key("ALT-2", cell_shift_proxyY2)
 
    cmd.set_key("ALT-5", cell_shift_proxyZ1)
 
    cmd.set_key("ALT-1", cell_shift_proxyZ2)
 
</source>
 
File: draw_cell.py
 
<source lang="python">
 
#original code written by Robert Campbell
 
#modified by Stuart Ballard
 
from cctbx import uctbx, sgtbx
 
from pymol.cgo import *
 
from pymol import cmd
 
from pymol.vfont import plain
 
 
 
def set_to_zero(a):
 
  if abs(a) < 1e-10:
 
    a=0
 
  return a
 
 
 
def draw_cell(obj,radius=1.0,mode=0):
 
  """
 
  From pymol issue the "run draw_cell.py" command to load the script,
 
  then issue the "draw_cell(object,<optional radius>)" command
 
  to actually run it and create the cgo object showing the unit cell
 
  border for the space group specified by molecular object 'object'.
 
 
 
  e.g. load 1avv.pdb
 
      run draw_cell.py
 
      draw_cell 1avv 0.5  (or draw_cell('1avv',.5))
 
 
 
  see also help(draw_cell_param) to draw the cell border for
 
  user-defined cell dimensions (i.e. not loaded from a pdb file)
 
 
 
  See also "help(draw_cell_param) to draw the cell border by
 
  specifying the unit cell parameters directly (i.e. not loaded from
 
  a pdb file).
 
  """
 
  radius=float(radius)
 
  cell_info=cmd.get_symmetry(obj)
 
  draw_cell_param(cell_info[0:6],radius,mode)
 
 
 
def draw_cell_param(cell_param_list,radius=1.0,mode=0):
 
  """
 
  If you wish to draw the unit cell border for any cell without the
 
  need to load a pdb file, then do this:
 
 
 
  e.g. run draw_cell.py
 
      draw_cell_param((45.2,45.2,70.8,90.,90.,120.),0.5)
 
 
 
  to generate the cell border for this trigonal space group "p 31 2 1"
 
  with a radius of 0.5A.  Labels for the origin, and A, B and C axes
 
  will appear as well.  The perimeter of the cell is colored with the
 
  RGB components corresponding to the A,B,C components.
 
  """
 
 
 
  U=uctbx.unit_cell((cell_param_list))
 
 
 
  vert_000 = map(set_to_zero,U.orthogonalize((0.,0.,0)))
 
  vert_100 = map(set_to_zero,U.orthogonalize((1.,0.,0)))
 
  vert_010 = map(set_to_zero,U.orthogonalize((0.,1.,0)))
 
  vert_001 = map(set_to_zero,U.orthogonalize((0.,0.,1)))
 
  vert_110 = map(set_to_zero,U.orthogonalize((1.,1.,0)))
 
  vert_011 = map(set_to_zero,U.orthogonalize((0.,1.,1)))
 
  vert_101 = map(set_to_zero,U.orthogonalize((1.,0.,1)))
 
  vert_111 = map(set_to_zero,U.orthogonalize((1.,1.,1)))
 
 
 
#  vert_000 = map(None,U.orthogonalize((0.,0.,0)))
 
#  vert_100 = map(None,U.orthogonalize((1.,0.,0)))
 
#  vert_010 = map(None,U.orthogonalize((0.,1.,0)))
 
#  vert_001 = map(None,U.orthogonalize((0.,0.,1)))
 
#  vert_110 = map(None,U.orthogonalize((1.,1.,0)))
 
#  vert_011 = map(None,U.orthogonalize((0.,1.,1)))
 
#  vert_101 = map(None,U.orthogonalize((1.,0.,1)))
 
#  vert_111 = map(None,U.orthogonalize((1.,1.,1)))
 
 
 
  #print vert_000
 
 
 
  #CYLINDER = ['CYLINDER']
 
  #radius = [0.2]
 
  #print radius
 
  cell = []
 
  cell.append(CYLINDER)
 
  cell = cell + vert_000 + vert_100 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_000 + vert_010 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_000 + vert_001 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_100 + vert_110 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_100 + vert_101 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_010 + vert_110 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_010 + vert_011 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_001 + vert_101 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_001 + vert_011 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_110 + vert_111 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_101 + vert_111 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(CYLINDER)
 
  cell = cell + vert_011 + vert_111 + [radius] + [1,1,1] + [1,1,1]
 
  cell.append(SPHERE)
 
  cell = cell + vert_000 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_001 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_010 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_011 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_100 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_101 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_110 + [radius]
 
  cell.append(SPHERE)
 
  cell = cell + vert_111 + [radius]
 
 
 
  cmd.load_cgo(cell,"cell")
 
  #return cell
 
 
 
  if mode == 1:
 
    text = [COLOR, 1.0, 0.0, 1.0,]
 
 
 
  #wire_text(text,plain,[-5.,-5.,-1],'Origin',[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]])
 
  #wire_text(text,plain,map(None,U.orthogonalize((1.05,0.0,0.0))),'A',[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]])
 
  #wire_text(text,plain,map(None,U.orthogonalize((0.0,1.05,0.0))),'B',[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]])
 
  #wire_text(text,plain,map(None,U.orthogonalize((0.0,0.0,1.05))),'C',[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]])
 
 
 
    cyl_text(text,plain,[-5.,-5.,-1],'Origin',0.20,axes=[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]],color=[1.0,0.0,1.0])
 
    cyl_text(text,plain,map(None,U.orthogonalize((1.05,0.0,0.0))),'A',0.20,axes=[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]],color=[1.0,0.0,0.0])
 
    cyl_text(text,plain,map(None,U.orthogonalize((0.0,1.05,0.0))),'B',0.20,axes=[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]],color=[0.0,1.0,0.0])
 
    cyl_text(text,plain,map(None,U.orthogonalize((0.0,0.0,1.05))),'C',0.20,axes=[[3.0,0.0,0.0],[0.0,3.0,0.0],[0.0,0.0,3.0]],color=[0.0,0.0,1.0])
 
 
 
    cmd.load_cgo(text,'text')
 
 
 
cmd.extend("draw_cell",draw_cell)
 
</source>
 
File: draw_symops_cctbx.py
 
<source lang="python">
 
#! /usr/bin/env python
 
# Copyright (c) 2004 Robert L. Campbell
 
 
 
from cctbx import uctbx, sgtbx
 
#import string, math
 
from pymol.cgo import *
 
from pymol import cmd
 
 
 
from all_axes_new import get_all_axes
 
 
 
import numpy as N
 
#import numarray as N
 
 
 
print "Finished importing for draw_symops_cctbx.py"
 
 
 
def set_to_zero(a):
 
  if abs(a) < 1e-10:
 
    a=0
 
  return a
 
 
 
def draw_symbol(start,end,symb,color,radius=0.2):
 
  degtorad = N.pi/180.
 
  costhirty = N.cos(30.0*degtorad)
 
  sinthirty = N.sin(30.0*degtorad)
 
  symb_obj = []
 
 
 
  if symb == '2' or symb == '2^1':
 
    pass
 
 
 
  elif symb == '3' or symb == '3^1' or symb == '3^2':
 
    symb_obj = [ BEGIN, TRIANGLES, COLOR ] + color
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([radius, 0, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([-radius*sinthirty, radius*costhirty, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([-radius*sinthirty, -radius*costhirty, 0]))[0].tolist()
 
 
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([radius, 0, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([-radius*sinthirty, radius*costhirty, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([-radius*sinthirty, -radius*costhirty, 0]))[0].tolist()
 
    symb_obj.append(END)
 
 
 
  elif symb == '4' or symb == '4^1' or symb == '4^2' or symb == '4^3':
 
    symb_obj = [ BEGIN, TRIANGLES, COLOR ] + color
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([-radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([-radius, -radius, 0]))[0].tolist()
 
 
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([radius, -radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([start]) + N.array([-radius, -radius, 0]))[0].tolist()
 
 
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([-radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([-radius, -radius, 0]))[0].tolist()
 
 
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([radius, radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([radius, -radius, 0]))[0].tolist()
 
    symb_obj.append(VERTEX)
 
    symb_obj = symb_obj + (N.array([end]) + N.array([-radius, -radius, 0]))[0].tolist()
 
    symb_obj.append(END)
 
 
 
  elif symb == '6' or symb == '6^1' or symb == '6^2' or symb == '6^3' or symb == '6^4' or symb == '6^5':
 
    # hexagons still need to be created :)
 
    pass
 
 
 
  return symb_obj
 
 
 
def draw_symops(obj,radius=0.2,extension=0):
 
  """
 
  From pymol issue the "run draw_symops_cctbx.py" command to load the script,
 
  then issue the "draw_symops(object,<optional radius>,<optional extension>)" command
 
  to actually run it and create the cgo object.
 
 
 
  e.g. load 1avv.pdb
 
      run draw_symops_cctbx.py
 
      draw_symops 1avv, 0.5, .2 
 
        or draw_symops('1avv',.5,.2)
 
        or draw_symops 1avv, radius=.5, extension=.2
 
 
 
  The different axis types appear as different objects on the PyMOL menu so they can be turned
 
  on and off individually.
 
 
 
  See also help(draw_symops_param) to draw operators by specifying the space group
 
  and cell dimensions directly (i.e. not loaded from a pdb file)
 
 
 
  The 'extension' parameter is a fractional increase in the length of each symmetry
 
  operator axis drawn.  i.e. a value of 0 is the default and a value of .2 increases
 
  the length by 20% at each end
 
  """
 
  radius=float(radius)
 
  extension=float(extension)
 
  cell_info=cmd.get_symmetry(obj)
 
  draw_symops_param(cell_info[0:6],cell_info[6],radius,extension)
 
 
 
def draw_symops_param(cell_param_list,sg,radius=0.2,extension=0):
 
  """
 
  If you wish to draw the symmetry operators for any cell without the need to load a
 
  pdb file, then do this:
 
 
 
  e.g. run draw_symops_cctbx.py
 
      draw_symops_param((45.2,45.2,70.8,90.,90.,120.),'p3121',0.5,0.1)
 
 
 
  to generate the symmetry operators for this trigonal space group "p 31 2 1"
 
  of radius .5 with 10% added as an extension at each end.
 
  """
 
  radius=float(radius)
 
  extension=float(extension)
 
 
 
  U=uctbx.unit_cell((cell_param_list))
 
 
 
#rotation axes
 
#    "2" "yellow",
 
#    "3" "orange",
 
#    "4" "mauve",
 
#    "6" "purple",
 
 
 
#screw axes (all sub_1 axes are green)
 
#    "21" "green",
 
#    "31" "green",
 
#    "32" "lime",
 
#    "41" "green",
 
#    "42" "cyan",
 
#    "43" "iceblue",
 
#    "61" "green",
 
#    "62" "silver",
 
#    "63" "cyan",
 
#    "64" "iceblue",
 
#    "65" "blue",
 
 
 
  color = {
 
    "2" : [1.0, 1.0, 0.0],
 
    "3" : [1.0, 0.5, 0.0],
 
    "4" : [1.0, 0.5, 1.0],
 
    "6" : [1.0, 0.0, 1.0],
 
    "2^1" : [0.0, 1.0, 0.0],
 
    "3^1" : [0.0, 1.0, 0.0],
 
    "3^2" : [0.5, 1.0, 0.5],
 
    "4^1" : [0.0, 1.0, 0.0],
 
    "4^2" : [0.0, 1.0, 1.0],
 
    "4^3" : [0.5, 0.5, 1.0],
 
    "6^1" : [0.0, 1.0, 0.0],
 
    "6^2" : [0.8, 0.8, 0.8],
 
    "6^3" : [0.0, 1.0, 1.0],
 
    "6^4" : [0.5, 0.5, 1.0],
 
    "6^5" : [0.0, 0.0, 1.0],
 
    }
 
 
 
  sg = sg.upper()
 
  symop_axes = get_all_axes(sg,extension=extension)
 
 
 
  #CYLINDER = 'CYLINDER'
 
  ax_obj = {}
 
  #vert_obj = []
 
 
 
  #debug_out = open('debug.log','w')
 
 
 
  if symop_axes:
 
    for i in range(len(symop_axes)):
 
      #print symop_axes[i]
 
      start = map(set_to_zero,U.orthogonalize(map(None,symop_axes[i]['start'])))
 
      end = map(set_to_zero,U.orthogonalize(map(None,symop_axes[i]['end'])))
 
###############################################################################
 
# Tried rounding off start and end values in order to understand why axes go
 
# missing in the drawing, but seem to be present in the cgo.  Doesn't help!
 
# e.g. for space group 'p23' one of the 3-fold rotations is missing (0,0,0 -> x,-x,x)
 
# changing one cell axis to something ever so slightly different recovers the axis
 
# e.g. set cell to be (30.00001,30.,30.,90.,90.,90) and it works!
 
#    start = map(lambda x: round(x,3),U.orthogonalize(symop_axes[i]['start']))
 
#    end = map(lambda x: round(x,3),U.orthogonalize(symop_axes[i]['end']))
 
###############################################################################
 
      color_ax = color[symop_axes[i]['symb']]
 
      symb_ax = symop_axes[i]['symb']
 
 
 
      #print "axis: ",symb_ax, start, end
 
      if ax_obj.has_key(symb_ax):
 
        ax_obj[symb_ax].append(CYLINDER)
 
      else:
 
        ax_obj[symb_ax] = [CYLINDER]
 
 
 
      ax_obj[symb_ax] = ax_obj[symb_ax] + start + end + [radius]
 
      ax_obj[symb_ax] = ax_obj[symb_ax] + color[symb_ax] + color[symb_ax]
 
      ax_obj[symb_ax] = ax_obj[symb_ax] + draw_symbol(start,end,symb_ax,color[symb_ax],radius*6.)
 
 
 
#  #######################################################################################
 
#    # Debugging output to try to understand why some axes go missing in the drawing.
 
#    # They don't appear to be missing from the cgo object, though!
 
#    for xxx in ax_obj[symb_ax]:
 
#      if xxx == 9.0:
 
#        #print "\n\n",xxx
 
#        xxx = "\n\n" + str(xxx) + " "
 
#        debug_out.write(xxx)
 
#      else:
 
#        #print xxx
 
#        #xxx = "\n" + str(xxx) + " "
 
#        xxx = str(xxx) + " "
 
#        debug_out.write(xxx)
 
#      #print ax_obj[symb_ax]
 
#  debug_out.write("\n\n")
 
#  big_string = str(ax_obj)
 
#  debug_out.write(big_string)
 
#  # End of debugging output
 
#  #######################################################################################
 
 
 
  else:
 
    print "\nNo symmetry axes found for this space group: %s\n" % sg
 
 
 
  for key in ax_obj.keys():
 
    name=sg + "_" + key
 
    cmd.load_cgo(ax_obj[key],name)
 
    #debug_out.write("\n\n" + key + "\n" + str(ax_obj[key]))
 
  #return ax_obj
 
 
 
cmd.extend("draw_symops",draw_symops)
 
#cmd.extend("draw_symops_param",draw_symops_param)
 
</source>
 
File: all_axes_new.py
 
<source lang="python">
 
#! /usr/bin/env python
 
# List all axes in the unit cell.
 
 
 
# usage:
 
#  python all_axes.py    - show axes for the 230 reference settings.
 
#  python all_axes.py P2  - show axes for (e.g.) space group P2
 
 
 
# RWGK = Ralf W. Grosse-Kunstleve
 
# RWGK Some further refinement is required:
 
# RWGK  - List only the axes of highest order (e.g. only 4, not 4 and 2).
 
# RWGK  - List only the axes with the smallest intrinsic component
 
# RWGK    (e.g. list only 3(1), not both 3(1) and 3(2)).
 
# RWGK See also: comment regarding shift_range below.
 
 
 
from cctbx import sgtbx
 
#from cctbx.misc.python_utils import list_plus
 
 
 
import numpy as N
 
import string, re
 
 
 
def list_plus(lhs, rhs):
 
  return [l + r for l, r in zip(lhs, rhs)]
 
 
 
def list_minus(lhs, rhs):
 
  return [l - r for l, r in zip(lhs, rhs)]
 
 
 
def list_multiplies(lhs, rhs):
 
  return [l * r for l, r in zip(lhs, rhs)]
 
 
 
def list_divides(lhs, rhs):
 
  return [l / r for l, r in zip(lhs, rhs)]
 
 
 
def list_modulus(lhs, rhs):
 
  return [l % r for l, r in zip(lhs, rhs)]
 
 
 
def list_dot_product(lhs, rhs=0):
 
  if (rhs == 0): rhs = lhs
 
  result = 0
 
  for l, r in zip(lhs, rhs): result += l * r
 
  return result
 
 
 
def str_ev(EV):
 
  return "[%d,%d,%d]" % EV
 
 
 
###def fract_2_dec(fraction):
 
###  list = fraction.split('/')
 
###  if len(list) == 2 and list[1] != 0:
 
###    decimal = string.atof(list[0])/string.atof(list[1])
 
###  else:
 
###    decimal = string.atof(fraction)
 
###  return decimal
 
 
 
def rlc_RTMxAnalysis(M):
 
  r_info = sgtbx.rot_mx_info(M.r())
 
  t_info = sgtbx.translation_part_info(M)
 
  t_intrinsic = t_info.intrinsic_part().mod_positive().as_double()
 
  t_shift = t_info.origin_shift().mod_positive().as_double()
 
 
 
  #End = list_plus(Start + map(None,r_info.ev()))
 
####debug
 
###  trans = 0
 
###  length = 0
 
####debug
 
 
 
  #if (r_info.type() == 1):
 
  if (r_info.type() < 2):
 
    #(rt, start, end) = ('1',(0,0,0),(0,0,0))
 
    return None
 
  #elif (r_info.type() == -1):
 
  #  (rt, start, end) = (str(r_info.type()),t_shift,())
 
  elif (abs(r_info.type()) == 2):
 
    trans = reduce(lambda x,y:x+y,t_intrinsic)
 
    if trans == 0:
 
      maxr = max([abs(x) for x in r_info.ev()])
 
      r = [float(x)/maxr for x in r_info.ev()]
 
      (rt, start, end) = (str(r_info.type()),t_shift,tuple(list_plus(t_shift,r)))
 
      #(rt, start, end) = (str(r_info.type()),t_shift,tuple(list_plus(t_shift,r_info.ev())))
 
    else:
 
      maxr = max([abs(x) for x in r_info.ev()])
 
      r = [float(x)/maxr for x in r_info.ev()]
 
      (rt, start, end) = (str(r_info.type())+"^1",t_shift,tuple(list_plus(t_shift,r)))
 
      #(rt, start, end) = (str(r_info.type())+"^1",t_shift,tuple(list_plus(t_shift,r_info.ev())))
 
  elif (r_info.type() == 3):
 
    if (r_info.sense() >= 0) :
 
      # ignore opposite sense of rotation axes since they superimpose
 
      trans = N.sqrt(reduce(lambda x,y:x+y,(map(lambda x,y:(y-x)*(y-x),(0,0,0),t_intrinsic))))
 
#      trans = N.sqrt(t_intrinsic[0]**2 + t_intrinsic[1]**2 + t_intrinsic[2]**2)
 
      if trans == 0:
 
        maxr = max([abs(x) for x in r_info.ev()])
 
        r = [float(x)/maxr for x in r_info.ev()]
 
# fudge to make sure that PyMOL actually draws the axis (move it slightly off [1,-1,1]) !!!
 
        r[0] = r[0]*1.000001
 
        (rt, start, end) = (str(r_info.type()),t_shift,tuple(list_plus(t_shift,r)))
 
        #(rt, start, end) = (str(r_info.type()),t_shift, tuple(list_plus(t_shift,r_info.ev())))
 
      else:
 
        maxr = max([abs(x) for x in r_info.ev()])
 
        r = [float(x)/maxr for x in r_info.ev()]
 
        #(rt, start, end) = (str(r_info.type())+ "^" + subscript ,t_shift,tuple(list_plus(t_shift,r)))
 
        (start, end) = (t_shift,tuple(list_plus(t_shift,r)))
 
        length = N.sqrt(reduce(lambda x,y:x+y,(map(lambda x,y:(y-x)*(y-x),start, end))))
 
  
#  r_info.sense() for 3^1 and 3^2 seems always to be "1" ???
+
==Installing SuperSym==
#        if r_info.sense() < 0:
 
#          subscript = str(1-r_info.sense())
 
#        else:
 
#          subscript = str(r_info.sense())
 
  
# use ratio of trans to length to get the correct axis symbol:
+
To install SuperSym v1.2, download SuperSymPlugin12.py from [https://sourceforge.net/projects/supersym/ https://sourceforge.net/projects/supersym/]. In PyMOL, go to:
# fudged the value to get the right numbers. (using length/2., rather than length/3.)
+
*Plugin > Manage Plugins > Install...
        if trans < length*0.5 :
+
A file selector dialog will appear. Select SuperSymPlugin12.py. PyMOL will direct you to restart, and upon doing so SuperSym will be accessible through the Plugin menu.
          subscript = '1'
 
        else:
 
          subscript = '2'
 
  
        rt = str(r_info.type())+ "^" + subscript
+
To use functions of SuperSym directly, without creating a drop-down menu, use the run command in PyMOL on SuperSymPlugin12.py.
        #(rt, start, end) = (str(r_info.type()) + "^" + subscript,t_shift, tuple(list_plus(t_shift,r_info.ev())))
 
###        print "Type, sense, Start, End, length, trans", rt, r_info.sense(), start, end, length, trans
 
#        print "type: %s, sense: %s, trans: %s, length: %s," % (r_info.type(), r_info.sense(), trans, length)
 
#        print "(rt, start, end)", (rt,start,end)
 
    else:
 
      return None
 
  #return (r_info.type(),r_info.ev(), t_intrinsic, t_shift)
 
  elif (r_info.sense() > 0):
 
    # ignore opposite sense of rotation axes since they superimpose
 
    trans = reduce(lambda x,y:x+y,t_intrinsic)
 
    if trans == 0:
 
      maxr = max([abs(x) for x in r_info.ev()])
 
      r = [float(x)/maxr for x in r_info.ev()]
 
      (rt, start, end) = (str(r_info.type()),t_shift,tuple(list_plus(t_shift,r)))
 
      #(rt, start, end) = (str(r_info.type()),t_shift, tuple(list_plus(t_shift,r_info.ev())))
 
    else:
 
      maxr = max([abs(x) for x in r_info.ev()])
 
      r = [float(x)/maxr for x in r_info.ev()]
 
      subscript =  str(int(trans*r_info.type()+.5))  # add 0.5 to fix rounding errors
 
      (rt, start, end) = (str(r_info.type())+ "^" + subscript ,t_shift,tuple(list_plus(t_shift,r)))
 
      #(rt, start, end) = (str(r_info.type()) + "^" + subscript,t_shift, tuple(list_plus(t_shift,r_info.ev())))
 
  #return (r_info.type(),r_info.ev(), t_intrinsic, t_shift)
 
  else:
 
    return None
 
#  print "type: %s, sense: %s, trans: %s, length: %s," % (r_info.type(), r_info.sense(), trans, length),
 
#  print "(rt, start, end)", (rt,start,end)
 
  return (rt, start, end)
 
  
def get_all_axes(space_group_symbol=None, space_group_info=None, extension=0):
+
Note: previous errors resulting from incorrect naming of the plugin file have been resolved in v1.2.
  assert space_group_symbol is None or space_group_info is None
 
  shift_range = 1 # RWGK Works for the 230 reference settings; it is not
 
          # RWGK clear to me (rwgk) what value is needed in general.
 
  if (space_group_symbol is not None):
 
    space_group_info = sgtbx.space_group_info(symbol=space_group_symbol)
 
  #space_group_info.show_summary()
 
  
  axes_dict = {}
+
==Feedback==
  for smx in space_group_info.group():
 
    r = smx.r()
 
    t = smx.t()
 
    shift = [0,0,0]
 
    for shift[0] in range(-shift_range,shift_range+1):
 
      for shift[1] in range(-shift_range,shift_range+1):
 
        for shift[2] in range(-shift_range,shift_range+1):
 
          ts = t.plus(sgtbx.tr_vec(shift, 1)).new_denominator(t.den())
 
          m = sgtbx.rt_mx(r, ts)
 
          #print m
 
          rtmxanal = rlc_RTMxAnalysis(m)
 
          #print r, t, shift, ts, m
 
          if rtmxanal:
 
            #print rtmxanal
 
            axes_dict[rtmxanal] = 0
 
  axes_list = axes_dict.keys()
 
  axes_list.sort()
 
  
  # reject nonenantiomorphic space groups
+
Please post any comments, complaints, bug fix requests, useful tricks, or cool adaptations of SuperSym here.
  if len(axes_list) > 0 and not re.compile("[A-z]").search(space_group_symbol[1:]):
 
    try:
 
      sgtbx.space_group_info(space_group_symbol).show_summary(),
 
      #print len(axes_list), space_group_symbol
 
    except:
 
      print space_group, space_group_symbol
 
      print
 
      sys.exit(1)
 
    axes = []
 
    for a in axes_list:
 
      if len(a) == 3 and len(a[1]) == 3 and len(a[2]) == 3:
 
        tmp_dict = {}
 
        print "%4s %7.4f %7.4f %7.4f    %7.4f %7.4f %7.4f " % (a[0],a[1][0],a[1][1],a[1][2],a[2][0],a[2][1],a[2][2])
 
        tmp_dict['symb'] = a[0]
 
        start_array = N.asarray(a[1])
 
        end_array = N.asarray(a[2])
 
        start_vec = start_array - (end_array - start_array)*extension
 
        end_vec = end_array + (end_array - start_array)*extension
 
        tmp_dict['start'] = start_vec
 
        tmp_dict['end'] = end_vec
 
#rlc#        tmp_dict['start'] = a[1]
 
#rlc#        tmp_dict['end'] = a[2]
 
        axes.append(tmp_dict)
 
      else:
 
        print a
 
  else:
 
    return None
 
  
  return axes
+
==The Menu==
 +
*'''Default Symmetry Partner Set'''
 +
** See '''Build Symmetry Partners > Cell [0,0,0] (default)'''
 +
*'''Draw Unit Cell'''
 +
**Creates a cgo object with unit cell axes as cylinders. This functions similarly to ''show cell'', but the cell axes are cylinders instead of lines, allowing for printing.
 +
*'''Build Symmetry Partners >'''
 +
**All options in this submenu generate sets of symmetry partners
 +
**'''Cell [0,0,0] (default)'''
 +
***Generates a suite of symmetry partners for a given object for the default unit cell, which is lattice position [0,0,0]
 +
**'''Cell [x,y,z] (custom)'''
 +
***Generates a suite of symmetry partners for a given object for a lattice position which you specify
 +
**'''2x2x2 Block'''
 +
***Generates 8 sets of symmetry partners for a given object, filling lattice positions [0,0,0] through [1,1,1]
 +
**'''3x3x3 Block'''
 +
***Generates 27 sets of symmetry partners for a given object, filling lattice positions [-1,-1,-1] through [1,1,1]. This option may take a long time to execute
 +
**'''By Partner'''
 +
***Generates only those symmetry partners which the user specifies by their defining symmetry operators
 +
*'''Coloring >'''
 +
**'''Default Rainbow'''
 +
***Colors all symmetry objects with a specified by their symmetry operations automatically
 +
**'''Select color for each operation'''
 +
***Select symmetry partners to color by their defining symmetry operation and select the color for each
 +
**'''Select one color for custom set of operations'''
 +
***Select a set of symmetry partners defined by symmetry operations and select one color for all of them
 +
*'''Graphics >'''
 +
**'''Lines'''
 +
***Convenience function to display symmetry partners as lines
 +
**'''Ribbon'''
 +
**Convenience function to display symmetry partners as ribbons
 +
**'''Cartoon'''
 +
***Convenience function to display symmetry partners as cartoons
 +
**'''Sphere Surface (best for printing)'''
 +
***Uses the findSurfaceResidues function and shows surface residues as spheres. If printing, this option saves at least 60% of materials relative to regular surfaces, with minimal loss in resolution
 +
**'''Surface (high load render)'''
 +
***Displays symmetry partners as surfaces. This option may take a very long time to execute
 +
*'''Symmetry Axes >'''
 +
**'''Build Axes'''
 +
***Builds all symmetry axes for the given object. This functionality will be customizable and extended in future versions
 +
*'''Move symmetry partners'''
 +
**Merely displays instructions for using built in hotkeys to move symmetry partners
 +
*'''About'''
 +
**Developer info
 +
*'''Help'''
 +
**Reference to this page
  
if (__name__ == "__main__"):
+
[[Category:Plugins]]
  import sys
+
[[Category:Script_Library]]
  if (len(sys.argv) == 1):
+
[[Category:Math_Scripts]]
    for i in range(230):
 
      get_all_axes(i + 1)
 
  else:
 
    for symbol in sys.argv[1:]:
 
      get_all_axes(symbol)
 
</source>
 

Latest revision as of 06:26, 24 January 2019

Symmetry partners for 1hpv showing 6-1 screw axis
Full cell of symmetry partners with symmetry axes displayed

SuperSym is a PyMOL plugin providing a large number of tools for visualization of space groups; unit cells; and symmetry axes, operators, and partners. Source code for all versions is available from https://sourceforge.net/projects/supersym/, and the most recent code is available in regular text format from SuperSymSource.

Dependencies

PyMOL, cctbx and numpy must all be compiled with the same Python distribution! See CCTBX.

This plugin was developed in 2010 for PyMOL version 1.2r1 and has not been updated since.

Bugs

Symmetry axes are not defined for all space groups, and do not display properly for some.

Acknowledgments

Primary coding and development was done by Stuart Ballard. All comments, questions, and issues should be directed to him at srballard@wisc.edu.

Code for unit cell and symmetry axis building is borrowed from scripts created by Robert Campbell and Ralf W. Grosse-Kunstleve, available at http://pldserver1.biochem.queensu.ca/~rlc/work/pymol/. Some of this code has been modified for use in SuperSym.

FindSurfaceResidues is utilized for some of SuperSym's graphics generation, with some modifications.

Installing SuperSym

To install SuperSym v1.2, download SuperSymPlugin12.py from https://sourceforge.net/projects/supersym/. In PyMOL, go to:

  • Plugin > Manage Plugins > Install...

A file selector dialog will appear. Select SuperSymPlugin12.py. PyMOL will direct you to restart, and upon doing so SuperSym will be accessible through the Plugin menu.

To use functions of SuperSym directly, without creating a drop-down menu, use the run command in PyMOL on SuperSymPlugin12.py.

Note: previous errors resulting from incorrect naming of the plugin file have been resolved in v1.2.

Feedback

Please post any comments, complaints, bug fix requests, useful tricks, or cool adaptations of SuperSym here.

The Menu

  • Default Symmetry Partner Set
    • See Build Symmetry Partners > Cell [0,0,0] (default)
  • Draw Unit Cell
    • Creates a cgo object with unit cell axes as cylinders. This functions similarly to show cell, but the cell axes are cylinders instead of lines, allowing for printing.
  • Build Symmetry Partners >
    • All options in this submenu generate sets of symmetry partners
    • Cell [0,0,0] (default)
      • Generates a suite of symmetry partners for a given object for the default unit cell, which is lattice position [0,0,0]
    • Cell [x,y,z] (custom)
      • Generates a suite of symmetry partners for a given object for a lattice position which you specify
    • 2x2x2 Block
      • Generates 8 sets of symmetry partners for a given object, filling lattice positions [0,0,0] through [1,1,1]
    • 3x3x3 Block
      • Generates 27 sets of symmetry partners for a given object, filling lattice positions [-1,-1,-1] through [1,1,1]. This option may take a long time to execute
    • By Partner
      • Generates only those symmetry partners which the user specifies by their defining symmetry operators
  • Coloring >
    • Default Rainbow
      • Colors all symmetry objects with a specified by their symmetry operations automatically
    • Select color for each operation
      • Select symmetry partners to color by their defining symmetry operation and select the color for each
    • Select one color for custom set of operations
      • Select a set of symmetry partners defined by symmetry operations and select one color for all of them
  • Graphics >
    • Lines
      • Convenience function to display symmetry partners as lines
    • Ribbon
    • Convenience function to display symmetry partners as ribbons
    • Cartoon
      • Convenience function to display symmetry partners as cartoons
    • Sphere Surface (best for printing)
      • Uses the findSurfaceResidues function and shows surface residues as spheres. If printing, this option saves at least 60% of materials relative to regular surfaces, with minimal loss in resolution
    • Surface (high load render)
      • Displays symmetry partners as surfaces. This option may take a very long time to execute
  • Symmetry Axes >
    • Build Axes
      • Builds all symmetry axes for the given object. This functionality will be customizable and extended in future versions
  • Move symmetry partners
    • Merely displays instructions for using built in hotkeys to move symmetry partners
  • About
    • Developer info
  • Help
    • Reference to this page