Thursday, November 11, 2010

Calling R from Java - RCaller

Edit: This version of RCaller is deprecated, please check the new version of 2.0. This entry is about older versions of RCaller and may be outdated. A blog entry for version 2.0 is in http://stdioe.blogspot.com/2011/07/rcaller-20-calling-r-from-java.html and http://stdioe.blogspot.com.tr/2014/04/rcaller-220-is-released.html for RCaller version 2.2

 

New version : Rcaller 0.5.2

 

Note: The source page of this article is http://www.mhsatman.com/rcaller.php

[2010/08/07] Now, Rcaller has a new version, 0.5.2, with some bug fixes and additional functionality. Some changes are done and some bugs are fixed by John Oliver. John is now second developer of the Rcaller.

Change Log for version 0.5.2:

  • Added a multi-threaded StreamReader class to RCaller, for stream reading both stderr & stdout to prevent read blocks.
  • StreamReader will optionally echo what it receives to the parent process stdout & stderr, so you can see what is going on
  • Changed RunRCode to use StreamReader
  • Changed RunRCode to wait for the sub-process to complete before returning
  • int[] RGetAsIntArray(String name) function was added so results from R functions can be handled as integer arrays
  • String[] RGetAsStringArray(String name) function was added in order to handle R results as String arrays
  • Removed extra cat(javaCode) call from makejava.r

RCaller

RCaller is an other simple way to call R from Java without JNI. There are lots of queries in the internet about "how to call r from java" or "call r function from java with / without JNI". There are some solutions about these works, for example, RServe is a server application written in C and it waits for socket connections, then accepts clients and runs the R code that sent from socket streams and returns SEXP 's (S / R Expressions). Also, rJava is a JNI solution for calling R from Java. But as i see, users don't want to struggle this things and they seeks more practical solutions.


RCaller uses neither sockets nor JNI interface for calling R functions from Java. RCaller simply runs RScript executable file using java's Runtime and Process classes. Then runs R commands using arguments and handles results using streams. RCaller converts R objects to Java's double or String arrays using a R script and BeanShell interpreter. After these operations R results can be handled by user using getter methods.


You can use it in your Java applications that needs some statistical calculations. Implementation and setting-up processes are easy. You can download source codes as Netbeans project and jars. Simply add two jars to your classpath and start calling R!





Examples

1)Getting Pi from R!



In this example, we are calling R code "a<-pi;" that sets the value of pi to variable a. Then, we handle this result from Java.


RCaller caller=new RCaller();
        StringBuffer code=new StringBuffer();
        code.append("a<-pi;cat(makejava(a))");
        try{
            caller.RunRCode(code.toString(),false,false);
            System.out.println(caller.RGet("a[0]"));
        }catch (Exception e){
            System.out.println(e);
        }


The result is 3.14159. RCaller always handles results as arrays, so a is not variable but double array. Array has only one element, so a[0] is the value that sent from R. We have to use cat(makejava(a)) to make R object 'a' usable in Java.
We call RunRCode() function with 3 parameters. Last 2 parameters are boolean. If first one is true, then content of stderr will be written on console. If the second one is true, then content of stdout will be written. We set them false not to write both outputs on the screen.

2)Calculate Linear Regression from Java using R



In this example, we set x and y with random variables that come from standard normal distributions and estimate linear regression using R and Java.


RCaller caller=new RCaller();
        StringBuffer code=new StringBuffer();
        code.append("x<-rnorm(10);");
        code.append("y<-rnorm(10);");
        code.append("ols<-lm(y~x);");
        code.append("cat(makejava(ols));");
        try{
            caller.RunRCode(code.toString(),false,false);
            double[] coefs=caller.RGetAsDoubleArray("coefficients");
            for (int i=0;i
        }catch (Exception e){
            System.out.println(e);
        }


The result is
-0.815634476060036
0.637334790434423


so, these are the estimated coefficients of the ordinary least squres regression.

3)Running RCaller in different platforms (Linux, Windows, Mac, etc)



RCaller is pure Java and can be run any platform that Java virtual machine runs. Also, you need to be have R as well. Default R engine is Rscript executable file that distrubited in R. Default value of engine is /usr/bin/Rscript but user can change location using setRScriptExecutableFile(String location) method.


RCaller caller=new RCaller();
        caller.setRScriptExecutableFile("C:\\Program Files\\...\\R\\..\\Rscript.exe");
 //caller.setRScriptExecutableFile("/usr/bin/Rscript");

4)What objects returned after running my R command?



RCaller converts R objects to Java objects. You can handle returned values' names like this:


