Search code examples
htmlrknitrgwidgets

integrating manipulate outputs with knitr


I was wondering if there is a way in which its possible to integrate the manipulate package or gWidgetsManipulate package so that their outputs can be viewable/manipulable in the html/markdown output file, as I think that this would be extremely useful when developing reproducible interactive research reports. I know that googleVis has some functionality that allows it to be integrated with knitr so that the outputs go into the html file by using options like results='asis' but googleVis is currently quite restrictive in its capabilities when using sliders for example.

If the package outputs of manipulate or gWidgetsManipulate hasn't quite been integrated yet, would it be possible to suggest a workaround for the time being that will allow it to be viewed in the html file?

i.e. my current code in my Rmd file before running knitr-ing to html looks like the below...but I get the following errors.

```{r}
library(manipulate)
manipulate(plot(1:x), x = slider(5, 10))
```

with output

library(manipulate)
## Error: there is no package called 'manipulate'
manipulate(plot(1:x), x = slider(5, 10))
## Error: could not find function "manipulate"

so trying the package gWidgetsManipulate instead...

```{r}
library(gWidgetsManipulate)
manipulate(plot(1:x), x = slider(5, 10))
```

you get the error...

library("gWidgetsManipulate")
## Loading required package: gWidgets
manipulate(plot(1:x), x = slider(5, 10))
## Error: unable to find an inherited method for function ".gwindow", for signature "NULL"

I have tried to specify a guiToolkit to fix this error by using things like

options(guiToolkit="WWW")

but to no avail...

Any help would be greatly appreciated, thanks in advance


Solution

  • If you don't absolutely need to use the gwidgets, I have a solution with Rook and googleVis that does what you want: displaying an interactive chart in html.

    The script for the slider: it contains a little javascript function to display the currently chosen value. It also submits the form at each change. You can easily change the min/max/... values here.

    slider_script <- '
      <input type="range" min="5" max="10" name="plot_max" value="%s" step="1" onchange="document.form1.submit(); showValue(this.value);" />
      <span id="range">%s</span>
      <script type="text/javascript">
      function showValue(newValue)
    {
        document.getElementById("range").innerHTML=newValue;
      }
    </script>
    '
    

    We build the code of the web page. The structure is typical for rook: html code is written inside res$write().

    ### this script builds the webpage
        webreport_app <- function(
          ){
          newapp = function(env) {
            req = Rook::Request$new(env)
            res = Rook::Response$new()
            # initialise variables for first execution
            if (is.null(req$POST())){
              plot_max <- 5
            } else{
              plot_max <- as.numeric(req$POST()[["plot_max"]])
            }
            res$write('<body style="font-family:Arial">')
            res$write("<H3>My App</H3>")
            res$write('<form name = "form1" method="POST">\n')
            res$write('<br> Number of dots: \n')
            res$write(sprintf(slider_script, plot_max, plot_max))
            res$write('<br><input type="submit" name="Go!">\n</form>\n')
            if (!is.null(req$POST())) {    
              # generate the plot
              library(googleVis)
              data_for_plot <- data.frame(x_var = 1:plot_max, y_var = 1:plot_max)
              Scatter1 <- gvisScatterChart(data_for_plot)
              # extract chart script
              chart_script <- capture.output(print(Scatter1, 'chart'))
              # write to html
              res$write(paste(chart_script, collapse="\n"))
              res$write("<br><br></body></html>")
            }
            res$finish()
          }
          return(newapp)
        }
    

    And finally launch the setup and launch the html server via Rook:

    library(Rook)
    
    # launch the web app
    if (exists("report_server")){
      report_server$remove(app, all = TRUE)
      report_server$stop()
      rm(report_server)
    }
    report_server = Rhttpd$new()
    report_server$add(app = webreport_app(), name = "My_app")
    report_server$start()
    report_server$browse("My_app")
    report_server$browse()