<!-- OpenCPU client library -->
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//cdn.opencpu.org/opencpu-0.4.js"></script>

The opencpu.js JavaScript client library builds on jQuery to provide Ajax wrappers for calling R from within a web page. The library works on all modern browsers, and lays the foundations for building scalable R web applications.

Apps — develop, ship and deploy standalone R web applications

The opencpu.js library is primarly designed for developing apps. An app is an R package which includes web page(s) that call R functions in the package through the OpenCPU API. Thereby you can easily package, ship and deploy portable, standalone R web applications. A repository of public OpenCPU apps is available at http://github.com/opencpu. Because apps are simply R packages, they are installed just like any other R package:

#install apps: 'stocks', 'markdownapp' and 'nabel'
library(devtools)
install_github(c("stocks", "markdownapp", "nabel"), username="opencpu")

By convention, the web pages are placed in the /inst/www/ directory in the R package. To use an app locally, simply start the opencpu single-user server:

library(opencpu)
opencpu$browse("/library/stocks/www")
opencpu$browse("/library/nabel/www")

The same apps can be installed and accessed on a cloud server by navigating to /ocpu/library/[pkgname]/www/:

One app in the public repository is called appdemo. This application contains some minimal examples to demonstrate basic functionality and help you get started with building apps using opencpu.js.

OpenCPU and jQuery — loading the libraries

The latest version of opencpu.js is available from github: https://github.com/jeroenooms/opencpu.js. The jQuery library must be included in your web page before opencpu.js, because one depends on the other. Your application code must be included after opencpu.js.

<script src="js/jquery.js"></script>
<script src="js/opencpu.js"></script>
<script src="js/app.js"></script>

It is recommended to ship a copy of the opencpu.js library with your application or website (as opposed to hotlinking it from some public location). This because the JavaScript library is in active development (0.x version) and the latest version might (radically) change from time to time. Shipping a version of opencpu.js with your app prevents it from breaking with upstream changes in the library. Also it is practical both for development and deployment if your app works offline.

Most functions in opencpu.js call out to $.ajax and return the jqXHR object. Thereby you (the programmer) have full control over the request. Note that the A in Ajax stands for asynchronous, which means each ajax request returns immediately. Server responses are processed using callback functions. This paradigm can be a bit confusing to R users, but it results in flexible, non-blocking applications. If you are new to jQuery, at least familiarize yourself with the jqXHR.done, jqXHR.fail and jqXHR.always methods (see jqXHR).

CORS — cross-domain opencpu requests

The recommended design for OpenCPU apps is to include the web pages in the R package. This results in a standalone application, which is easy to distribute and deploy and can also be used offline. Furthermore, it guarantees that the version of front-end and R code are in sync, and the package manager automatically takes care of dependencies when the app is installed on a server.

However it is also possible to use the opencpu.js library from an external site that is not hosted on OpenCPU. In this case, we must specify the external OpenCPU server using ocpu.seturl():

//set page to communicate to with "mypackage" on server below
ocpu.seturl("//cloud.opencpu.org/ocpu/library/mypackage/R")

Cross domain requests are convenient for development and illustrative examples, see e.g: jsfiddle examples. However, when possible it is still recommended to include a copy of your web pages in the R package for every release of your app. That way you get a nice redistributable app and there is no ambiguity over version compatibility of the front-end (web pages) and back-end (R functions).

Also note that even when using CORS, the opencpu.js library still requires that all R functions used by a certain application are contained in a single R package. This is on purpose, to force you to keep things organized. If you would like to use functionality from various R packages, you need to create an R package that includes some wrapper functions and formally declares its dependencies on the other packages. Writing an R package is really easy these days, so this should be no problem.

JSfiddle — fiddle around with some examples

Since OpenCPU now supports CORS, and so do all major browsers, we started using JSfiddle to illustrate how to use the library. The opencpu jsfiddle homepage lists all our fiddles, and we will keep adding new examples. Many of these examples are actually referenced and explained in this manual page. But if this is all tl;dr, just start playing.

This chapter describes two high-level functions that are used to call R functions that generate either a plot or return some data. They are easy to use because they directly take the output from the R function; no session management is required.

The Plot Widget — generate an R plot in a div

