Code class: Utilizing event hooks in Instant JChem for drill-down and data pivots

news · 8 years ago
by Erin Bolstad

One of the most common needs for analyzing biological data in relation to chemical structures is to be able to “drill down” through a summarized or minimal table, in order to get all of the underlying biological data. Our example is based around the Wombat data set included with Instant JChem (when making a local database with demo data). Under the ‘Wombat (compound view)’ data tree, you will see a form labelled ‘Wombat (compound view)’. This form contains selected activity data for each compound - The type of assay, the target, value, and species/tissue. However, the child table WOMBAT.ACT.LIST has extensive data on each assay: min and max values, SwissProt ID, receptor family, the radioligand of binding, nonspecific binding, and so on. While this is too much data to present in the simplified form, this data would be good to have on hand, and easily accessible. This is where the drill-down script comes in. Of course if you were using this you might use a completely different approach for obtaining the drill down data, such as retrieving it from an external database or web service.

Drill-down pop-up in the Wombat (Compounds View) form

In IJC 5.11, event hooks were introduced. This is the ability to add a Groovy script to an action. Currently only double clicks are supported in form view and grid view, but there are several other actions planned. The event hook script discussed here will open a window (containing a JEditorPane) with an html table containing all the drilled-down data for the double-clicked cell, in a pivoted fashion. The code is installed into the ‘Code’ section for the table widget.

To follow this example, you should download the full code text from here:

Now let’s walk through some interesting parts:

[java firstline="18"]CHILD = 'WOMBAT.ACT.LIST'[/java]

The child table is hard-coded in this case. However, you could easily get the entity at the destination of edge (in single child cases), or even cycle through child entities until you find one with some distinguishing feature (perhaps a field name with ‘assay’ in it).

[java firstline="27"]def removeArray = ['ID', 'WOMBAT_ACT_LIST_ID', 'Wombat structures ID'] def childFields = childEty.getFields().getItems().findAll { !removeArray.contains( }[/java]

The activity table has a few columns we don’t want to include in our pivot table. These are the ‘ID’, ‘WOMBAT_ACT_LIST_ID’, and ‘Wombat structures ID’ fields - they are placed in an array called removeArray. Since we need to get the data from these fields for our pop-up, we need to correctly identify them with their DFField name. Line 27 builds the array of all fields in the activities table. Then we need to remove the undesired fields from the array, but first we need their proper DFField name. Line 28 is a single call that does several things: the findAll() command finds all the fields (.getFields().getItems()) that match the closure condition - in this case, where the field name does not contain the names in the removeArray. We now have an array of fields that we wish to display in our drill-down popup.

The variable selRow is the selected row ID of the child table, called by getting the row from the vertex state that corresponds to the row in the widget (event.widget.vertexState.selectedRowsIds)

The method getTableVals is now called, passing in the vertex state, the selected row ID, and the array of fields we wish to display. This method is defined at the bottom of the script:

[java firstline="53"] def getTableVals(def edgeVS, def selRow, def childFields) { def tableData = [] childFields.each { n -> // For each field we want to display... def fieldData = edgeVS.getData([selRow[0]], DFEnvironmentRO.DEV_NULL) def insertVal = fieldData[selRow[0]][] tableData.add([, insertVal]) } return tableData } [/java]

This method builds an array with the name of the field, and the corresponding value from the child table. The array being built (tableData) is created by iterating through the array of desired fields (childFields), and getting the data from the child table for the selected row (lines 3 - 7). With the data for each field, the key and value are added to the tableData array as [name of field, value of field] (line 6).

Back in the main script, the next line calls the showData method, which actually creates the popUp:

[java firstline="36"] void showData(def selRow, def tableData, def childFields) { // Launch panel to show option of JEditor Pane or launching google in browser JEditorPane jep = new JEditorPane() jep.contentType = 'text/html' jep.text = realContent(selRow, tableData, childFields) // jep.preferredSize = new Dimension(500, 1000) Insets insets = new Insets(10, 10, 10, 10) jep.setMargin(insets) jep.editable = false // this is ugly, but seems the only way to get dialog with only OK button DialogDescriptor dd = new DialogDescriptor(jep, "Web search", false, [DialogDescriptor.OK_OPTION] as Object[], DialogDescriptor.OK_OPTION, DialogDescriptor.DEFAULT_ALIGN, null, null) // show the dialog DialogDisplayer.getDefault().notifyLater(dd) } [/java]

This method creates a JEditorPane popup, to display the drill-down data. In this case, we declare that we’re passing in html (line 39), and then defining the text with a call to the realContent method. This is discussed later, but let’s finish up with the popUp. The details of JEditorPane are worth exploring, as it has many options for use. Here we set some margins, and declare it uneditable. We then launch the popup with the DialogDisplayer class and the notiftylater(dd) method. This is a bit ugly, but currently the only way to get this to popup with only an ‘OK’ button. We may find better methods in the future.

The realContent method called here creates a string of html to be displayed, as defined below. This looks a bit scary, but is pretty handy:

[java firstline="64"] String realContent(def selRow, def tableData, def childFields) { StringWriter writer = new StringWriter() def buildWin = new MarkupBuilder(writer) buildWin.html{ body { h1 "Assay Data Drill Down" br() table(border:1, cellPadding:3) { tr { th("Wombat ID") selRow.each { t -> th(t) } } tableData.each { k, v -> tr{td(k) td(v)}}} p { mkp.yieldUnescaped "©" mkp.yield " 2012 Synergistic Cloud Paradigms Inc." }}} return writer.toString() } [/java]

This method uses another Groovy specific trick, MarkupBuilder. This is a class that allows for easy building of XML and HTML pages within Groovy. We create a new page by creating a new MarkupBuilder object (line 66), and then using MarkupBuilder’s language to build the buildWin.html page. MarkupBuilder is pretty straight-forward, building paragraphs and tables with intuitive calls. To build our pivot table, we populate the first row with “Wombat ID” and then the ID itself (lines 73 to 75). From here out we cycle through the array of field names and values with tableData.each, creating a new row with the name and value in sequential cells (td(k), td(v)) (lines 78 to 80). At this point, the string of html is complete, and passed back to the main script to be inserted into the popup.

This script has several snippets that can be reused elsewhere, or expanded for greater functionality. We hope to expand more on it in the future.