rshinyinputbinding

how to set Shiny::toJSON args from custom update***Input function?


I am developing a custom input binding for Shiny. I have a data.table that I am passing to a javascript. Unfortunately, the data needs to be encoded row-wise rather than column-wise. private$inputMessageQueue is processsed without extra arguments so there is no place to overrideshiny::toJSON default args. How can I get the format I need?

Shiny function that receives my data.table (as message$data)

debugging in: session$sendInputMessage(inputId, message)
debug: {
    data <- list(id = inputId, message = message)
    private$inputMessageQueue[[length(private$inputMessageQueue) + 
        1]] <- data
}

structure of my data.table:

Browse[4]> str(message$data)
Classes ‘data.table’ and 'data.frame':  8 obs. of  7 variables:
 $ coOrdinate       : chr  "c1" "c2" "c3" "c4" ...
 $ injectionSite    : Factor w/ 2 levels "head","body": NA NA NA NA NA NA NA NA
 $ drug             : Factor w/ 2 levels "aconitin","nicotine": NA NA NA NA NA NA NA NA
 $ drugConcentration: num  NA NA NA NA NA NA NA NA
 $ bath             : Factor w/ 2 levels "aconitin","nicotine": NA NA NA NA NA NA NA NA
 $ bathConcentration: num  NA NA NA NA NA NA NA NA
 $ status           : Factor w/ 3 levels "active","dead",..: 1 1 1 1 1 1 1 1
 - attr(*, ".internal.selfref")=<externalptr> 

Actual data in my data.table:

Browse[4]> message$data
   coOrdinate injectionSite drug drugConcentration bath bathConcentration status
1:         c1            NA   NA                NA   NA                NA active
2:         c2            NA   NA                NA   NA                NA active
3:         c3            NA   NA                NA   NA                NA active
4:         c4            NA   NA                NA   NA                NA active
5:         c5            NA   NA                NA   NA                NA active
6:         c6            NA   NA                NA   NA                NA active
7:         c7            NA   NA                NA   NA                NA active
8:         c8            NA   NA                NA   NA                NA active

what I want Shiny to do:

Browse[4]> jsonlite::toJSON(message$data)

[
    {"coOrdinate":"c1","status":"active"},
    {"coOrdinate":"c2","status":"active"},
    {"coOrdinate":"c3","status":"active"},
    {"coOrdinate":"c4","status":"active"},
    {"coOrdinate":"c5","status":"active"},
    {"coOrdinate":"c6","status":"active"},
    {"coOrdinate":"c7","status":"active"},
    {"coOrdinate":"c8","status":"active"}
] 

what Shiny does when private$InputMessageQueue is processed (as found in shiny.R)

jsonlite::toJSON(I(message$data),dataframe='columns',null='null', na='null', auto_unbox=T, force=T, rownames=F, keep_vec_name=T)

{
    "coOrdinate":["c1","c2","c3","c4","c5","c6","c7","c8"],
    "injectionSite":[null,null,null,null,null,null,null,null],
    "drug":[null,null,null,null,null,null,null,null],
    "drugConcentration":[null,null,null,null,null,null,null,null],
    "bath":[null,null,null,null,null,null,null,null],
    "bathConcentration":[null,null,null,null,null,null,null,null],
    "status":["active","active","active","active","active","active","active","active"]
}

If all else fails, I can cast my data.table to a matrix. This will give me row-wise JSON, but I'll lose the column names:

Browse[4]> jsonlite::toJSON(I(as.matrix(message$data)),dataframe='columns',null='null', na='null', auto_unbox=T, force=T, rownames=F, keep_vec_name=T)

[
    ["c1",null,null,null,null,null,"active"],
    ["c2",null,null,null,null,null,"active"],
    ["c3",null,null,null,null,null,"active"],
    ["c4",null,null,null,null,null,"active"],
    ["c5",null,null,null,null,null,"active"],
    ["c6",null,null,null,null,null,"active"],
    ["c7",null,null,null,null,null,"active"],
    ["c8",null,null,null,null,null,"active"]
] 

So, how can I force Shiny to pass my data.frame row-wise?


Solution

  • You can simply pre-encode your R data using jsonlite::toJSON() and pass the encoded JSON string to shiny. It will be treated as a verbatim JSON string instead of being double-encoded (e.g. "[1,2]" will not be encoded again as "\"[1,2]\""). This is due to the fact that we used the argument json_verbatim = TRUE in jsonlite::toJSON() (PR#795). This requires shiny >= 0.12.0.