$("#mydiv").rplot( fun, [, args ] [, callback ]) Returns: jqXHR

fun (string)
Name of the R function (required)
args (object)
Function arguments.
callback (function)
Callback function. Not needed for plot widget. Called with session object.

A fun an easy way to get started is by making plots. The opencpu.js library implements a jquery plugin called rplot which makes it easy to embed live plots in your webpage. For example, consider the R function smoothplot in the stocks package:

#The R function
function(ticker = "GOOG", from = "2013-01-01", to=Sys.time()){
  mydata <- yahoodata(ticker, from, to);
  qplot(Date, Close, data = mydata, geom = c("line", "smooth"));
}

It defines three arguments, each of which optional: ticker, from, and to. These are the arguments that we can pass from the opencpu.js client app. In this example, we only pass the first two arguments.

//JavaScript client code
var ticker = $("#ticker").val();
var req = $("#plotdiv").rplot("smoothplot", {
    ticker : ticker,
    from : "2013-01-01"
})

//optional: add custom callbacks
req.fail(function(){
    alert("R returned an error: " + req.responseText);
});

This creates a plot widget in the #plotdiv element (a div in your html). It calls the R function smoothplot and passes argument values as specified, and displays the generated plot including PNG, PDF, and SVG export links. The final lines specify an error handler, which is optional but recommended. Have a look at the jsfiddle, or the full stocks app to see all of this in action!

Basic JSON RPC — a.k.a Data Processing Unit

ocpu.rpc( fun, [, args ] [, complete ] ) Returns: jqXHR

fun (string)
Name of the R function (required)
args (object)
Function arguments.
complete (function)
Callback function. Is called only on success with one arg: R function return value.

With opencpu.js we can use R as a remote calculator. Consider the very simple example of calculating the standard deviation for a vector of numbers. In this case we call the default R function sd in the stats package

var mydata = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];

//call R function: stats::sd(x=data)
var req = ocpu.rpc("sd",{
    x : mydata
}, function(output){
    alert("Standard Deviation equals: " + output);
});

//optional
req.fail(function(){
    alert("R returned an error: " + req.responseText);
});

See it in action here. When calling ocpu.rpc, the arguments as well as return value are transferred using JSON. On the R side, the jsonlite package is used to convert between JSON and R objects. Hence, the above code is equivalent to the R code below. The output object is a JSON string which is sent back to the client and parsed by JavaScript.

library(jsonlite)

#parse input from JSON into R
jsoninput <- '{"x" : [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]}'
fnargs <- fromJSON(jsoninput)

#the actual function call
result <- do.call(stats::sd, fnargs)

#convert result back to JSON
jsonoutput <- toJSON(result)

Another example is available here: http://jsfiddle.net/opencpu/9nVd5/. This example calls the lowess function in R, to smooth a bunch of values. This can be useful to remove outliers from noisy data. One difference with the previous example, is that lowess does not return a single value, but a list with two vectors: x and y. See the lowess help page for more detail.

The stateless functions are convenient for applications with a single R function call and a single output (either a plot or the function return value). However, other applications might require more sophisticated interaction with the R session. This section section talks about stateful applications; i.e. the client creates and manipulates objects on the server. Therefore, the difference with before is that calling functions (POST) is decoupled from retrieving output (GET).

State in OpenCPU — managing sessions

Management of state in OpenCPU is quite different from what R users are used to, which can be confusing at first. In OpenCPU, the client does not have a single private R process on the server which handles all incoming requests, such as in e.g. Shiny or in an R terminal session. Instead, OpenCPU is plain HTTP, and therefore each requests is anonymous and stateless. After every function call, OpenCPU cleans (or kills) the R process that was used to handle the request.

However, all outputs of every function call, such as return value, graphics, stdout or files in working directory, are stored on the server, and a session ID is returned to the client. These session IDs can be used to control these outputs on the server in future requests. For example, a client can retrieve outputs in various formats, share them with others, or use stored R objects as arguments in subsequent function calls. Hence to build a statefull application, there is no point in assigning objects to the global environment. Instead, we need to design R functions to return the value of interest. This way the client can call the function, and use its return value in subsequent function calls.

