Selecting rows from a DT table using Crosstalk in Shiny

So I would like to brush across points in D3Scatter and use it to filter the rows of a datatable produced using the DT package with crosstalk.

Just like this, which totally works outside of shiny:

library(crosstalk)
library(d3scatter)
library(DT)

shared_iris <- SharedData$new(iris)

bscols(d3scatter(shared_iris, ~Petal.Length, ~Petal.Width, ~Species, width = "100%",
                 x_lim = range(iris$Petal.Length), y_lim = range(iris$Petal.Width)),
       
       datatable(shared_iris))

But when I put it in Shiny, I can select points on the scatter from the table, but not vice versa:

library(shiny)
library(crosstalk)
library(d3scatter)
library(DT)

ui <- fluidPage(
  fluidRow(
    column(6, d3scatterOutput("scatter1")),
    column(6, DT::dataTableOutput("scatter2"))
  )
)

server <- function(input, output, session) {
  jittered_iris <- reactive({
    iris
  })
  
  shared_iris <- SharedData$new(jittered_iris)
  
  output$scatter1 <- renderD3scatter({
    d3scatter(shared_iris, ~Petal.Length, ~Petal.Width, ~Species, width = "100%",
              x_lim = range(iris$Petal.Length), y_lim = range(iris$Petal.Width))
  })
  
  output$scatter2 <- DT::renderDataTable({
    datatable(shared_iris)
  })
}

shinyApp(ui, server)

They've got it working here: https://rstudio-pubs-static.s3.amazonaws.com/215948_95c1ab86ad334d2f82856d9e5ebc16af.html

I'm at a loss. I feel like I've tried everything. Any clues anyone?

Thanks,

So it looks like you have everything right except one small thing. You need to change your shared_iris assignment to this:

shared_iris <- SharedData$new(jittered_iris())

Since jitter_iris is a reactive, you need to add parenthesis because reactive objects are essntially functions that need to be called as functions would be.

1 Like

Thanks, but this does not work:

"Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)"

From the crosstalk help:

"Notice that we passed the reactive expression itself (jittered_iris), not the value of the reactive expression (jittered_iris()). We don’t want to read the reactive expression at the time that we construct the SharedData object, but instead, want to give the reactive expression itself to the new object so the latter can read the former at any point in the future."

Sorry I got a solution to this and forgot to put it here in case anyone finds it. It's here https://stackoverflow.com/a/48291243/486245

(basically, you just need to turn off server side processing with server = FALSE in the renderDataTable bit)

2 Likes