Background

Although not being documented yet, making plugins for the biocep workbench is easy (well if you are familiar with Swing). This tutorial presents the making of a really simple plugin, although not using swing directly for the user interface but using jaxx to generate the appropriate verbose swing code. JAXX is a way to make swing user interfaces using XML tags to describe the user interface structure. This article will get you started on the concept of jaxx.

The application

The application we are demonstrating here is really simple and may not be useful beyond getting started at making other plugins for biocep. It will add a single view into the workbench allowing to retrieve data from yahoo finance using the function get.hist.quote from the beginning of a year to today, and display the result in a graphical device. This will look something like that:

Screenshot.png

Structure of the plugin

A workbench plugin is more or less just any java class that takes an RGui interface and does something with it. Here is how I've structured the plugin so that I can build and install using ant.

$ tree
.
|-- build.properties
|-- build.xml
|-- descriptor.xml
|-- lib
|   |-- dt.jar
|   |-- jaxx-runtime.jar
|   |-- jaxx-swing.jar
|   `-- jaxxc.jar
`-- src
    `-- com
        `-- addictedtor
            `-- workbench
                `-- plugin
                    `-- simple
                        |-- SimplePlugin.jaxx
                        `-- SimplePlugin.jaxxscript
7 directories, 10 files

build.properties

The build.properties file contains some properties to describe to ant where the workbench is installed and where we should install the plugin. Here is how it looks on my system:

install.dir=/home/romain/RWorkbench/plugins
biocep.dir=/opt/biocep
biocep.jar=biocep.jar

The build.xml file

The build.xml is a standard ant build file with a set of targets to compile the plugin, create a zip for distribution and install the plugin in the installation directory (as indicated in the build.properties file). Let's take a look at the steps specifically involving jaxx. To compile jaxx files in ant, you need to define an additional ant task

24   <target name="defineAntTask">
25     <taskdef name="jaxxc" classname="jaxx.JaxxcAntTask" 
26       classpath="lib/jaxxc.jar"/>
27   </target>

and then use this task to compile the jaxx files in your source tree, here we are compiling the SimplePlugin.jaxx file. After that, classes have been generated and you may compile the java files using the standard javac ant task.

31   <target name="compile" depends="clean,defineAntTask">
32     <mkdir dir="build/classes"/>
33     <jaxxc srcdir="src" keepJavaFiles='yes' 
34       destdir="build/classes" classpath="${full.biocep.jar}" />
35     <javac srcdir="src" destdir="build/classes" source="1.5" target="1.5" > 
36       <classpath refid="simple.class.path"/>
37     </javac>
38   </target>

Finally, we can make the jar file. I usually prefer one jar file per biocep plugin, so I unjar the content of the jaxx runtime classes to jar it back into a single jar file

42   <target name="build" depends="compile">
43     <mkdir dir="build/lib"/>
44     <unjar src="lib/jaxx-runtime.jar" dest="build/classes" />
45     <jar jarfile="build/lib/simple.jar">
46       <fileset dir="build/classes" />
47       <fileset dir="src">
48         <include name="*.xml" />
49         <include name="**/*.props" />
50         <include name="**/*.properties" />
51         <include name="**/*.html" />
52         <include name="**/*.gif" />
53         <include name="**/*.png" />
54       </fileset>
55     </jar>  
56   </target>

The descriptor.xml file

The descriptor.xml file is used by the workbench to load the plugin, it identifies the plugin main class

   1 <plugin>  
   2   <view name="Simple Plugin" 
   3     class="com.addictedtor.workbench.plugin.simple.SimplePlugin" />
   4 </plugin>

We are pointing the workbench to the class com.addictedtor.workbench.plugin.simple.SimplePlugin and the workbench will instanciate one object of the class using the constructor that takes an RGui interface, through which we will communicate with R.

The SimplePlugin.* files

The SimplePlugin.jaxx file contains the description of the user interface using XML and the SimplePlugin.jaxxscript file contains java code to implement some of the logic of the application

