{info} 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 (ebolstad@chemaxon.com)
* 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)
}