Batch Searching Button

Summary: This script is associated with a Query structure table. It reads in an SDF of query structures and runs a search for each one against a Markush structures table. Each query is inserted into the query table with a many to many relationship to the Markush structures table. This allows each query to be browsed in a form view to quickly look at results. The username, date, and query name is also inserted to the table for reference.

This button is used on the Markush demo data set, shown on the Queries form. The Queries table has a many to many relationship with the VMNS table (containing the structures for searching), and has the VMNS table as a child. This would be easy to adapt to any other system which could benefit from batch searching. All queries remain in the database with their relationship, meaning that results can be viewed and searched in groups that share a data base. If privacy is a concern, the script could be adapted to automatically export the results (using Export/Import Query Results Script as a guideline), and then clearing the table. In this case the Export/Import Query Results Script could be used to reimport the search results in a local database copy for analysis.

A more advanced option for keeping queries on a shared database private would be to take advantage of table visibility options associated with user-names, so that the query table is viewable only by one group or person.


/** Batch Searching of a Structure Table button, from the Query form
 *
 * @author Erin Bolstad ([email protected])
 * Jan 2012
 */

import javax.swing.SwingUtilities
import com.im.df.api.dml.*
import com.im.commons.progress.*
import com.im.df.api.chem.MarvinStructure
import chemaxon.formats.MolImporter
import chemaxon.struc.Molecule
import com.im.df.api.support.*
import com.im.df.api.util.DIFUtilities
import static com.im.df.query.JChemSearchConstants.*
import chemaxon.sss.search.JChemSearchOptions
import chemaxon.sss.SearchConstants
import chemaxon.sss.search.options.HomologyTranslationOption
import javax.swing.*
import java.awt.GridBagConstraints
import groovy.swing.SwingBuilder
import org.openide.NotifyDescriptor
import org.openide.DialogDisplayer

evaluate = { widget ->
    if (SwingUtilities.isEventDispatchThread()) {
        Thread.start() {
            evaluateImpl(widget)
        }
    } else {
        evaluateImpl(widget)
    }
}