This design has several advantages that are important for scalable applications:

  • Non blocking: everything is async, your GUI won't block while waiting for R to return.
  • Robustness: if an R call gets stuck, errors or crashes, it doesn't take down your application.
  • Concurrency: applications are parallel by design. Clients can perform simultaneous requests and combine results later.

Call an R function — decouple call from output

ocpu.call( fun, [, args ] [, callback ] ) Returns: jqXHR

fun (string)
Name of the R function (required)
args (object)
Function arguments.
callback (function)
Callback function. 1 argument: Session object.

The ocpu.call function is the stateful equivalent of ocpu.rpc. It has the same arguments, but the difference is in the callback function. The ocpu.rpc callback argument is a JSON object containing the data returned by the R function. The ocpu.call callback argument is a Session object. The session object is a javascript class that stores the session ID; it does not contain any actual data. However, from the session object, we can asynchronously retrieve data, plots, files, stdout, etc. See this jsfiddle in action.

//toy example
var req = ocpu.call("rnorm", {n: 100}, function(session){

    //read the session properties (just for fun)
    $("#key").text(session.getKey());
    $("#location").text(session.getLoc());

    //retrieve session console (stdout) async
    session.getConsole(function(outtxt){
        $("#output").text(outtxt);
    });

    //retrieve the returned object async
    session.getObject(function(data){
        //data is the object returned by the R function
        alert("Array of length " + data.length + ".\nFirst few values:" + data.slice(0,3));
    });
})

We can also use the Session object to pass the R value returned by the function call as an argument to a subsequent function call, without ever retrieving the object. All state in OpenCPU is managed by controlling R objects in sessions on the server. This jsfiddle example continues on the previous example, and calculates the variance of the vector generated before, by passing the session object as an argument. A more simple example here

var req1 = ocpu.call("rnorm", {n: 100}, function(session1){
    var req2 = ocpu.call("var", {x : session1}, function(session2){
        session2.getObject(function(data){
            alert("Variance equals: " + data);
        });
    });
});

Argument Types — passing data to opencpu

In opencpu.js there are 4 types of arguments: a basic JavaScript value/object (automatically converted to R via JSON), a session object (represents an R value from a previous function call), a file and a code snippet. We have already seen examples the first two argument types earlier. Below is an example of using a file as an argument. The file will automatically be uploaded and used to call the R function. See it in action using this jsfiddle.

//This must be HTML5 <input type="file">
var myfile = $("#csvfile")[0].files[0];
var header = true;

//call read.csv in R. File is automatically uploaded
var req = ocpu.call("read.csv", {
    "file" : myfile,
    "header" : myheader
}, function(session){
    //use output here
});

The final type of argument is a code snippet. This injects raw R code into the function call. It is usually recommended to use this type only when really needed, because it requires the client to understand R code, which kills interoperability. But this argument type is useful for example in applications that explicitly let the user do some R coding. See here for a basic example:

//create snippet argument
var x = new ocpu.Snippet($("#input").val());

//perform the request
var req = ocpu.call("mean", {
    "x" : x
}, function(session){
    //use output here
});

One interesting special case is using a code Snippet when calling the identity function in R. This comes down to executing a raw block of code in a session. Try this jsfiddle to see this in action.

The Session Object — controlling objects, plots, files, etc

The callback argument for ocpu.call() is always a session object. This object does not contain actual data, it just holds a sessoin ID and which can be used to retrieve output from the server. All session objects have the following methods:

session.getKey() Returns: string

Read the session ID. For debugging only.

session.getLoc() Returns: string

Read the session URL. For debugging only.

session.getFileURL( path ) Returns: string

path (string)
Path of the file w.r.t. working directory. (required)

The methods below initiate an ajax request and return the jqXHR object. A callback is required to process output.

session.getObject( [ name ] [, data ] [, success ]) Returns: jqXHR

name (string)
Name of the object. Usually not required. Defaults to .val which means the function return value.
data (object)
Arguments for the /json output format.
success (function)
Callback argument: function return data.

session.getConsole( [ success ] ) Returns: jqXHR

success (function)
Callback argument: session console text.

session.getStdout( [ success ] ) Returns: jqXHR

success (function)
Callback argument: session stdout text.

session.getFile( path [, success ] ) Returns: jqXHR

path (string)
Path of the file w.r.t. working directory. (required)
success (function)
Callback argument: file content.