Convert R Objects to JavaScript
Once webR has been loaded into a web page, objects can be converted into JavaScript from the R environment. For example, it is possible perform some computation within R and then convert the resulting R object into a JavaScript object for use.
Converting R objects to JavaScript objects
Explicitly converting an RObject
to JavaScript can be done by invoking the RObject.toJs()
method, which returns a JavaScript representation of the associated R object. In most cases, JavaScript conversion has been implemented by serialising the R object to an WebRDataJs
.
Serialising R objects
Invoking RObject.toJs()
on an R object serialises the object to a JavaScript object of type WebRDataJs
. This type is designed to form a tree structure, supporting an unambiguous JavaScript representation for potentially nested R objects.
Most R objects are serialised to JavaScript objects that contain the following properties,
Property | Value |
---|---|
type |
A description of the R object’s type as a string. |
names |
An array of strings corresponding to the R object’s names attribute, or null for no names. |
values |
An array containing the value(s) associated with the R object. A JavaScript null indicates a missing value, NA . |
Some R objects, such as lists or environments, contain references to other R objects. Such objects are serialised recursively. Any R objects deeper than the maximum depth setting will not be serialised and instead included in the values
array as an RObject
. By default, R objects are serialised with infinite maximum depth.
An R NULL
object is serialised to a JavaScript object of type WebRDataJsNull
. This type does not include the names
or values
properties.
Serialisation options
An options
argument of type ToJsOptions
can be provided to the RObject.toJs() method for fine-grained control over how objects are serialised.
The following options are available,
Property | Description |
---|---|
depth |
How deep should nested R objects be serialised? A value of 0 indicates infinite depth. |
Example: Serialising an R double atomic vector
const primes = await webR.evalR('c(2,3,5,7,11,13)');
await primes.toJs()
{
type: 'double'
names: null
values: [2, 3, 5, 7, 11, 13]
}
Other R object conversion methods
Subclasses of RObject
provide additional methods to convert objects into a JavaScript representation. For example, the toTypedArray()
method can be invoked on atomic vectors, such as an RDouble
, to access a copy of the raw buffer as it exists in WebAssembly memory.
const primes = await webR.evalR('c(2,3,5,7,11,13)')
await primes.toTypedArray()
Float64Array(6) [2, 3, 5, 7, 11, 13, buffer: ArrayBuffer(48), ... ]
Cached R objects
WebR.objs
contains named references to long-living R objects in the form of RObject
proxies. WebR.objs
is automatically populated at initialisation time, and its properties may be safely accessed once the promise returned by WebR.init()
resolves.
WebR.objs
contains references to the following R objects,
Property | JavaScript Type | R object |
---|---|---|
null |
RNull |
NULL |
true |
RLogical |
TRUE |
false |
RLogical |
FALSE |
na |
RLogical |
Logical NA |
globalEnv |
REnvironment |
The R global environment |
baseEnv |
REnvironment |
The R base environment |
Additional R object proxy hooks
The RObject
proxies are implemented with so-called hooks, for instance a hook that forwards class method invocation to the webR worker thread. The following hooks provide additional R object functionality.
Executing R functions from JavaScript
At the moment, R functions cannot be directly converted into JavaScript functions. However, references to R functions can be executed from JavaScript in a limited way. It is possible to return an R function or closure with WebR.evalR()
and wrap it as an RFunction
proxy. The R function represented by the proxy can be called by either:
Invoking the
RFunction.exec()
method on theRFunction
object.Using
()
, i.e. the normal JavaScript function call syntax.
In either case, both JavaScript or RObject
proxies can be passed as arguments to the associated R function. In the case of JavaScript values they are converted to R objects before function execution.
const fn = await webR.evalR('function(x) { 2 * x }');
const result = await fn.exec([1,2,3]);
await result.toArray()
[2, 4, 6]
The result of the R computation is automatically converted back into a JavaScript representation using RObject.toJs()
if the RFunction
proxy was executed using ()
.
const sin = await webR.evalR('sin');
await sin([1,2,3]);
{
type: 'double'
names: null
values: [0.8414709848078965, 0.9092974268256817, 0.1411200080598672]
}
Looping over R vectors
RObject
proxies are async iterable for objects with a length
property. As such, R vectors can be looped over using the JavaScript for await...of
syntax. For example,
const list = await webR.evalR('list(2,4,6,"abc")')
for await (i of list){
console.log(await i.toArray())
}
[2]
[4]
[6]
['abc']