R Shiny and Integrated Google Charts

415 Views Asked by At

I am working to learn how to integrate Google Charts into a app without using the additional overhead of the package and baking most things into the app myself. Below is a simple Hello World example that, for now, has the elements I want properly contained within the app.

What I am trying to learn how to do is use the data created in the object tmp() to populate the data table I am creating. The app below works, but the charts are populated from the data hard coded in the data object for now.

Is there a way my can be used to populate the data array?

Minimal reproducible ui file

ui <- fluidPage(
    titlePanel("Hello Google Charts"),
    sidebarLayout(
        sidebarPanel(
            h1('Hello World')
        ),
    mainPanel(
        htmlTemplate("test3.html"),
        verbatimTextOutput('x')
        )
    )
)

Minimal reproducible server file

server <- function(input, output) {
    tmp <- data.frame(v1 = rnorm(4), v2 = rnorm(4))
    output$x <- renderPrint({tmp})
} 

HTML file test3.html

<html>
  <head>
   <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
   <script type="text/javascript">
      google.charts.load('current', {'packages':['gauge']});
      google.charts.setOnLoadCallback(drawChart);

      function drawChart() {


        var data = google.visualization.arrayToDataTable([
          ['v1', 'v2'],
          ['1', -1.9372140],
          ['2', -1.5234370],
          ['3', 0.2374601],
          ['4', 1.0550744]
        ]);

        var options = {
          width: 400, height: 120,
          redFrom: 75, redTo: 100,
          yellowFrom:50, yellowTo: 75,
          minorTicks: 10
        };

        var chart = new google.visualization.Gauge(document.getElementById('chart_div'));

        chart.draw(data, options);

        setInterval(function() {
          data.setValue(0, 1, 40 + Math.round(60 * Math.random()));
          chart.draw(data, options);
        }, 10000);
        setInterval(function() {
          data.setValue(1, 1, 40 + Math.round(60 * Math.random()));
          chart.draw(data, options);
        }, 100);
        setInterval(function() {
          data.setValue(2, 1, 10 );
          chart.draw(data, options);
        }, 100);
      }
    </script>
  </head>

  <body>
    <div id="chart_div" style="width: 400px; height: 120px;">
    </div>
  </body>
</html>
1

There are 1 best solutions below

0
Stéphane Laurent On

In order to send something from R to JavaScript, you have to use Shiny.addCustomMessageHandler in the JavaScript script and session$sendCustomMessage in the Shiny server (see ?shiny::session).

Here is a working app.

JavaScript file shinyHandler.js, to put in the www subfolder of the app:

$(document).ready(function(){
  google.charts.load('current', {'packages':['gauge']});
  google.charts.setOnLoadCallback(drawChart);

  function drawChart(data) {

    var options = {
      width: 400, 
      height: 120,
      redFrom: 75, 
      redTo: 100,
      yellowFrom:50, 
      yellowTo: 75,
      minorTicks: 10
    };

    var chart = 
      new google.visualization.Gauge(document.getElementById("chart_div"));

    var gdata = new google.visualization.DataTable(data);
    chart.draw(gdata, options);

/*    setInterval(function() {
      gdata.setValue(0, 1, 40 + Math.round(60 * Math.random()));
      chart.draw(gdata, options);
    }, 10000);
    setInterval(function() {
      gdata.setValue(1, 1, 40 + Math.round(60 * Math.random()));
      chart.draw(gdata, options);
    }, 100);
    setInterval(function() {
      gdata.setValue(2, 1, 10 );
      chart.draw(gdata, options);
    }, 100); */
  } 

  Shiny.addCustomMessageHandler("chart", function(data){drawChart(data);});

});

And the shiny app:

library(shiny)

dataframe2datatable <- function(dat){
  list(
    rows = lapply(1:nrow(dat), function(i){
      list(c = lapply(unname(as.list(dat[i,])), function(x) list(v = x)))
    }),
    cols = lapply(names(dat), function(x){
      list(
        label = x, 
        type = ifelse(mode(dat[[x]]) == "character", "string", "number")
      )
    })
  ) 
}

dat <- data.frame(
  v1 = as.character(1:4),
  v2 = rnorm(4),
  stringsAsFactors = FALSE
)

ui <- fluidPage(
  tags$head(
    tags$script(src = "https://www.gstatic.com/charts/loader.js"),
    tags$script(src = "shinyHandler.js")
  ),
  br(),
  actionButton("draw", "Draw chart"),
  br(),
  div(id = "chart_div")
)

server <- function(input, output, session){

  observeEvent(input[["draw"]], {
    session$sendCustomMessage("chart", dataframe2datatable(dat))
  })

}

shinyApp(ui, server)

enter image description here