Visualizing Torsional Angle Distribution¶
Problem¶
You want to generate an interactive image (in svg file format) that visualizes the distribution of dihedral angles of rotatable bond in a multi-conformer molecule. See example in Figure 1.
hover over any rotatable bond in the molecule (marked with a circle)
Figure 1. Example of visualizing torsional information
Ingredients¶
|
Difficulty level¶
Download¶
Solution¶
The first step of generating the image is to identify the rotatable bonds in the input molecule using the IsRotatableOrMacroCycleBond bond predicate. The get_dihedrals function iterates over rotatable bonds and identifies their dihedral atoms. These dihedral atoms are stored on the molecule in a OEGroupBase object for further process.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class IsRotatableOrMacroCycleBond(oechem.OEUnaryBondPred):
"""
Identifies rotatable bonds and single bonds in macro-cycles.
"""
def __call__(self, bond):
"""
:type mol: oechem.OEBondBase
:rtype: boolean
"""
if bond.GetOrder() != 1:
return False
if bond.IsAromatic():
return False
isrotor = oechem.OEIsRotor()
if isrotor(bond):
return True
if oechem.OEBondGetSmallestRingSize(bond) >= 10:
return True
return False
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | def get_dihedrals(mol, itag):
"""
Iterates over rotatable bonds and identifies their dihedral
atoms. These atoms are added to the molecule in a group
using the given tag.
:type mol: oechem.OEMol
:type itag: int
:return: Number of dihedral angles identified
:rtype: int
"""
nrdihedrals = 0
for bond in mol.GetBonds(IsRotatableOrMacroCycleBond()):
atomB = bond.GetBgn()
atomE = bond.GetEnd()
neighB = None
neighE = None
for atom in atomB.GetAtoms(oechem.OEIsHeavy()):
if atom != atomE:
neighB = atom
break
for atom in atomE.GetAtoms(oechem.OEIsHeavy()):
if atom != atomB:
neighE = atom
break
if neighB is None or neighE is None:
continue
atomorder = [neighB, atomB, atomE, neighE]
bondorder = [mol.GetBond(neighB, atomB), bond, mol.GetBond(neighE, atomE)]
if neighB.GetIdx() < neighE.GetIdx():
atomorder.reverse()
bondorder.reverse()
atoms = oechem.OEAtomVector(atomorder)
bonds = oechem.OEBondVector(bondorder)
nrdihedrals += 1
mol.NewGroup(itag, atoms, bonds)
return nrdihedrals
|
After the dihedral atoms are identified, the set_dihedral_histograms function is used to iterate over the conformation of the molecule and calculate torsion angles using the OEGetTorsion function . These angles are binned to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | def set_dihedral_histograms(mol, itag, nrbins):
"""
Iterates over the dihedral groups and bins the torsional
angles for each conformation. The histogram data is then
attached to the groups with the given tag.
:type mol: oechem.OEMol
:type itag: int
:type nrbins: int
"""
angleinc = 360.0 / float(nrbins)
for group in mol.GetGroups(oechem.OEHasGroupType(itag)):
atoms = oechem.OEAtomVector()
for atom in group.GetAtoms():
atoms.append(atom)
histogram = [0] * nrbins
for conf in mol.GetConfs():
rad = oechem.OEGetTorsion(conf, atoms[0], atoms[1], atoms[2], atoms[3])
deg = math.degrees(rad)
deg = (deg + 360.0) % 360.0
binidx = int(math.floor((deg / angleinc)))
histogram[binidx] += 1
group.SetData(itag, histogram)
|
The last step is to highlight the dihedral atoms when hovered over and depict the corresponding dihedral angle histogram. In order to achieve the hover effect in the generated SVG image, SVG groups are utilized (OESVGGroup) in the depict_dihedrals function. For each dihedral two groups are created. These groups are associated by calling the OEAddSVGHover function: while hovering the mouse over objects drawn inside the torsion_area_<id> the objects drawn in the torsion_data_<id> will be displayed. The group id must be unique amongst all the ids in the SVG image. Everything that is rendered between the OEImageBase.PushGroup and the corresponding OEImageBase.PopGroup methods is considered “inside” the group.
It is important that the molecule is rendered into the image after the dihedral angles are highlighted (after the second loop). As a result the highlight will appear underneath the molecule rather than on top of.
In the last loop of the depict_dihedrals function transparent circles are drawn (using OESVGAreaPen) in the middle of the the dihedral angle representing the hover areas in the interactive SVG image.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | def depict_dihedrals(image, dimage, mol, refmol, opts, itag, nrbins, colorg):
"""
Highlights the dihedral atoms of a torsion and the depicts the
corresponding dihedral angle histogram when hovering over
the center of the torsion on the molecule display.
:type image: oedepict.OEImageBase
:type dimage: oedepict.OEImageBase
:type mol: oechem.OEMol
:type refmol: oechem.OEMol
:type opts: oedepict.OE2DMolDisplayOptions
:type itag: int
:type nrbins: int
:type oechem.OEColorGradientBase
"""
nrconfs = mol.NumConfs()
center = oedepict.OEGetCenter(dimage)
radius = min(dimage.GetWidth(), dimage.GetHeight()) * 0.40
draw_dihedral_circle(dimage, center, radius, nrbins, nrconfs)
suppressH = True
oegrapheme.OEPrepareDepictionFrom3D(mol, suppressH)
if refmol is not None:
oegrapheme.OEPrepareDepictionFrom3D(refmol, suppressH)
disp = oedepict.OE2DMolDisplay(mol, opts)
dihedrals = []
ref_dihedrals = []
centers = []
agroups = []
dgroups = []
nrdihedrals = 0
for group in mol.GetGroups(oechem.OEHasGroupType(itag)):
uniqueid = uuid.uuid4().hex
agroup = image.NewSVGGroup("torsion_area_" + uniqueid)
dgroup = image.NewSVGGroup("torsion_data_" + uniqueid)
oedepict.OEAddSVGHover(agroup, dgroup)
dihedrals.append(group)
if refmol is not None:
ref_dihedrals.append(get_reference_dihedral(group, refmol, itag))
centers.append(get_center(disp, group))
agroups.append(agroup)
dgroups.append(dgroup)
nrdihedrals += 1
for didx in range(0, nrdihedrals):
image.PushGroup(dgroups[didx])
dihedral = dihedrals[didx]
abset = oechem.OEAtomBondSet(dihedral.GetAtoms(), dihedral.GetBonds())
draw_highlight(image, disp, abset)
dihedral_histogram = dihedral.GetData(itag)
draw_dihedral_histogram(dimage, dihedral_histogram, center, radius, nrbins, nrconfs)
if refmol is not None and ref_dihedrals[didx] is not None:
ref_dihedral = ref_dihedrals[didx]
draw_reference_dihedral(dimage, ref_dihedral, itag, center, radius)
image.PopGroup(dgroups[didx])
clearbackground = True
oedepict.OERenderMolecule(image, disp, not clearbackground)
markpen = oedepict.OEPen(oechem.OEBlack, oechem.OEWhite, oedepict.OEFill_On, 1.0)
farpen = oedepict.OEPen(oechem.OEBlack, oechem.OERed, oedepict.OEFill_Off, 2.0)
angleinc = 360.0 / float(nrbins)
for didx in range(0, nrdihedrals):
image.PushGroup(agroups[didx])
dihedral = dihedrals[didx]
dihedral_histogram = dihedral.GetData(itag)
flexibility = determine_flexibility(dihedral_histogram)
color = colorg.GetColorAt(flexibility)
markpen.SetBackColor(color)
markradius = disp.GetScale() / 8.0
image.DrawCircle(centers[didx], markradius, markpen)
if refmol is not None and ref_dihedrals[didx] is not None:
ref_dihedral = ref_dihedrals[didx]
if get_closest_dihedral_angle(mol, dihedral, ref_dihedral, itag) > angleinc:
image.DrawCircle(centers[didx], markradius, farpen)
radius = disp.GetScale() / 4.0
image.DrawCircle(centers[didx], radius, oedepict.OESVGAreaPen)
image.PopGroup(agroups[didx])
|
Usage¶
Usage
dihedral2img.py and acyclovi.sdf multi-conformer molecule file
The following command will generate the image shown in Figure 1:
prompt > python3 dihedral2img.py -in acyclovi.sdf -out acyclovi.svg
Command Line Parameters¶
Simple parameter list
input/output options
-in : Input filename of a multi conformer molecule
-out : Output filename of the generated image
-ref : Input filename of reference molecule
visualization options
-flexibility : Visualize dihedral angle flexibility
-nrbins : Number of bins in the dihedral angle histogram
Discussion¶
OpenEye’s Omega TK can be used to generate diverse sets of low-energy conformations.
Usage
The following commands will generate a multi-conformer file for molecule acyclovi:
prompt > echo "c1nc2c(=O)[nH]c(nc2n1COCCO)N acyclovi" > acyclovi.ism
prompt > python3 omega.py acyclovi.ism acyclovi.sdf
Visualizing Torsion Flexibility¶
By using the -flexibility parameter, the flexibility of the torsions angles can be visualized using a color gradient. Torsions with high flexibility are colored red, while black color indicates restrained torsion angles.
The flexibility of the torsion is determined with the following rudimentary method:
1 2 3 4 5 6 7 8 9 10 | def determine_flexibility(histogram):
"""
Returns the simple estimation of torsion flexibility by counting the
number of non-zero bins in the torsional histogram.
:type histogram: list(int)
"""
nr_non_zero_bins = sum([1 for x in histogram if x > 0]) * 2
return nr_non_zero_bins
|
Usage
dihedral2img.py and penicillin.sdf multi-conformer molecule file
The following command will generate the image shown in Figure 2:
prompt > python3 dihedral2img.py -in penicillin.sdf -out penicillin.svg -flexibility
The Figure 2 shows that the preferred angle of the amide bond in the molecule is around 180° coloring the corresponding bond circle black, while the other bonds have more flexibility. The utilized color gradient can revealed by hovering over the “Legend” label.
hover over any rotatable bond in the molecule (marked with a circle)
Figure 2. Example of visualizing torsion flexibility
Visualizing Torsional Angle Distribution with Reference¶
By using the -ref parameter, the torsion angle of a reference molecule (such as experimental conformation) can visualized in the generated image.
Usage
dihedral2img.py and 0QI.sdf multi-conformer molecule file with corresponding 0QI.pdb reference molecule file
The following command will generate the image shown in Figure 3:
prompt > python3 dihedral2img.py -in 0QI.sdf -ref 0QI.pdb -out 0QI.svg
When hovering over a rotatable bond in Figure 3 the corresponding torsional angle of the reference molecule is depicted in the middle of the radial histogram. Red circle is depicted around the bond marker when the reference angle is not close to any generated torsional angles. This allows to make instant judgment whether the generated conformations can reproduce an experimentally determined conformation.
hover over any rotatable bond in the molecule (marked with a circle)
Figure 3. Example of visualizing torsion flexibility with reference molecule
See also in OEChem TK manual¶
API
- OEAtomBondSet class
- OEBondGetSmallestRingSize function
- OEExponentColorGradient class
- OEGetTorsion function
- OEGroupBase class
- OEHasGroupType predicate
- OEIsRotor predicate
- OEUnaryBondPred class
See also in OEDepict TK manual¶
Theory
- Molecule Depiction chapter
- Generating Interactive SVG images chapter
API
- OE2DMolDisplay class
- OE2DMolDisplayOptions class
- OE2DPoint class
- OEAddInteractiveIcon function
- OEAddSVGHover function
- OEDrawLegendLayout function
- OEDrawSVGHoverText function
- OEDrawTextToCenter function
- OEFont class
- OEImage class
- OEImageFrame class
- OELegendLayout class
- OELegendLayoutOptions class
- OEPen class
- OERenderMolecule function
- OESVGAreaPen object
See also in GraphemeTM TK manual¶
API
- OEColorGradientDisplayOptions class
- OEColorGradientLabel class
- OEDrawColorGradient function
- OEPrepareDepictionFrom3D function