Macs in Chemistry

Insanely great science

 

Scripting Vortex 14

In tutorial 4 we looked at using the command line tool sddesc from Chemical Computing Group to calculate a number of molecular descriptors and then import them into Vortex. However there a couple of issues with doing this not the least ensuring all the environment variables are set correctly. An alternative is to use MOE as a web service and access the tools using the SOAP protocol (Simple Object Access Protocol). This protocol provides a specification for exchanging structured information in the implementation of Web Services in computer networks. It relies on XML Information Set for its message format.

The MOE Web Server

You can start the MOE web server using the following command in a Terminal window

prompt$ /Applications/moe2012/bin/moeweb

You should get a list of information including the IP address of the server and the port you need to address (usually port 8888)

You should also get a list of very useful web pages

YellowPages results now available:
    (1): [soap] DataTypes
    (2): [soap] DepictionLayout
    (3): [soap] MedChemProps
    (4): [soap] MolToSMILES
    (5): [soap] SMILESToMol
    (6): [soap] Version

If you now open a web browser and go to

http://localhost:8888/soap.html

You will get a web page giving a list of the available functions.

soap1

If like me you are not particularly familiar with constructing SOAP queries then these pages are invaluable. Select the SMILESToMol hyperlink and you should get the page below. Fill in a valid SMILES string and click on the “Preview SOAP Request” button and you can see the syntax of the expected SOAP request and this is what we will be included in the Vortex script as the SOAP request.

soap2

The MolToSMILES script

To start with I thought I’d create a script that retrieves the SMILES string from the web server, mainly because it avoids the complication of trying to parse the returned XML if there are multiple properties. We do however need to import an XML parsing library. The Element type is a flexible container object, designed to store hierarchical data structures in memory. The type can be described as a cross between a list and a dictionary, XML is an inherently hierarchical data format, and the most natural way to represent it is with a tree.

import xml.etree.ElementTree as ET

The first part just allows the user to confirm that they are not posting proprietary information to an external web service. We then get the structure as a MOL file.

mymol = vortex.getMolProperty(mfm.getMolFileAtRow(r), 'MOL')

Then we construct the SOAP request, we need the URL we are posting to and the data wrapped in the SOAP request format taken from the appropriate MOE SOAP function web page.

We then perform the request

request = urllib2.Request(url, data, headers=headers)
contents = urllib2.urlopen(request).read()

We then need to create a column in Vortex, and then parse the data, since there is only the SMILES string returned this is fairly straight-forward with help from Matt. The XML response from the MOE server is parsed using the python ElementTree module. This module parses an XML string using ET.fromstring() into a hierarchical tree data structure that allows us to easily pick out various values in the response. In this case, the desired value is just the text within a tag named "smiles", which can be found using a relatively simple XPath query:

   mysmiles = root.find('.//smiles')

This query recursively searches through the tree and returns the first element with the tag "smiles" that it finds. The text contents of that element is given by mysmiles.text

# Using MOE via a web service this uses a local copy of MOE
    # 

import sys
import com.dotmatics.vortex.util.Util as Util

if Util.getPlatform() == Util.PlatformIsWindows:
 sys.path.append(vortex.getVortexFolder() + '\\modules\\jythonconsole')
 sys.path.append(vortex.getVortexFolder() + '\\modules\\jythonlib')
else:
sys.path.append(vortex.getVortexFolder() + '/modules/jythonconsole')
sys.path.append(vortex.getVortexFolder() + '/modules/jythonlib')

import urllib2
import urllib
import xml.etree.ElementTree as ET

content = javax.swing.JPanel()

label = javax.swing.JLabel("<html><b>Make sure this uses a local web service</b><p><br>If you don't want to post your data to the internet press Cancel.</html>")

layout.fill(content, label, 2, 2)



ret = vortex.showInDialog(content, "MOE Web Service")

if ret == vortex.OK:

 mfm = vtable.getMolFileManager()
rows = vtable.getRealRowCount()
for r in range(0, rows):
    mymol = vortex.getMolProperty(mfm.getMolFileAtRow(r), 'MOL')


    url ='http://yourserver.local:8888/soap/MolToSMILES'

    data = '''<?xml version="1.0"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
    <InputType>
    <molecule><![CDATA[%s]]></molecule>
    </InputType>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>''' % mymol

    headers = {
    'Content-Type': 'text/html',
    'Content-Length': len(data)
    }

    request = urllib2.Request(url, data, headers=headers)
    contents = urllib2.urlopen(request).read()

