R Integration
R Integration Overview
R is a language and environment for statistical computing and graphics. It is used in many industries to analyze and visualize what are often very large datasets. For a more detailed overview see http://www.r-project.org/
We want to make it easy to interface SmartClient and SmartGWT applications with the R environment so that data available in the web application tier can be sent to R for analysis and the outputs of this analysis (whether text or graphical) can be made available to the web tier for post processing and ultimate display to the end user - in short to make it easy to use R with all its power in your application.
Here we present a ready-to use example of this sort of integration in the form of a web interface that drives the generation of a sophisticated stock chart leveraging a third party library written natively in R. The key components here are:
- SmartClient or SmartGWT
- R installed on some server
- The quantmod R module (for stock data lookup and chart generation)
- The Rserve R module (part of the Java->R interface)
- The rJava library (part of the Java->R interface)
In the example below, we create a form that takes a stock ticker that is sent to the server along with the current size of the chart image. This data is processed by a standard DataSource that uses JSR223 as a bridge to execute R code embedded directly in the DataSource. This R script is sent via rJava to the Rserve module running in the R environment for execution and the results (a binary chart in this case) are streamed back to the browser for display.
With this, we think you should be able to use R in your own SmartClient/SmartGWT applications - let us know how it goes! We would love to hear how you use this...
SmartClient with R
This sample uses the ChartPane.js and RChart.js scripts as the client-side code, and the RChartDS.ds.xml as the dataSource:
isc.defineClass("ChartPane", "VLayout").addProperties({
formDefaults: {
_constructor: "DynamicForm",
width: 200,
wrapItemTitles: false,
autoFocus: true,
itemKeyPress: function (item, keyName, characterValue) {
if (keyName == "Enter") this.creator.updateChart();
},
numCols: 3,
items: [
{name: "stockSymbol", title: "Stock Symbol", defaultValue: "GOOG"},
{name: "Chart", type: "button", click: "form.creator.updateChart()", startRow: false}
]
},
updateChart : function () {
this.rChart.setCriteria(this.form.getValues());
},
rChartDefaults: {
_constructor: "RChart",
name: "stockChart",
width: "900",
height: "360"
},
autoChildren: ["form", "rChart"],
initWidget : function () {
this.Super("initWidget", arguments);
this.addAutoChildren(this.autoChildren);
this.updateChart();
}
});
isc.defineClass("RChart", "Img").addProperties({
imageType: "normal",
initWidget : function () {
//this.doSetSrc();
this.Super("initWidget", arguments);
},
resized : function () {
this.doSetSrc();
this.resetSrc();
},
draw : function () {
this.Super("draw", arguments);
this.doSetSrc();
this.resetSrc();
},
getCriteria : function () {
// clone any criteria passed to us initially (don't scribble on user-provided object)
var criteria = isc.addProperties({}, this.criteria);
isc.addProperties(criteria, {
name: this.name,
// coerce to string for passing to REngine
width: this.getVisibleWidth()+"",
height: this.getVisibleHeight()+""
});
return criteria;
},
setCriteria : function (criteria) {
this.criteria = criteria;
this.doSetSrc();
this.resetSrc();
},
doSetSrc : function () {
this.src = RChartDS.getFetchDataURL(this.getCriteria(), {operationId: "getChart"});
}
});
<DataSource
ID="RChartDS"
>
<fields>
<field name="name" primaryKey="true"/>
</fields>
<operationBindings>
<operationBinding operationType="fetch" operationId="getChart">
<script language="groovy"><![CDATA[
def chartRequest = new DSRequest("RChartDS", "fetch", rpc);
// create a unique string for the temporary file used for the R-generated image
criteria.tmpFilename = "/tmp/"+criteria.name+"_"+UUID.randomUUID()+".png";
def chartResponse = chartRequest.setCriteria(criteria)
.setOperationId(criteria.name)
.execute();
rpc.doCustomResponse();
requestContext.setContentType("image/png");
def os = response.getOutputStream();
os.write(chartResponse.data);
os.flush();
]]></script>
</operationBinding>
<operationBinding operationType="fetch" operationId="stockChart">
<script language="REngine"><![CDATA[
library('quantmod')
png(filename=criteria$tmpFilename, height=as.numeric(criteria$height), width=as.numeric(criteria$width))
symbols <- getSymbols(criteria$stockSymbol, auto.assign=FALSE)
chartSeries(symbols, name=criteria$stockSymbol, subset='last 3 months', TA="addVo();addBBands()")
# Turn off device driver (to flush output to png)
dev.off();
# Read the generated image, delete it and return the binary stream
returnVal <- readBin(criteria$tmpFilename,'raw',1024*1024);
unlink(criteria$tmpFilename);
returnVal;
]]></script>
</operationBinding>
</operationBindings>
</DataSource>
Finally, this is the code in the .html:
<SCRIPT SRC="../../isomorphic/DataSourceLoader?dataSource=RChartDS"></SCRIPT>
<SCRIPT src="scripts/ChartPane.js"></SCRIPT>
<SCRIPT src="scripts/RChart.js"></SCRIPT>
<SCRIPT>
isc.ChartPane.create({
ID : "chartPane",
width: "100%",
height: "100%"
});
</SCRIPT>
This screenshot shows you the sample in action:
SmartGWT with R
The client-side code of this sample is the following:
public void onModuleLoad() {
ChartPane chartPane = new ChartPane();
chartPane.draw();
}
class ChartPane extends VLayout {
private RChart rChart;
private DynamicForm form;
private Criteria criteria;
public ChartPane () {
this.form = new DynamicForm();
this.form.setWidth(200);
this.form.setWrapItemTitles(false);
this.form.setAutoFocus(true);
this.form.setNumCols(3);
TextItem text = new TextItem();
text.setName("stockSymbol");
text.setTitle("Stock Symbol");
text.setDefaultValue("YHOO");
ButtonItem button = new ButtonItem();
button.setTitle("Chart");
button.setStartRow(false);
button.addClickHandler(new ClickHandler() {
@Override
public void onClick(
com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
updateChart();
}
});
this.form.setItems(text, button);
this.form.addItemKeyPressHandler(new ItemKeyPressHandler() {
@Override
public void onItemKeyPress(ItemKeyPressEvent event) {
if (event.getKeyName().equalsIgnoreCase("Enter")) {
updateChart();
}
}
});
this.rChart = new RChart();
this.criteria = new Criteria();
this.criteria.addCriteria("name", "stockChart");
this.criteria.addCriteria("stockSymbol", this.form.getValueAsString("stockSymbol"));
this.criteria.addCriteria("width", "900");
this.criteria.addCriteria("height", "360");
this.rChart.setCriteria(criteria);
this.addMembers(form, rChart);
}
private void updateChart () {
this.criteria.addCriteria("stockSymbol", this.form.getValueAsString("stockSymbol"));
this.rChart.setCriteria(criteria);
}
}
class RChart extends Img {
Criteria criteria = new Criteria();
public RChart () {
this.setImageType(ImageStyle.NORMAL);
this.setName("stockChart");
this.setWidth("900");
this.setHeight("360");
this.doSetSrc();
this.resetSrc();
}
private void doSetSrc() {
DataSource ds = DataSource.get("RChartDS");
DSRequest properties = new DSRequest();
properties.setOperationId("getChart");
this.setSrc(ds.getFetchDataURL(this.getCriteria(), properties));
}
private void setCriteria(Criteria criteria) {
this.criteria = criteria;
this.doSetSrc();
this.resetSrc();
}
private Criteria getCriteria() {
return this.criteria;
}
}
This screenshot shows you the sample in action:
Either SmartClient or SmartGWT sample uses the same .ds.xml as the dataSource.
Installing the R engine and the packages needed.
1.- Directions for installing R: http://www.r-project.org/
2.- After installing R, run it and install the following packages:
2.1.- quantmod:
install.packages("quantmod")
2.2.- Rserve. Further information: http://www.rforge.net/Rserve/
install.packages("Rserve")
2.3.- rJava (JRI). Further information: http://rforge.net/JRI/
install.packages("rJava")
3.- Download the libraries needed:
Rserve: JRS.jar, REngine.jar, RserveEngine.jar
JRI: JRS.jar, REngine.jar, JRI.jar, JRIEngine.jar
Further information: http://www.rforge.net/rscript/index.html
Setting up the samples
SmartClientR sample
You can download the sample from here. Unzip it and put the SmartClientR folder into the smartclientSDK/examples/ folder and follow these steps:
1.- Copy the RChartDS.ds.xml file into the smartclientSDK/shared/ds/ folder.
2.- Copy the libraries of Rserve or JRI into the smartclientSDK/WEB-INF/lib/ folder.
3.- Open a console and run:
Windows machine: set path=%path%;C:\Program Files\R\R-2.15.3\bin\(x64 or i386);C:\Program Files\R\R-2.15.3\library\rJava\jri\(x64 or i386) (You need to verify this path in your R installation)
Linux machine: setenv R_HOME /usr/lib64/R (You need to verify this path in your R installation)
4.- If you are going to use Rserve, you'll need to do the following:
Windows machine:
- Run R, once you are in R's console, run these commands:
library(Rserve) (Enter)
Rserve() (Enter)
- Open the embeddedTomcat.bat file located in the smartclientSDK/WEB-INF/bin/ folder. Search this line:
"%JAVA%" -Xmx512m -Duser.timezone=GMT -Djava.awt.headless=true -cp
Add -Dorg.rosuda.jrs.host=localhost before -cp.
- Finally, run embeddedTomcat.bat from the opened console.
Linux machine:
- Run 'R CMD Rserve' from the opened console.
- Open the embeddedTomcat.sh file located in the smartclientSDK/WEB-INF/bin/ folder. Search this line:
$JAVA -Xmx512m -Duser.timezone=GMT -Djava.awt.headless=true -cp
Add -Dorg.rosuda.jrs.host=localhost before -cp.
- Finally, run embeddedTomcat.sh from the opened console.
5.- If you are going to use JRI, you'll need to run the embeddedTomcat.sh/embeddedTomcat.bat file from the opened console.
SmartGwtR sample
You can download the sample from here. Unzip it and put the SmartGwtR folder into the samples/ folder of a SmartGWT SDK.
To run the sample, you need to have ANT configured. Then open a console and run the following:
1.- Copy the libraries of Rserve or JRI into the WEB-INF/lib/ folder of the sample.
2.- Open a console and go to the SmartGwtR folder. Run the following:
Windows machine: set path=%path%;C:\Program Files\R\R-2.15.3\bin\(x64 or i386);C:\Program Files\R\R-2.15.3\library\rJava\jri\(x64 or i386) (You need to verify this path in your R installation)
Linux machine: setenv R_HOME /usr/lib64/R (You need to verify this path in your R installation)
3.- Compile the project by running: ant
4.- If you are going to use Rserve, you'll need to do the following:
Windows machine:
- Run R, once you are in R's console, run these commands:
library(Rserve) (Enter)
Rserve() (Enter)
- Finally, run: 'ant -buildfile build-rserve.xml hosted'.
Linux machine:
- Run 'R CMD Rserve' from the opened console.
- Finally, run: 'ant -buildfile build-rserve.xml hosted'.
5.- If you are going to use JRI, you'll need to run: 'ant -buildfile build-jri.xml hosted'.
Finally, if you are testing the samples on a Windows machine, you'll need to make a change in the RChartDS.ds.xml dataSource. Open it and search '/tmp/', finally replace it with for example: 'c:/myFolder/'.

