Skip to content

Commit 9d6b030

Browse files
committed
Merge branch 'drawing'
This fixes a bunch of stuff in molecule drawing, especially for explicit/implicit hydrogens.
2 parents 753455b + a2f11cd commit 9d6b030

3 files changed

Lines changed: 53 additions & 12 deletions

File tree

rmgpy/molecule.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ cdef class Molecule(Graph):
104104

105105
cpdef Graph copy(self, bint deep=?)
106106

107+
cpdef deleteHydrogens(self)
108+
107109
cpdef makeHydrogensImplicit(self)
108110

109111
cpdef makeHydrogensExplicit(self)

rmgpy/molecule.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,32 @@ def split(self):
594594
molecules.append(molecule)
595595
return molecules
596596

597+
def deleteHydrogens(self):
598+
"""
599+
Irreversibly delete all non-labeled hydrogens, without incrementing
600+
the "implicitHydrogens" count of the neighbouring atom, or updating
601+
Connectivity Values or the implicitHydrogens flag. If there's nothing
602+
but Hydrogens, it does nothing.
603+
It destroys information; be careful with it.
604+
"""
605+
cython.declare(atom=Atom, neighbor=Atom, hydrogens=list)
606+
# Check that the structure contains at least one heavy atom
607+
for atom in self.vertices:
608+
if not atom.isHydrogen():
609+
break
610+
else:
611+
# No heavy atoms, so leave explicit
612+
return
613+
hydrogens = []
614+
for atom in self.vertices:
615+
if atom.isHydrogen() and atom.label == '':
616+
neighbor = self.edges[atom].keys()[0]
617+
hydrogens.append(atom)
618+
# Remove the hydrogen atoms from the structure
619+
for atom in hydrogens:
620+
self.removeAtom(atom)
621+
622+
597623
def makeHydrogensImplicit(self):
598624
"""
599625
Convert all explicitly stored hydrogen atoms to be stored implicitly,

rmgpy/molecule_draw.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,10 @@ def findBackbone(chemGraph, ringSystems):
577577
chemGraph = chemGraph.copy()
578578

579579
# Remove hydrogen atoms from consideration, as they cannot be part of
580-
# the backbone
581-
chemGraph.makeHydrogensImplicit()
580+
# the backbone.
581+
# Do this irreversibly, because we have a copy and we don't want to change
582+
# the implicitHydrogen count of the other atoms.
583+
chemGraph.deleteHydrogens()
582584

583585
# If there are only one or two atoms remaining, these are the backbone
584586
if len(chemGraph.atoms) == 1 or len(chemGraph.atoms) == 2:
@@ -1132,32 +1134,45 @@ def drawMolecule(molecule, path=None, surface=''):
11321134
print 'Cairo not found; molecule will not be drawn.'
11331135
return
11341136

1135-
# This algorithm requires that the hydrogen atoms be implicit
1136-
implicitH = molecule.implicitHydrogens
1137-
molecule.makeHydrogensImplicit()
1137+
# This algorithm now works with explicit hydrogen atoms on the molecule.
1138+
# Please ensure all the subroutines do also.
1139+
# We will delete them from the *copied* list of atoms, and store them here:
1140+
implicitHydrogensToDraw = {}
1141+
for atom in molecule.atoms:
1142+
implicitHydrogensToDraw[atom] = atom.implicitHydrogens
11381143

11391144
atoms = molecule.atoms[:]
1140-
bonds = molecule.bonds.copy()
1145+
# bonds = molecule.bonds.copy() is too shallow for a dict-of-dicts,
1146+
# so we loop one level deep and copy the inner dicts.
1147+
bonds = dict()
1148+
for atom1,atom2dict in molecule.bonds.iteritems():
1149+
bonds[atom1] = atom2dict.copy()
1150+
11411151
cycles = molecule.getSmallestSetOfSmallestRings()
11421152

11431153
# Special cases: H, H2, anything with one heavy atom
11441154

1145-
# Remove all unlabeled hydrogen atoms from the molecule, as they are not drawn
1155+
# Remove all unlabeled hydrogen atoms from the copied atoms and bonds, as they are not drawn
11461156
# However, if this would remove all atoms, then don't remove any
11471157
atomsToRemove = []
11481158
for atom in atoms:
11491159
if atom.isHydrogen() and atom.label == '': atomsToRemove.append(atom)
11501160
if len(atomsToRemove) < len(atoms):
11511161
for atom in atomsToRemove:
11521162
atoms.remove(atom)
1153-
for atom2 in bonds[atom]: del bonds[atom2][atom]
1163+
for atom2 in bonds[atom]:
1164+
del bonds[atom2][atom]
1165+
implicitHydrogensToDraw[atom2] = implicitHydrogensToDraw[atom2] + 1
11541166
del bonds[atom]
11551167

11561168
# Generate the coordinates to use to draw the molecule
11571169
try:
11581170
coordinates = generateCoordinates(molecule, atoms, bonds, cycles)
11591171
except (ValueError, LinAlgError), e:
11601172
logging.error('Error while drawing molecule {0}: {1}'.format(molecule.toSMILES(), e))
1173+
import sys, traceback
1174+
exc_type, exc_value, exc_traceback = sys.exc_info()
1175+
traceback.print_exc()
11611176
return None, None, None
11621177

11631178
coordinates[:,1] *= -1
@@ -1181,8 +1196,8 @@ def drawMolecule(molecule, path=None, surface=''):
11811196
# Add implicit hydrogens
11821197
for i in range(len(symbols)):
11831198
if symbols[i] != '':
1184-
if atoms[i].implicitHydrogens == 1: symbols[i] = symbols[i] + 'H'
1185-
elif atoms[i].implicitHydrogens > 1: symbols[i] = symbols[i] + 'H{0:d}'.format(atoms[i].implicitHydrogens)
1199+
if implicitHydrogensToDraw.get(atoms[i],0) == 1: symbols[i] = symbols[i] + 'H'
1200+
elif implicitHydrogensToDraw.get(atoms[i],0) > 1: symbols[i] = symbols[i] + 'H{0:d}'.format(implicitHydrogensToDraw[atoms[i]])
11861201

11871202
# Special case: H2 (render as H2 and not H-H)
11881203
if symbols == ['H','H']:
@@ -1218,8 +1233,6 @@ def drawMolecule(molecule, path=None, surface=''):
12181233
else:
12191234
surface.finish()
12201235

1221-
if not implicitH: molecule.makeHydrogensExplicit()
1222-
12231236
return surface, cr, (0, 0, width, height)
12241237

12251238
################################################################################

0 commit comments

Comments
 (0)