block by timelyportfolio 2c8e0fcbd5b4fb73151c1be9df17c103

R plotly + defiant.js with crosstalk

Full Screen

Summary

plotly has built-in crosstalk thanks to Carson Sievert and Joe Cheng. This allows us to do some interesting things. In this experiment, I use the really neat defiant.js to query the mpg data and update the selection. plotly knows what to do with it!

Code

library(htmltools)
library(crosstalk)
library(plotly)
library(pipeR)

sd <- SharedData$new(mpg, group="a")
pl <- plot_ly(sd) %>% add_markers(x=~factor(cyl), y=~hwy)

tagList(
  tags$script(
    src = "https://cdn.rawgit.com/hbi99/defiant.js/master/dist/defiant.min.js"
  ),
  tags$div(
    style = "width:30%; display:block; float:left;",
    tags$button("//*[class='compact']"),
    tags$button("//*[hwy > 25]"),
    tags$button("//*[contains(manufacturer,'au') and class='compact']"),
    tags$div(
      tags$pre(id="error-reporter")
    )
  ),
  tags$div(
    style = "width:50%; display:block; float:left;",
    pl
  ),
  tags$script(
sprintf(
"
var d3 = Plotly.d3 //use d3 for convenience from Plotly
var data = %s;
var grp = crosstalk.group('a') // we set this to 'a' in SharedData

function updateQuery(querytext){
  if(querytext !== '') {
    try{
      var res = JSON.search( data, querytext );
      var key = d3.keys(
        d3.nest()
          .key(function(d){return +d.key_;})
          .map(res)
      );
      grp.var('selection').set(key);
      d3.select('#error-reporter').text('success: ' + querytext);
    } catch (err) {
      d3.select('#error-reporter').text(err);
      grp.var('selection').set(null);
    };
  } else {
    grp.var('selection').set(null);
  }
}

d3.selectAll('button').on('click',function(){
  updateQuery(d3.select(this).text());
});

// update reporter to show queried by plotly
grp.var('selection').on('change', function(x){
  if(typeof(x.sender) !== 'undefined'){
    d3.select('#error-reporter').text('queried by plotly');
  }
});
",
  jsonlite::toJSON(sd$data(withKey=TRUE),dataframe="rows")
)
  )
) %>>%
  browsable()