evaluateImpl = { widget ->
    def rs = widget.form.resultSet
    def dataTree = rs.dataTree

    // Script assumes that table infrastructure is already set up with relationships, and script is on the Query Results table
    def queryEty = dataTree.rootVertex.entity
    def queryEdp = queryEty.schema.dataProvider.getEntityDataProvider(queryEty)
    def schema = queryEty.schema
    def queryVS = rs.rootVertexState
    def VMNSvertex = dataTree.rootVertex.edges.find { it.destination.entity.name == 'VMNS' }
    def VMNSety = VMNSvertex.destination.entity
    def VMNSfld = VMNSety.fields.items.find { it.name == 'Markush structure' }
    def VMNSedp = VMNSety.schema.dataProvider.getEntityDataProvider(VMNSety)

    def queryStrucFld = queryEty.fields.items.find { it.name == 'Query structure' }
    def queryIdFld = queryEty.fields.items.find { it.name == 'CdId' }
    def queryNameFld = queryEty.fields.items.find { it.name == 'Query Name' }
    def queryDateFld = queryEty.fields.items.find { it.name == 'Query Date' }
    def queryUserFld = queryEty.fields.items.find { it.name == 'User' }
    def queryHitsFld = queryEty.fields.items.find { it.name == 'Hits' }

    assert queryStrucFld != null
    assert queryIdFld != null
    assert queryNameFld != null
    assert queryDateFld != null
    assert queryUserFld != null
    assert queryHitsFld != null

    QUERYSTRUCFLD = queryStrucFld
    QUERYIDFLD = queryIdFld
    QUERYDATEFLD = queryDateFld
    QUERYUSERFLD = queryUserFld
    QUERYNAMEFLD = queryNameFld
    QUERYHITSFLD = queryHitsFld

    def userName = schema.getUsername()
    USERNAME = userName

    def timeStamp = new Date()
    TIMESTAMP = timeStamp

    rel = DIFUtilities.findUsagesInRelationships(queryEty)
    firstRel = rel.get(0)
    FIRSTREL = firstRel

    // Get name of the search
    def querySel = new SwingBuilder()
    querySel.setVariable('properties',[:])
    def vars = querySel.variables
    def frame = querySel.dialog(title:'Batch Query', modal:true) {
        panel () {
            gridBagLayout()
            label(text:"Enter query name:", constraints:gbc(
                    gridx:0,
                    gridy:0,
                    insets:[10,10,10,0]))
            textField(id:'newName', constraints:gbc(
                    gridx:1,
                    ipadx:200,
                    gridy:0,
                    fill:GridBagConstraints.HORIZONTAL,
                    insets:[10,5,10,10]))
            translation = buttonGroup()
            radioButton(id:'broadTrans', text:"Homology Broad Translation", buttonGroup:translation, selected:true, constraints:gbc(
                    gridx:0,
                    gridy:1,
                    gridwidth:2,
                    anchor:LINE_START))
            radioButton(id:'narrowTrans', text:"Homology Narrow Translation", buttonGroup:translation, constraints:gbc(
                    gridx:0,
                    gridy:2,
                    gridwidth:2,
                    anchor:LINE_START))
            button(id:'ok', label: "OK", constraints:gbc(
                    gridx:0,
                    gridy:3,
                    anchor:LINE_END,
                    insets:[10,0,10,0]),
                actionPerformed: {
                    vars.buttonResults = 'ok'
                    dispose()})
            button(id:'cancel', label: "Cancel", constraints:gbc(
                    gridx:1,
                    gridy:3,
                    anchor:LINE_START,
                    insets:[10,0,10,0]),
                actionPerformed: {
                    vars.buttonResults = 'quit'
                    dispose()})
        }
    }

    frame.pack()
    frame.setLocationRelativeTo(null)
    frame.show()

    def chosenAction = vars.buttonResults

    if (chosenAction == 'quit') {
        return
    }

    if (chosenAction == 'ok') {
        searchName = vars.newName.text
        homoGroup = (vars.broadTrans.selected ? 'Homology Broad Translation' : 'Homology Narrow Translation')
    }

    switch(homoGroup) {
        case "Homology Broad Translation":
        jcopts = new JChemSearchOptions(SearchConstants.SUBSTRUCTURE)
        jcopts.homologyBroadTranslation = HomologyTranslationOption.ALL
        break
        case "Homology Narrow Translation":
        jcopts = new JChemSearchOptions(SearchConstants.SUBSTRUCTURE)
        jcopts.homologyNarrowTranslation = HomologyTranslationOption.NONE
        break
    }
    JCOPTS = jcopts
    SEARCHNAME = searchName

    // Prompt for file of SDFs to search against
    def chooser = new JFileChooser()
    chooser.setDialogTitle('Select SDF containing the query molecules')
    if (chooser.showOpenDialog(null)==JFileChooser.APPROVE_OPTION) {
        File fileName = chooser.getSelectedFile()
        NAME = fileName.getCanonicalPath()
    } else {
        return
    }

    importer = new MolImporter(NAME)
    importer.grabbingEnabled = true
    mol = new Molecule()

    name = NAME
    queryNum = 1

    while (importer.read(mol)) {

        String molStr = importer.grabbedMoleculeString
        def queryMol = new MarvinStructure(mol)
        QUERYMOL = queryMol
        MOLPASS = mol

        def queryIDs = queryEdp.queryForIds(DFTermExpression.ALL_DATA, null, DFEnvironmentRO.DEV_NULL)

        def id = queryIDs.max() + 1
        ID = id

        // Build and execute substructure query
        def queryMsg = "Running query $queryNum"
        def envQuery = EnvUtils.createDefaultEnvironmentRO(queryMsg, true)

        try {
            jcopts = JCOPTS
            queryMol = QUERYMOL

            def q = DFTermsFactory.createFieldOperatorValueExpr(Operators.STRUCTURE_EXACT, VMNSfld, [(JCHEM_SEARCH_OPTIONS): jcopts], queryMol)
            List resultIds = VMNSedp.queryForIds(q, SortDirective.EMPTY, envQuery)
            RESULTIDS = resultIds
        } finally {
            envQuery?.feedback.finish()
        }

        List resultIds = RESULTIDS

        def lockRL = DIFUtilities.getLockable(queryEdp).obtainLock('Query')
        def envRL = EnvUtils.createDefaultEnvironmentRW(lockRL, 'Updating Relationship Data', true)

        try {
            id = ID
            resultIds = RESULTIDS
            firstRel = FIRSTREL

            // Everything inserted here
            mol = MOLPASS
            queryStrucFld = QUERYSTRUCFLD
            queryIdFld = QUERYIDFLD
            queryMol = QUERYMOL
            queryDateFld = QUERYDATEFLD
            queryUserFld = QUERYUSERFLD
            queryNameFld = QUERYNAMEFLD
            queryHitsFld = QUERYHITSFLD
            timeStamp = TIMESTAMP
            userName = USERNAME
            searchName = SEARCHNAME

            //Update the Query Results table
            def hitNum = resultIds.size()
            vals =[(queryStrucFld.id):queryMol]
            vals.putAt(queryIdFld.id, id)
            vals.putAt(queryDateFld.id, timeStamp)
            vals.putAt(queryUserFld.id, userName)
            vals.putAt(queryHitsFld.id, hitNum)
            vals.putAt(queryNameFld.id, searchName)
            queryEdp.insert(vals, null, envRL)

            if (resultIds.isEmpty() == false) {
                resultIds.each { hit ->
                    def x = id
                    def y = hit
                    DIFUtilities.connectRelationalData(firstRel.forward, x, y, envRL)
                }
            }
        } finally {
            lockRL?.release()
            envRL?.feedback.finish()
        }
        
        queryNum++
    }
    importer.close()

    def message = "Batch searching done! To view the new queries, please go to the Query Grid View, and select 'Show All' when in query mode (click Query at the upper left corner of the form)"
    NotifyDescriptor d = new NotifyDescriptor.Message(message)
    DialogDisplayer.getDefault().notify(d)
}

Versions: This script has been tested on IJC versions 6.0



Copyright © 1999-2012 ChemAxon Ltd.    All rights reserved.