# Create new columns in table if needed

    column = vtable.findColumnWithName('SMILES', 1, 3)
    vtable.fireTableStructureChanged()

# Parse response

    root = ET.fromstring(contents)
    if root.tag == 'error':
        print 'Error from MOE server:'
        print root.text
    else:

        mysmiles = root.find('.//smiles')

    if mysmiles is not None:
        column = vtable.findColumnWithName('SMILES', 1, 3)
        column.setValueFromString(r, mysmiles.text)
        print mysmiles.text
    else:
            print 'Could not parse response:'
            print contents


vtable.fireTableStructureChanged()

The result of running this script is a new column called SMILES, and because Vortex is smart enough to realise what the contents are the SMILES strings get automatically rendered as 2D images.

mol2smiles

You can download the script from here MOESoapMolToSmiles.vpy.zip

The MolToMedChemProps Script

The first part of the script is very similar, with the url amended and the a slightly modified SOAP request (taken from the appropriate MOE web page), the real difference is the parsing on the returned XML data. As before, the XML string is parsed into a tree using ET.fromstring(), but in this case there are multiple values to extract. Instead of using XPath queries for the tag names of each property, it is possible to traverse the XML tree and extract the values without necessarily knowing exactly which properties are present. The response consists of a root element named "Envelope", which contains an element named "Body" , which contains an element named "MedChemPropsOutputType", which in turn contains all the properties:

<Envelope>
    <Body>
        <MedChemPropsOutputType>
        <MW moesoaptype="real">396.53099155426025</MW>
        <MF moesoaptype="string">C24 H32 N2 O3</MF>
        <charge moesoaptype="int">0</charge>
        <logP moesoaptype="real">4.945400000000005</logP>
        ...
        </MedChemPropsOutputType>
    </Body>
</Envelope>

It is possible to iterate over the children of each element as if the element was a python list. As "Body" is the first child of "Envelope", and "MedChemPropsOutputType" is the first child of "Body", we can simply use root[0][0]. We can then iterate over each of the child property elements with a for loop, using prop.tag for the column heading, prop.attrib['moesoaptype'] for the data type, and prop.text for the value itself.

# Using MOE via a web service this uses a local copy of MOE
# 

import sys
import com.dotmatics.vortex.util.Util as Util

if Util.getPlatform() == Util.PlatformIsWindows:
sys.path.append(vortex.getVortexFolder() + '\\modules\\jythonconsole')
sys.path.append(vortex.getVortexFolder() + '\\modules\\jythonlib')
else:
sys.path.append(vortex.getVortexFolder() + '/modules/jythonconsole')
sys.path.append(vortex.getVortexFolder() + '/modules/jythonlib')

import urllib2
import urllib
import xml.etree.ElementTree as ET


content = javax.swing.JPanel()

label = javax.swing.JLabel("<html><b>Make sure this uses a local web service</b><p>.<br>If you don't want to post your data to the internet press Cancel.</html>")

layout.fill(content, label, 2, 2)

ret = vortex.showInDialog(content, "MOE Web Service")

if ret == vortex.OK:

mfm = vtable.getMolFileManager()
rows = vtable.getRealRowCount()
for r in range(0, rows):
    mymol = vortex.getMolProperty(mfm.getMolFileAtRow(r), 'MOL')


    url ='http://yourserver.local:8888/soap/MedChemProps'

    data = '''<?xml version="1.0"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
    <InputType>
    <molecule><![CDATA[%s]]></molecule>
    <wash>false</wash>
    </InputType>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>''' % mymol

    headers = {
    'Content-Type': 'text/html',
    'Content-Length': len(data)
    }

    request = urllib2.Request(url, data, headers=headers)
    contents = urllib2.urlopen(request).read()

# Create new columns in table if needed
    root = ET.fromstring(contents)
    for prop in root[0][0]:
            datatype = vortex.STRING
            if prop.attrib['moesoaptype'] == 'int':
                    datatype = vortex.INT
            elif prop.attrib['moesoaptype'] == 'real':
                    datatype = vortex.DOUBLE
            column = vtable.findColumnWithName(prop.tag, 1, datatype)
            column.setValueFromString(r, prop.text)
vtable.fireTableStructureChanged()

The result of running the script is shown below

moesoap4

You can download the script here MOESoapMedChemProps.vpy.zip

Last Updated 20 Sept 2013