albertosantini / node-rio

Integration with Rserve, a TCP/IP server for R framework
https://github.com/albertosantini/node-conpa
MIT License
176 stars 35 forks source link

How can I retrieve matrix from command #33

Closed samzhao2008 closed 8 years ago

samzhao2008 commented 8 years ago

When I tried to operate matrix, it seems the library doesn't return it.

rio.$e({
  command: "a = matrix(1:6, nrow=2, ncol=3, byrow=T)"
}).then(data=>{
  console.log(data);
})

nothing printed. Is there a way to get the matrix value to a 2-d array so that my js code can use it to do something else?

albertosantini commented 8 years ago

Thanks for the feedback.

Firstly a solution.

rio.$e({
    command: "require(RJSONIO); a=matrix(1:6, nrow=2, ncol=3, byrow=T); toJSON(a)"
}).then(data => {
    console.log(JSON.parse(data));
}).catch(function(err) {
    console.log(err);
})

And the output

> rio.$e({
...     command: "require(RJSONIO); a=matrix(1:6, nrow=2, ncol=3, byrow=T); toJSON(a)"
... }).then(data => {
...     console.log(JSON.parse(data));
... }).catch(err => {
...     console.log(err);
... })
Promise { <pending> }
> [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

Coming back to the initial snippet, it is correct there is not anything displayed.

Of course, it doesn't mean rio works ok. Indeed, adding the catch part an error is displayed.

Then, you can enable the debug flag: rio.enableDebug(true);.

> rio.$e({
...     command: "matrix(1:6, nrow=2, ncol=3, byrow=T)"
... }).then(data => {
...     console.log(data);
... }).catch(err => {
...     console.log(err);
... })
Promise { <pending> }
> Connected to Rserve
Supported capabilities --------------

Sending command to Rserve
00000000: 0300 0000 3400 0000 0000 0000 0000 0000  ....4...........
00000010: 0430 0000 6d61 7472 6978 2831 3a36 2c20  .0..matrix(1:6,.
00000020: 6e72 6f77 3d32 2c20 6e63 6f6c 3d33 2c20  nrow=2,.ncol=3,.
00000030: 6279 726f 773d 5429 0001 0101 0101 0101  byrow=T)........
00000040: 0101 0101                                ....

Data Header
00000000: 0100 0100 3800 0000 0000 0000 0000 0000  ....8...........

Data packet
00000000: a030 0000 1514 0000 2008 0000 0200 0000  .0..............
00000010: 0300 0000 1304 0000 6469 6d00 0100 0000  ........dim.....
00000020: 0400 0000 0200 0000 0500 0000 0300 0000  ................
00000030: 0600 0000                                ....

Type SEXP 160
Type 160 is currently not implemented
true
Disconnected from Rserve
Closed from Rserve

The relevant part is Type 160 is currently not implemented.

I am afraid I didn't implement that structure. Contribution is welcome.

samzhao2008 commented 8 years ago

Great solution, very helpful. Thanks.

albertosantini commented 8 years ago

I investigated a bit.

160 === 0xA0 is the first byte of the data packet.

If the type is greater than 128, it means there are attributes, in terms of SEXP parsing. Indeed 160 & ~128 is equal to 32, the type for integer array, exactly as the numbers contained in the matrix.

Really attributes implementation is quite cumbersome. They are a sort of metadata and they make sense in R context. In JS, when the structure is very complex, the JSON serialization is the way.

(Added in todo list; don't hold the breath) :)