RCaller caller=new RCaller();
        StringBuffer code=new StringBuffer();
        code.append("x<-rnorm(10);");
        code.append("y<-rnorm(10);");
        code.append("ols<-lm(y~x);");
        code.append("s<-summary(ols);");
        code.append("cat(makejava(s));");
        try{
            caller.RunRCode(code.toString(),false,false);
            ArrayList fields=caller.getFieldList();
            for (int i=0;i
        }catch (Exception e){
            System.out.println(e);
        }


The result is:
double[] residuals
double[] coefficients
double[] sigma
double[] df
double[] rsquared
double[] adjrsquared
double[] fstatistic
double[] covunscaled
double[] residuals
double[] coefficients
double[] sigma
double[] df
double[] rsquared
double[] adjrsquared
double[] fstatistic
double[] covunscaled


and these are all returned fields from the summary() R command.

Download source code and jars






Version0.5.2
Netbeans project and source codeDownload
Jars (RCaller.jar and bsh-core-2.0b4.jar)Download

Version0.5.1
Netbeans project and source codeDownload
Jars (RCaller.jar and bsh-core-2.0b4.jar)Download

If you like this solution or you have got any questions, you can send e-mail using mhsatman [at] yahoo.com.
Mehmet Hakan Satman, Istanbul University, Faculty of Economics, Department of Econometrics

27 comments:

  1. Hi, I like your package, but I have a question: how do I extract into java the R return values that do not have a name?

    I am trying to use the R acf (autocorrelation function) out of java, but without documentation, I am not sure I understand how to use the RGetAsDoubleArray() to get the acf.

    Please help!

    ReplyDelete
  2. try this:


    public Main(){
    RCaller c=new RCaller();
    StringBuffer buf=new StringBuffer();
    buf.append("x<-rnorm(50);a<-acf(x);result<-as.double(a$acf);");
    buf.append("cat(makejava(result))");
    try{
    c.RunRCode(buf.toString(), true, true);
    double[] d=c.RGetAsDoubleArray("result");
    for (int i=0;i<d.length;i++) System.out.println(d[i]);
    }catch(Exception e){
    System.out.println(e.toString());
    }

    }





    the key point is :
    buf.append("x<-rnorm(50);a<-acf(x);result<-as.double(a$acf);");
    buf.append("cat(makejava(result))");

    ReplyDelete
  3. Hi,
    I have tried Rcaller..Its good but I have few basic query because I am newbie in this.
    1. If I have R functions or R code in R file then How can I call that file or function through this?
    2. And what about Image which I got from R.How to get that image in Java?

    Here is one example which I am trying but giving an error..
    Here rnorm is working but hist(histogram plot function) is not working why?

    import rcaller.RCaller

    class HistController {

    def index = {

    RCaller caller=new RCaller()
    StringBuffer code=new StringBuffer()
    code.append("x<- rnorm(100);y<- hist(x);result<-as.double(y$hist);")
    code.append("cat(makejava(result);")

    caller.RunRCode(code.toString(),false,false);
    double[] d=caller.RGetAsDoubleArray("result");
    for (int i=0;i<d.length;i++)
    println(d.toString())
    }

    ReplyDelete
  4. It is possible to load a library using RCaller? In my app, I need to load a time series forecast package in order to call some functions and extract the results to a java object.

    The command code.append("library(forecast)"); is not working...

    ReplyDelete
  5. Hello,
    Can you show me with examples of forcast package function?
    Can you also show me to call my own function? If I have function written in one R file, so how to call it from that file?

    Thanks

    ReplyDelete
  6. Hi,
    it might need a ; at the end.
    try this: code.append("library(forecast);");

    BTW, I have problems when calling RCaller. The error is the following:
    Parse error at line 1, column 1. Encountered: [
    at bsh.Parser.generateParseException(Unknown Source)
    at bsh.Parser.jj_consume_token(Unknown Source)
    at bsh.Parser.Line(Unknown Source)
    at bsh.Interpreter.Line(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at rcaller.StreamReader.run(RCaller.java:79)

    And the code I'm running is the following:
    String[] noms = new String[1];
    noms[0] = "ABANTO";
    code=new StringBuffer();
    code.append("path.files<-'C:/.../R_data';");
    code.append("lapply(list.files(path = path.files, pattern = '.RData', full.names = TRUE), load, envir=.GlobalEnv);");
    for(int i=0; i<noms.length; i++) {
    code.append("mylist <- lapply(ls(pattern = '"+noms[i]+"'), get);");
    code.append(""+noms[i]+" <- Reduce(function(x,y) merge(x, y, all = TRUE), mylist);");
    }
    try{
    rcaller.RunRCode(code.toString(), true, true);
    }catch (Exception e) {
    System.out.println(e);
    }

    I would be grateful if anyone could help me as soon as possible.

    ReplyDelete
    Replies
    1. Hello,
      Have you ever tried to load an Rdata file from Rcaller?
      I'm not sure that my statement is correct:
      code.addRCode("load(/Users/bendarraz/Documents/ObjTable.RData)");

      Thanks

      Delete
  7. I get the following error when I call a r function from Java. If someone knows, pl reply.

    STDOUT: null device
    Parse error at line 1, column 6. Encountered: device
    at bsh.Parser.generateParseException(Unknown Source)
    at bsh.Parser.jj_consume_token(Unknown Source)
    at bsh.Parser.Statement(Unknown Source)
    at bsh.Parser.BlockStatement(Unknown Source)
    at bsh.Parser.Line(Unknown Source)
    at bsh.Interpreter.Line(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at rcaller.StreamReader.run(RCaller.java:79)

    ReplyDelete
  8. "STDOUT: null device " >> I think Java can not find a console device. which operating system do you use?

    ReplyDelete
  9. for image and plot handling see:

    http://stdioe.blogspot.com/2011/05/handling-plots-with-rcaller.html

    ReplyDelete
  10. Excellent package but for some reason I cant seem to get this right. So I install R and I import this package into Eclipse. I then tried to run the program and the GUI pulled up fine. But somehow it keeps giving me an error which says that the script executable file cannot be found. Could you let me know where I can download these files or if I have R, how I can generate these myself? Unfortunately I am noob to both R and executable files.
    However, I do believe that RCaller is a fantastic approach to statistical solutions with R.

    ReplyDelete
  11. Satyavrat: which os are you currently using? in windows, you have to specify the path of the file Rscript executable. It is in the /bin directory of R installed. There is an example for this:

    RCaller caller=new RCaller();

    /* For Windows */
    caller.setRScriptExecutableFile("C:\\Program Files\\...\\R\\..\\Rscript.exe");

    /* For Linux */
    caller.setRScriptExecutableFile("/usr/bin/Rscript");


    also you can change those paths if your R installation is in another directory.

    ReplyDelete
  12. I am using windows right now...but in the future we might want to put it on the cloud. something like EC2 or something, but there I'll use an AMI for convenience purposes instead of actually copying the entire thing on there. In that case is there anything I can try?

    I'll try it on my local machine first though and fingers crossed that I can get it working :)

    ReplyDelete
  13. Just to get back on the first post, I had done everything but I was just pointing it to the wrong RScript.exe :)
    Thanks a lot for your help, this is absolutely brilliant.

    ReplyDelete
  14. RCaller caller = new RCaller();
    caller.setRScriptExecutableFile("D:\\Program Files\\R\\R-2.13.0\\bin\\Rscript.exe");
    StringBuffer code = new StringBuffer();

    code.append("library(RJDBC);");
    code.append("drv <- JDBC(\"oracle.jdbc.driver.OracleDriver\",\"D:/Program Files/Apache Software Foundation/Tomcat 6.0/lib/ojdbc14.jar\",identifier.quote=\"`\");");
    code.append("conn <- dbConnect(drv, \"jdbc:oracle:thin:@ISPL61:1521:CRSFRD\", \"ENTPROD\", \"ENTPROD\");");
    code.append("query<-\"SELECT TO_CHAR(transaction_date_time,'MON-yy'), COUNT(*) FROM ledger_transaction WHERE transaction_date_time BETWEEN to_date('02-NOV-10','dd-MON-yy') AND to_date('31-JAN-11','dd-MON-yy') GROUP BY TO_CHAR(transaction_date_time,'MON-yy')\";");
    code.append("rs1 <- dbSendQuery(conn, query);");
    code.append("d1 <- fetch(rs1, n = -1);");
    code.append("month <- array(d1[,1]);");
    code.append("count <- array(d1[,2]);");
    code.append("mcount <- mean(count);");
    code.append("mcount <- mean(count);");
    code.append("print(mcount);");


    System.out.println(code);
    try {
    caller.RunRCode(code.toString(), false, false);
    ArrayList fields = caller.getFieldList();
    Iterator it = fields.iterator();
    while (it.hasNext()) {
    System.out.println("data -- " + it.next());
    }

    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }


    please check my above code
    here am getting :
    Parse error at line 1, column 1. Encountered: [
    at bsh.Parser.generateParseException(Unknown Source)
    at bsh.Parser.jj_consume_token(Unknown Source)
    at bsh.Parser.Line(Unknown Source)
    at bsh.Interpreter.Line(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at bsh.Interpreter.eval(Unknown Source)
    at rcaller.StreamReader.run(RCaller.java:79)

    and at final am getting result also.
    Please can anybody help me over this..

    ReplyDelete
  15. Hello, I am experiencing the same "parse error" that has been posted several times now by other users. Even with this error, the results from R are returned to Java, but I would like to prevent it from being displayed. I have noticed that I only get this error if the output from my R code contains certain special characters (I do not get this error with the pi example). I have not narrowed them down yet, but I suspect one or more of the following are the culprits: "{", ":", "[".

    I would simply like to output a string similar to: {"R1":["R1.R","FAIL"]} without getting the parse error.

    Any ideas?
    Thanks

    ReplyDelete
  16. RCaller 2.0 is released!

    home page is http://www.mhsatman.com/rcaller.php

    blog entry with examples:
    http://stdioe.blogspot.com/2011/07/rcaller-20-calling-r-from-java.html

    Source and jar files is in:
    http://code.google.com/p/rcaller/source/browse/#hg%2FRCaller%2Fdist

    it should be erroneous. please tell me the bugs.

    ReplyDelete
  17. trying to call r as using :

    public void RCall2(){
    try{
    RCaller caller = new RCaller();
    //caller.setRscriptExecutable("/usr/bin/Rscript");
    caller.setRscriptExecutable("C:\\Program Files\\R\\R-2.13.1\\bin\\Rscript.exe");
    caller.cleanRCode();

    double[] numbers = new double[] {1,4,3,5,6,10};

    caller.addDoubleArray("x", numbers);
    File file = caller.startPlot();
    System.out.println(file);
    caller.addRCode("plot.ts(x)");
    caller.endPlot();
    caller.runOnly();
    caller.showPlot(file);
    }catch (Exception e){
    System.out.println(e.toString());
    }
    }

    getting error:
    java.lang.UnsupportedClassVersionError: Bad version number in .class file
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    Exception in thread "main"

    ReplyDelete
  18. ok it is not about Rscript, it is about the version of the Java compiler and interpreter. Download the source code from the google code of RCaller and compile yourself.

    RCaller is compiled in Linux with openjdk 1.6.

    ReplyDelete
  19. ohh.. i am using jdk1.5,let me try with 1.6

    ReplyDelete
  20. yes, it worked with jdk 1.6
    Thanks.

    ReplyDelete
  21. Hi. I'm trying to run the examples several times in an outside loop. But I'm getting the following error message:

    rcaller.exception.RCallerExecutionException: Can not run c:\Program Files (x86)\R\R-2.11.1\bin\Rscript.exe. Reason: java.lang.IllegalThreadStateException
    C:\Users\John\AppData\Local\Temp\RPlot7393243421770041168.png

    The first run works. But the following fail.

    CODE:

    public RCaller caller;

    public MyTest () {
    caller = new RCaller();
    caller.setRscriptExecutable("c:\\Program Files (x86)\\R\\R-2.11.1\\bin\\Rscript.exe");

    for (int i=0; i<10; i++)
    Test1(i);
    }

    public void Test1(int it){
    try{
    caller.cleanRCode();

    double[] numbers = new double[] {1,4,3,5,6,10};

    caller.addDoubleArray("x", numbers);
    File file = caller.startPlot();
    System.out.println(file);
    caller.addRCode("plot.ts(x, main='"+ it + "')");
    caller.endPlot();
    caller.runOnly();
    caller.showPlot(file);

    }catch (Exception e){
    System.out.println(e.toString());
    }
    }

    }

    ReplyDelete
    Replies
    1. Hello,
      Did you succeed in solving your IllegalThreadStateException?

      Thanks

      Delete
    2. Hello, I had same problem.
      For use this or for plots:

      caller.runOnly();

      You need to run in all iterations:
      caller = new RCaller();
      caller.setRscriptExecutable("c:\\Program Files (x86)\\R\\R-2.11.1\\bin\\Rscript.exe");

      so code will be (but not tested) :
      CODE:

      public RCaller caller;

      public MyTest () {


      for (int i=0; i<10; i++)
      Test1(i);
      }

      public void Test1(int it){
      try{
      caller = new RCaller();
      caller.setRscriptExecutable("c:\\Program Files (x86)\\R\\R-2.11.1\\bin\\Rscript.exe");
      caller.cleanRCode();


      double[] numbers = new double[] {1,4,3,5,6,10};

      caller.addDoubleArray("x", numbers);
      File file = caller.startPlot();
      System.out.println(file);
      caller.addRCode("plot.ts(x, main='"+ it + "')");
      caller.endPlot();
      caller.runOnly();
      caller.showPlot(file);

      }catch (Exception e){
      System.out.println(e.toString());
      }
      }

      }

      I think this is probably a bug.

      bye!

      Delete
  22. Hi everyone!

    I'm trying to make a call to plot3d() using RCaller in my java program, from the "rgl" library in R. It seems to work but the graph only displays for about a quarter of a second and then promptly closes, the window have the title "RGL device 1 [Focus]". If can provide any answers please let me know!

    ReplyDelete
  23. hi
    i am getting this output..can any one help me?
    Sourced file: inline evaluation of: ``a[0];'' : Not an array : at Line: 1 : in file: inline evaluation of: ``a[0];'' : [ 0 ]

    ReplyDelete

Thanks