I would like to create a ChemDraw .cdx file from an InChI with Python.
This answer gives a solution for cdx --> InChI.
The minimal example below cdx_to_inchi works fine, but
I could not figure out how I can get inchi_to_cdx to work.
import comtypes.client as w32
def cdx_to_inchi(cdx):
ChemDraw = w32.CreateObject("ChemDraw.Application")
ChemDraw.Visible = False
Compound = ChemDraw.Documents.Open(cdx) # opens existing file
inchi = Compound.Objects.Data("chemical/x-inchi")
print(inchi)
ChemDraw.Quit()
def inchi_to_cdx(inchi):
ChemDraw = w32.CreateObject("ChemDraw.Application")
ChemDraw.Visible = False
Compound = ChemDraw.Documents.Open("Emtpy.cdx") # opens existing file
# ChemDraw.Documents.New("NewFile.cdx") # How to create a new file?
# Compound.Objects.SetData(inchi) # How to paste InChi data?
# ChemDraw.Documents.Save() # How to save?
# ChemDraw.Documents.SaveAs("MyMolecule.cdx") # How to save under different name?
ChemDraw.Quit()
cdx = r'C:\Data\Test.cdx'
inchi = '1S/C6H6/c1-2-4-6-5-3-1/h1-6H'
cdx_to_inchi(cdx)
inchi_to_cdx(inchi)
解决方案
The following is at least a somehow working solution. It basically "mimics" a human user with keypresses. It is adapted from here. The drawbacks are:
it seems to be Windows specific
ChemDraw has to be the active application, i.e. will not work in the background
additional delays slow down the whole procedure. a few 10'000 molecules would take about a day (well, better than by hand ;-)
These questions remain:
How to make it platform independent?
How to let it work in the background?
How to avoid additional delays or how short can the delays be made that it still works reliably?
Code:
### create a ChemDraw .cdx file from an InChI string
import win32com.client as win32
import win32clipboard
import time
def sleep():
time.sleep(0.5) # wait for 0.5 seconds that script is not too fast for ChemDraw
def sleep_short():
time.sleep(0.25) # wait for 0.25 seconds between key presses
# initialize windows shell (so we can send keyboard commands)
shell = win32.Dispatch("WScript.Shell")
def hit_keys(keys): # function to wait, then send a keypress signal
sleep_short()
shell.SendKeys(keys,1)
# initialize ChemDraw
chemdraw = win32.gencache.EnsureDispatch('ChemDraw.Application') # connect to ChemDraw
chemdraw.Visible = True # window needs to be visible otherwise keypresses will not work
sleep()
doc = chemdraw.Documents.Add() # create a new document
doc.Activate()
sleep()
# ChemDraw must be the active application, so it can receive keyboard commands
shell.AppActivate("ChemDraw Prime") # name of the ChemDraw window bar
sleep()
inchi = 'InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H'
# set clipboard data
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(inchi)
win32clipboard.CloseClipboard()
sleep() # not sure whether a delay is needed here
hit_keys("%e") # edit
hit_keys("s") # paste special
hit_keys("i") # pase as inchi
sleep()
ffname = r'C:\Users\Test\Scripts\MyMolecule.cdx' # full filename
doc.SaveAs(ffname) # save the file
doc.Close()
chemdraw.Quit() # close ChemDraw
### end of code