If you are already familiar with Swing, it does not take too much effort to grab what is going on with this jaxx file

   1 <JPanel layout="{new BorderLayout()}">
   2     
   3     <script source="SimplePlugin.jaxxscript" />
   4     
   5     <JPanel constraints="BorderLayout.NORTH" id="toolbar">
   6         <JComboBox id ="instruments" >
   7             <item value='{null}' 
   8                 label='Select an instrument'/>
   9             <item value='Nasdaq'   />
  10             <item value='Dow'      />
  11             <item value='SP 500'   />
  12             <item value='CAC 40'   />
  13             <item value='FTSE 100' />
  14             <item value='DAX'      />
  15         </JComboBox>
  16         <JLabel text="start year :" />
  17         <JTextField id="startyear" text="2003" 
  18             onActionPerformed='go()' />
  19         <JButton id="submit" text="go" 
  20             onActionPerformed='go()' />
  21         
  22     </JPanel>
  23     
  24     <JScrollPane constraints="BorderLayout.CENTER">
  25         <org.kchine.r.workbench.views.PDFPanel id = "pdf" />
  26     </JScrollPane>
  27     
  28     <JPanel constraints="BorderLayout.SOUTH" id="statusbar">
  29       <JLabel id="info"  text = " " />
  30     </JPanel>
  31     
  32 </JPanel>
  33 

The SimplePlugin.jaxx file complements the jaxx code by implementing a set of java methods, including the constructor for the class which needs to take an RGui interface as its only parameter

 8 public SimplePlugin( RGui rgui){
 9     this.rgui = rgui ;
10     initMap( ) ;
11     loadRPackage( "tseries" ); 
12 }
13 

... a simple utility method to load an R package. We can see here of of the main design decision about the RGui interface, the instance of R that is running on the background may only do one thing at a time, which is why when you want to do something with it, you need to lock it, do whatever, and then unlock it

14 public void loadRPackage( String pack ){
15     try{
16         rgui.getRLock().lock() ;
17         rgui.getR().evaluate( "require( 'tseries' )" ) ;
18     } catch(Exception e) {
19         JOptionPane.showMessageDialog(this, 
20             "Please install the tseries package");
21     } finally{
22         rgui.getRLock().unlock() ;
23     }
24 }

Finally, the go function does the actual work of retrieving data from yahoo about the chosen instrument since the start of the chosen year, and then plot the result in the PDF panel

36 public void go( ){
37     Object instrument = instruments.getSelectedItem() ;
38     if( instrument == null ) {
39       JOptionPane.showMessageDialog(this, "Please select an instrument");
40       return ;
41     }
42   
43     int start = 2003 ; 
44     try{ 
45         start = Integer.parseInt( startyear.getText( ) ) ;
46     } catch( Exception e ){
47         JOptionPane.showMessageDialog(this, "Invalid start year");
48         return ;
49     }
50     String ins = (String)map.get(instrument) ; 
51     String cmd = 
52         "x = get.hist.quote(instrument = '^" +   ins +
53         "', start = '" +  
54         start +  "-01-01', quote = 'Close' )" ;
55     String plot = 
56         "plot( x, ylab = '"+ instrument + "' )" ;
57     try{
58       rgui.getRLock().lock( ) ;
59       rgui.getR().evaluate(cmd) ;
60       pdf.setPDFContent( rgui.getR().getPdf( plot , 800, 400) );
61     } catch(Exception e){
62       e.printStackTrace( ) ;
63     } finally{
64       rgui.getRLock().unlock( ) ;
65     }
66   
67 }
68 

Perspectives

Extend JAXX to make it more R-friendly

As opposed to other XML based user interfaces in java, Jaxx is not only restricted to swing tags and any other class might be included in a jaxx tree. Moreover, we can extend jaxx to define how to interpret a given tag, so with a bit of work we could embed R code in a gentle way into jaxx files, I am thinking something like that :

   1 <JButton>
   2     <action language="R">
  3     cat( "hello world" ) 
   4     </action>
   5 </JButton>
   6 

What about rgg

There also is the rgg package which has similar ideas except as far as I can see the nesting is done the other way, XML tags are embedded in R code within an rgg file.

   1 <rgg>
   2 file = <filechooser label="CSV" description="Csv Dateien" 
   3        extensions="csv" fileselection-mode="files-only"/>
   4 
   5 myIris = read.table(file, header=<checkbox label="header" span="2"/>, 
   6   sep=<combobox items="\t,;" label="Seperator" selected="T"/>)
   7 summary(myIris)
   8 </rgg>
   9 

the XML is processed and the script is transformed into an R script. One of the advantages of rgg though is that it defines a set of R related tags such as <matrix>

Files

Here is the source of the pluginplugin and the simple.zip which you can simply unzip into your RWorkbench/plugins directory.