0
votes

I have tried without success to create a toggle-able plot display using the following code:

library(shiny)
library(rgl)

ui <- (fluidPage(
  checkboxInput("chk", label = "Display", value = TRUE),
  playwidgetOutput("control"),
  rglwidgetOutput("wdg")
))

server <- function(input, output, session) {
  options(rgl.useNULL = TRUE)
  save <- options(rgl.inShiny = TRUE)
  on.exit(options(save))

  open3d()
  plot3d(rnorm(100), rnorm(100), rnorm(100))
  scene <- scene3d()
  rgl.close()

  plot3d(scene)

  output$wdg <- renderRglwidget({
    rglwidget(controllers = c("control"))
  })

  output$control <- renderPlaywidget({
    toggleWidget("wdg", respondTo = "chk",
                 ids = as.integer(names(scene$objects[1])))
  })
}

shinyApp(ui = ui, server = server)

With the current code setup, I get the following error:

Error: length(buttonLabels) == length(components) is not TRUE

From what I can tell about the way toggleWidget wraps playwidget, though, it seems like both buttonLabels and components are character vectors with a length of 1.

I have also tried a number of different variations for the ids variable of toggleWidget with similar levels of success. Examples for rgl in Shiny seem to be few and far between.

What is the proper way to use a toggleWidget in rgl with Shiny?

1
You shouldn't be putting toggleWidget inside renderPlaywidget. The latter is intended to hold a playWidget and nothing else. However, I don't know Shiny well enough to know what you should be doing instead. How would you include html code? - user2554330
I think my previous comment is wrong, sorry! Not sure what the issue is. - user2554330

1 Answers

2
votes

The particular error message you are seeing was due to a bug in rgl: when linked to a Shiny control, you needed to explicitly set the toggleWidget label to character(). There was also another bug related to the checkbox that Shiny uses. Both bugs have been fixed.

However, this isn't enough to get your example to work. I haven't fully debugged it, but I can see the following:

  • You are plotting the scene twice. You probably only want to plot it once.
  • Since you've saved the scene in variable scene, you should pass that to rglwidget().
  • The safest way to get the ids to toggle is to save the result of the plot3d call, then use those values in the toggleWidget call.

I'm not sure which of these cause your script to fail, but the new demo(shinyToggle) (shown below) works fine.

library(shiny)
library(rgl)

open3d(useNULL = TRUE)
ids <- plot3d(rnorm(100), rnorm(100), rnorm(100))[1]
scene <- scene3d()
rgl.close()

ui <- (fluidPage(
    checkboxInput("chk", label = "Display", value = FALSE),
    playwidgetOutput("control"),
    rglwidgetOutput("wdg")
))

server <- function(input, output, session) {
    options(rgl.useNULL = TRUE)
    save <- options(rgl.inShiny = TRUE)
    on.exit(options(save))

    output$wdg <- renderRglwidget({
        rglwidget(scene, controllers = c("control"))
    })

    output$control <- renderPlaywidget({
        toggleWidget("wdg", respondTo = "chk",
                 ids = ids)
    })
}

if (interactive())
  shinyApp(ui = ui, server = server)