Ran into the need of saving my molecules in 2D (ChemDraw-like) format. I was wondering if Avogadro2 can do this?
Openbabel could «flatten» 3D structures for you, too. See, for example
obabel -:"CCOCC" --gen3d -h -O ether_3d.xyz
for a structure which is 3D; however you can use this (here: intermediate) result for a subsequent
obabel ether_3d.xyz --gen2d -O ether_2d.xyz
with all coordinates in z equal to zero.
(The export of flat/2D structures into .mol/.sdf is not unique to ChemDraw. The absolute configuration equally can be described by e.g., a CFG=2 in the atom block.)
Yeah, you can also export to .mol or .sdf or CDXML to read in ChemDraw.
But my suggestion is to Copy As => SMILES and then paste that into ChemDraw or another program to make sure it depicts in a “standard” depiction.
I’ll also be adding in an RDKit package, which would include a “export to SVG” using RDKit’s excellent depiction code.
Thank you both for your suggestions, they prompted me to investigate openbabel’s svg saving capabilities and with a simple piece of code I can incorporate it into my workflow.
import pybel
def save_SVG(your_xyz_string, directory = './'):
mol = pybel.readstring("xyz", your_xyz_string)
SVG_options = {'d' : False, # Supress printing of name
'u' : False} # Color in black
#mol.removeh() # Activate if you wish to remove hydrogens
with open('{}{}.svg'.format(directory, "your_file"), "w") as SVG_file:
SVG_file.write(mol.write(format = 'svg', opt = SVG_options))
This way I can bypass ChemDraw altogether ![]()
@Juanes If your workflow were about automated documentation/report generation with openbabel’s .svg, then maybe chemobabel is interesting for you.
My suggestion honestly, is to use RDKit, e.g.
mol = Chem.MolFromXYZBlock(your_xyz_string)
rdDetermineBonds.DetermineConnectivity(mol)
rdDetermineBonds.DetermineBondOrders(mol)
# and finally the stereochemistry
Chem.AssignStereochemistryFrom3D(mol)
d2d = rdMolDraw2D.MolDraw2DSVG(256,256,-1,-1,True)
opts = d2d.drawOptions()
# change options if you want
d2d.DrawMolecule(mol)
d2d.FinishDrawing()
svg = d2d.GetDrawingText()
There are a few other open source packages for 2D depiction, but IMHO RDKit’s is the best and most polished.
https://greglandrum.github.io/rdkit-blog/index.html#category=drawing
I managed to do exactly what I needed with RDKit. Read in a large number of .xyz files, set certain atoms as arbitrary functional groups, and save them in 2D format in a standard format. Here’s the code in case anyone finds it useful:
from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit.Chem import rdDetermineBonds
from rdkit.Chem.Draw import rdMolDraw2D
def save_svg(xyz_string, directory = './', substitutions = []):
# Create RDKit Mol object
raw_mol = Chem.MolFromXYZBlock(xyz_string)
mol = Chem.Mol(raw_mol)
rdDetermineBonds.DetermineBonds(mol, charge = 0)
# Change atoms in SUBSTITUTIONS to R_1, R_2, ...
idx_label = 1
for s in substitutions:
s_atom = mol.GetAtomWithIdx(s - 1)
s_atom.SetAtomicNum(0)
s_atom.SetProp('atomLabel', r'R<sub>{}</sub>'.format(idx_label))
idx_label += 1
AllChem.Compute2DCoords(mol)
# Optional: remove hydrogens for cleaner images
mol = Chem.RemoveHs(mol)
# Generate the SVG string. (-1, -1) sets up an image of dynamic size.
# This way the size of the molecules is consistent
drawer = rdMolDraw2D.MolDraw2DSVG(-1, -1)
# Draw the molecule in ACS 1996 format.
rdMolDraw2D.DrawMoleculeACS1996(drawer, mol)
drawer.FinishDrawing()
# Generate data and save
svg_data = drawer.GetDrawingText()
# Optional: Make background transparent by removing the white rectangle definition
svg_data = svg_data.replace('fill:#FFFFFF', 'fill:none')
with open('{}{}.svg'.format(directory, xyz_string.split('\n')[1].split('.')[0]), "w") as SVG_file:
SVG_file.write(svg_data)
coronene_xyz = '''36
coronene. Charge: 0 Multiplicity: 1
C -2.814239 -2.433172 0.000525
C -3.513376 -1.223602 0.002701
C -0.697550 -3.653345 -0.002618
C 0.698759 -3.652519 -0.001820
C -3.513586 1.223537 0.000527
C -2.814145 2.433955 -0.002756
C 2.812425 -2.431717 -0.000080
C 3.510775 -1.222823 -0.000368
C -0.693728 3.655328 -0.002757
C 3.513380 1.217812 -0.000093
C 0.703619 3.653094 0.000099
C 2.817285 2.428028 0.001718
C -1.413713 -2.448903 -0.000374
C -2.828768 0.000371 0.001923
C 1.411873 -2.447319 -0.000016
C -1.412347 2.451259 -0.001785
C 2.825145 -0.001786 0.000107
C 1.415885 2.447462 0.001370
C -0.709153 -1.223993 0.000860
C -1.416107 0.001258 0.001239
C 0.704852 -1.223993 0.000716
C -0.708427 1.226774 0.000442
C 1.412492 0.000086 0.000957
C 0.706772 1.225249 0.000733
H -3.375091 -3.365350 -0.000588
H -4.600904 -1.247566 0.003981
H -1.221003 -4.606899 -0.005194
H 1.225395 -4.604113 -0.003085
H -4.601016 1.245985 0.001760
H -3.376485 3.364890 -0.006057
H 3.374359 -3.362811 -0.000380
H 4.598225 -1.244815 -0.001362
H -1.215405 4.609787 -0.005562
H 4.600919 1.236595 -0.002001
H 1.231371 4.604264 0.000723
H 3.381985 3.357602 0.002887'''
coronene_substitutions = [25, 26]
save_svg(coronene_xyz, './', coronene_substitutions)
save_svg(DPTTA_xyz, './', DPTTA_substitutions)
@Thomas, yes! I am indeed trying to document the many molecules I am generating in my project automatically. chemobabel looks very interesting and useful and will use it, if not for this workflow / project, at some point certainly.
Once again, thank you both for your suggestions.