Search code examples
rrgl

R: rgl link multiple plots to a single widget


I'm trying to link a playwidget() slider to multiple plot so that the slider affects all plots. I want to use it in a Rmarkdown file and not in a Shiny application.

I managed to append the plots in the subsetControl and added the subscenes control, but it's not working properly: the first subset works fine but if I move the slider I get the first plot (with black and red points) duplicated in both plots.

library(rgl)

open3d() # Remove the earlier display

layout3d(matrix(c(1,2), nrow=1), sharedMouse = T)

next3d()
setosa <- with(subset(iris, Species == "setosa"), 
               spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                         col="black",
                         radius = 0.211))
versicolor <- with(subset(iris, Species == "versicolor"), 
                   spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                             col="red",
                             radius = 0.211))

next3d()
setosa2 <- with(subset(iris, Species == "setosa"), 
                spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                          col="yellow",
                          radius = 0.211))
versicolor2 <- with(subset(iris, Species == "versicolor"), 
                    spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                              col="blue",
                              radius = 0.211))


rglwidget() %>%
  playwidget(start = 0, stop = 2, interval = 1,
             subsetControl(1, subscenes = subsceneList(), subsets = list(
               All = c(setosa, setosa2, versicolor, versicolor2),
               Setosa = c(setosa, setosa2),
               Versicolor = c(versicolor, versicolor2)
             )))

Solution

  • The model used in rgl subscenes is that the root owns all the objects, and each subscene displays some of them. Your code starts by displaying setosa and versicolor in the first subscene and setosa2 and versicolor2 in the second one, but the the subset control says to display both setosa and setosa2 in one subset, and both versicolor and versicolor2 in the other, and do this in both subscenes. Since setosa and setosa2 have the same shape and location, only one appears at a time: the first drawn.

    To get what you want, you need two subsetControls, both controlled by the same playwidget, e.g.

    library(rgl)
    
    open3d() # Remove the earlier display
    
    layout3d(matrix(c(1,2), nrow=1), sharedMouse = T)
    
    next3d()
    sub1 <- subsceneInfo()$id
    setosa <- with(subset(iris, Species == "setosa"), 
                                 spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                                                    col="black",
                                                    radius = 0.211))
    versicolor <- with(subset(iris, Species == "versicolor"), 
                                         spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                                                            col="red",
                                                            radius = 0.211))
    
    next3d()
    sub2 <- subsceneInfo()$id
    setosa2 <- with(subset(iris, Species == "setosa"), 
                                    spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                                                        col="yellow",
                                                        radius = 0.211))
    versicolor2 <- with(subset(iris, Species == "versicolor"), 
                                            spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                                                                col="blue",
                                                                radius = 0.211))
    
    
    rglwidget() %>%
        playwidget(start = 0, stop = 2, interval = 1,
                             list(subsetControl(1, subscenes = sub1, subsets = list(
                                All = c(setosa, versicolor),
                                Setosa = setosa,
                                Versicolor = versicolor
                             )),
                             subsetControl(1, subscenes = sub2, subsets = list(
                                All = c(setosa2, versicolor2),
                                Setosa = setosa2,
                                Versicolor = versicolor2
                             ))))